News:

Don't forget to visit the main site! There's lots of helpful docs, patches, and more!

Main Menu

SM's physics values? Can you help me find the right ones?

Started by Swagger, April 22, 2014, 01:11:50 AM

Previous topic - Next topic

Swagger

xMax[0] = 2.75;  max run speed
yMax[0] = 5;  max vert speed

xAccGround[0] = .1875;  accel while running
xAccAir[0] = .1875; air control

xDeaccGround[0] = .305;  decell while running
xDeaccAir[0] = .305; decell while in air

Grav[0] = 0.109;  gravity

JumpHeight[0] = 4.62;  jump velocity


Can anyone double check these values for me? I used some asm cheat sheet I found, but whenever I put these values into my engine, the results are too floaty, the acceleration is too fast, and the decell is too fast as well. Can anyjuan help?


Swagger

I already checked that topic and got all the values. I turned all the ASM values into decimals (including the correct subpixel values as fractions) and yet the engine still doesn't feel right.
The horizontal momentum deceleration is .5 according to that ASM table. I did many frame by frame checks and it's definitely not .5, it took 9 frames to get from 2.75 to 0, so it's more like .30555

RT-55J

Address Parameters Meaning
7E0AF6 2 bytes, unsigned Horizontal position
7E0AF8 2 bytes, unsigned Horizontal sub-pixel position[4]
7E0AFA 2 bytes, unsigned Vertical position
7E0AFC 2 bytes, unsigned Vertical sub-pixel position
7E0B00 1 byte, unsigned Vertical hitbox radius
7E0B42 1 byte, unsigned Horizontal speed[5], pixels
7E0B44 2 bytes, unsigned Horizontal speed, fraction of a pixel
7E0B46 1 byte, unsigned Horizontal momentum[6], pixels
7E0B48 2 bytes, unsigned Horizontal momentum, fraction of a pixel
7E0B2E 1 byte, unsigned Vertical speed, pixels
7E0B2C 2 bytes, unsigned Vertical speed, fraction of a pixel
7E0B3F 1 byte, unsigned Speed boost level
7E0A68 1 byte, unsigned Shinespark charge timer
7E0DC2 1 byte, unsigned Beam charge counter
7E0CCC 1 byte, unsigned Weapon cooldown timer


sauce: http://tasvideos.org/GameResources/SNES/SuperMetroid.html

Swagger


Zero One

Yes, but you can open the ROM in a hex editor of choice, go to those addresses and find the values you're looking for.

RT-55J

Those aren't rom addresses. Those are ram addresses. If you record a movie input file, you can use the emulator's frame advance and RAM watch functions to see precisely how speed, momentum, position, etc. can on a per-frame basis for whatever set of inputs or conditions you want.

more info: http://tasvideos.org/EmulatorResources/RamWatch.html
SM ram watch file: http://tasvideos.org/Addresses-20.html (you don't need to use BizHawk)

Beyond that, my other suggestions are to make sure you got the framerate and resolution right. I know from playing it on a real SNES that for some reason running feels much faster than when I play it on an emulator because heaven knows why.

Alternatively, since the goal of your project is to be a standalone game (edit: wait, I got you mixed up with somebody else, so uhh... do whatever you planned on), you could tweak the physics values until you get something that works well enough for your design goals. No one is going to sue you if it ain't a carbon copy.

Swagger

I need the 60 fps values, not the 50 fps ones. Any data for those?

edit: Okay, the addresses work for both. Thanks.


RT-55J

ooh nice. You even have the turn-around animation implemented.

personitis

Looks to be accurately similar. Can't say how it would feel though since we've nothing to fiddle with ourselves. Nice work.

Also, you should get on skype. :heheh:

Swagger

My skype is skip.this.step, can also look for "Skip This".

Add me on skype if wanna test my online SM engine!

SirAileron

Super Metroid clone engine? Sweet mercy, it's all I've wanted for years and years.


personitis

Quote from: person701 on April 23, 2014, 01:26:29 AM
Also, you should get on skype. :heheh:
This was more of a poke for fun at the single comment (at least when I watched it) on your video above.

Swagger

Aileron helped test a lot of stuff online.
Things are getting more and more stable. Ish.

Here's a video: https://www.youtube.com/watch?v=aK3qVtbnys4&feature=youtu.be

Smiley

Hey hey hey, that's looking pretty good, except the lag issues. Keep up the good work. What are you using to make this, if I may ask?

So we have a person working on a 3D multiplayer Metroid game, and another working on a 2D one. Hopefully both of them become something awesome as time goes on!

Swagger




Quietus

I've seen a few of these projects over the years.  Hopefully we'll see this finished. :^_^:

Swagger

I can't continue work on the project. Huge memory leak with the networking dll that I use, and there's no fix for it since it's discontinued. If matches can't last for more than 5 min due to slowdown, I don't think there's much hope for this project. Even using CleanMem.dll to clear all unnecessary memory within the game every 10 frames, the memory requirement STILL went up. I can't work with this, so I'd rather just come out and crush all your hopes and dreams instead of keeping quiet and saying 'soon'.

If you still want to play what I've made up until this point with me, get on Skype and we can have some free for all.... But that's all we can have, really.

Swagger

Faucet Networking started to work for me now. Hopefully it'll all go well.

Swagger

Triple posts are the best posts. Anyway, progress is damn good with the engine. Everything runs off of Faucet Networking now, and while the cursed memory leaks are still there, I think the creator of Faucet Networking is much more hell bent on getting rid of those obnoxious shits. Nothing to see visually, it's the same game as before with MUCH, MUCH, MUCH, MUCH gooder networking (barely ANY lag or hiccups), but whatever. Here's the oServer step event code just so you guys can see what the hell I have to deal with.

global.IncomingSocket = fct_socket_accept(global.AcceptorSocket);

if fct_socket_has_error(global.AcceptorSocket)
{
error_message("Server socket has error.");
game_end();
}



// New player connected: Add socket and ID, send ID to connection;

if global.IncomingSocket > 0
{
fct_socket_sendbuffer_limit(global.IncomingSocket, 65536);

NewID = -1;
CanStop = 1;

NewList[0] = ds_list_create();
NewList[1] = ds_list_create();
NewPriority = ds_priority_create();

ds_priority_copy(NewPriority, PlayerList);

for (i=0;i<ds_priority_size(PlayerList);i+=1)
{
  ds_list_add(NewList[0], ds_priority_find_min(NewPriority));
  ds_list_add(NewList[1], ds_priority_find_priority(NewPriority, ds_priority_find_min(NewPriority)));
  ds_priority_delete_min(NewPriority);
}


NewID = irandom(global.MaxPlayers-1);
while (ds_list_find_index(NewList[1], NewID) != -1)
  NewID = irandom(global.MaxPlayers-1);
 
ds_priority_destroy(NewPriority);
ds_list_destroy(NewList[0]);
ds_list_destroy(NewList[1]);

ds_priority_add(PlayerList, global.IncomingSocket, NewID);

fct_write_ubyte(global.IncomingSocket, 3);
fct_write_ushort(global.IncomingSocket, PACK_ID);
fct_write_ubyte(global.IncomingSocket, NewID);
fct_socket_send(global.IncomingSocket);

global.IncomingSocket = -1;
}

// REC MESSAGES

NewewList[0] = ds_list_create();
NewewList[1] = ds_list_create();
NewewPriority = ds_priority_create();

ds_priority_copy(NewewPriority, PlayerList);

for (i=0;i<ds_priority_size(PlayerList);i+=1)
{
ds_list_add(NewewList[0], ds_priority_find_min(NewewPriority));
ds_list_add(NewewList[1], ds_priority_find_priority(NewewPriority, ds_priority_find_min(NewewPriority)));
ds_priority_delete_min(NewewPriority);
}


for (jj=0;jj<ds_list_size(NewewList[1]);jj+=1)
{
CurrentSocket = ds_list_find_value(NewewList[0],jj);
CurrentID = ds_list_find_value(NewewList[1],jj);

while (fct_tcp_receive(CurrentSocket,Size[CurrentID]))
{
  if Header[CurrentID] == 1
  {
   Header[CurrentID] = 0;
   Size[CurrentID] = fct_read_ubyte(CurrentSocket);
  }
  else
  {
   Command = fct_read_ushort(CurrentSocket);
   Header[CurrentID] = 1;
   Size[CurrentID] = 1;
   
   switch Command
   {
    case PACK_DISCONNECT:
     HandleID = fct_read_ubyte(CurrentSocket);
     HandleLength = fct_read_ubyte(CurrentSocket);
     HandleString = fct_read_string(CurrentSocket, HandleLength);
     
     NewList[0] = ds_list_create();
     NewList[1] = ds_list_create();
     NewPriority = ds_priority_create();
     
     ds_priority_copy(NewPriority, PlayerList);
     
     for (i=0;i<ds_priority_size(PlayerList);i+=1)
     {
      ds_list_add(NewList[0], ds_priority_find_min(NewPriority));
      ds_list_add(NewList[1], ds_priority_find_priority(NewPriority, ds_priority_find_min(NewPriority)));
      ds_priority_delete_min(NewPriority);
     }
     
     ds_priority_clear(PlayerList);
 
     for (i=0;i<ds_list_size(NewList[1]);i+=1)
     {
      if ds_list_find_value(NewList[1],i) != HandleID
       ds_priority_add(PlayerList, ds_list_find_value(NewList[0],i), ds_list_find_value(NewList[1],i));
     } 
     
     for (i = 0; i < ds_priority_size(PlayerList);i += 1)
     {
      Socket = ds_list_find_value(NewList[0], i);
  //    if ds_list_find_value(NewList[1],i) != HandleID
      {
       fct_write_ubyte(Socket, 6);
       fct_write_ushort(Socket, PACK_DISCONNECT);
       fct_write_ubyte(Socket, HandleID);
       fct_write_ubyte(Socket, HandleLength);
       fct_write_ushort(Socket, HandleString);
       fct_socket_send(Socket);
      }
     } 
 
     ds_priority_destroy(NewPriority);
     ds_list_destroy(NewList[0]);
     ds_list_destroy(NewList[1]); 
    break;
   
   
    case PACK_RESPONSE:   
     HandleID = fct_read_ubyte(CurrentSocket);
     Timeout[HandleID] = TIMEOUT;
    break;
   
    case PACK_POS:

     NewList[0] = ds_list_create();
     NewList[1] = ds_list_create();
     NewPriority = ds_priority_create();
     
     ds_priority_copy(NewPriority, PlayerList);
     
     for (i=0;i<ds_priority_size(PlayerList);i+=1)
     {
      ds_list_add(NewList[0], ds_priority_find_min(NewPriority));
      ds_list_add(NewList[1], ds_priority_find_priority(NewPriority, ds_priority_find_min(NewPriority)));
      ds_priority_delete_min(NewPriority);
     }
       
     HandleID = fct_read_ubyte(CurrentSocket);     
     Timeout[HandleID] = TIMEOUT;
     HandleExist = fct_read_ubyte(CurrentSocket);
     Exists[HandleID] = HandleExist;
     HandleX = fct_read_short(CurrentSocket);
     HandleY = fct_read_short(CurrentSocket);
     HandleXVel = fct_read_short(CurrentSocket);
     HandleYVel = fct_read_short(CurrentSocket);
     
     HandleSprite = fct_read_short(CurrentSocket);
     HandleIndex = fct_read_short(CurrentSocket);
     HandleTorso = fct_read_short(CurrentSocket);
     HandleTorsoIndex = fct_read_short(CurrentSocket);
     HandleTorsoX = fct_read_byte(CurrentSocket);
     HandleTorsoY = fct_read_byte(CurrentSocket);
     HandleFacing = fct_read_byte(CurrentSocket);
     HandleLegs = fct_read_byte(CurrentSocket);
     
     Bullet = 0;
     
     for (Bullet=0;Bullet<5;Bullet+=1)
     {
      HandleProj[Bullet] = fct_read_byte(CurrentSocket);
      HandleProjX[Bullet] = fct_read_short(CurrentSocket);
      HandleProjY[Bullet] = fct_read_short(CurrentSocket);
      HandleProjAngle[Bullet] = fct_read_short(CurrentSocket);
      HandleProjSprite[Bullet] = fct_read_ushort(CurrentSocket);
      HandleProjIndex[Bullet] = fct_read_ushort(CurrentSocket);
     }

     
         
     for (ii = 0; ii < ds_list_size(NewList[1]); ii += 1)
     {
      SendSocket = ds_list_find_value(NewList[0], ii);
      if ds_list_find_value(NewList[1], ii) != HandleID
      {
       fct_write_ubyte(SendSocket, 79);
       fct_write_ushort(SendSocket, PACK_POS);
       fct_write_ubyte(SendSocket, HandleID);
       fct_write_ubyte(SendSocket, HandleExist);
       fct_write_short(SendSocket, HandleX);
       fct_write_short(SendSocket, HandleY);
       fct_write_short(SendSocket, HandleXVel);
       fct_write_short(SendSocket, HandleYVel);
       
       fct_write_short(SendSocket, HandleSprite);
       fct_write_short(SendSocket, HandleIndex);
       fct_write_short(SendSocket, HandleTorso);
       fct_write_short(SendSocket, HandleTorsoIndex);
       fct_write_byte(SendSocket, HandleTorsoX);
       fct_write_byte(SendSocket, HandleTorsoY);
       fct_write_byte(SendSocket, HandleFacing);
       fct_write_byte(SendSocket, HandleLegs);         
         
       for (Bullet=0;Bullet<5;Bullet+=1)
       {     
        fct_write_byte(SendSocket, HandleProj[Bullet]);
        fct_write_short(SendSocket, HandleProjX[Bullet]);
        fct_write_short(SendSocket, HandleProjY[Bullet]);
        fct_write_short(SendSocket, HandleProjAngle[Bullet]);
        fct_write_ushort(SendSocket, HandleProjSprite[Bullet]);
        fct_write_ushort(SendSocket, HandleProjIndex[Bullet]);           
       }
                       
       fct_socket_send(SendSocket);                       
      }
     }
   
     ds_priority_destroy(NewPriority);
     ds_list_destroy(NewList[0]);
     ds_list_destroy(NewList[1]); 
    break;
   } 
  }
}
}

ds_priority_destroy(NewewPriority);
ds_list_destroy(NewewList[0]);
ds_list_destroy(NewewList[1]);

// HANDLE TIMEOUTS

NewList[0] = ds_list_create();
NewList[1] = ds_list_create();
NewPriority = ds_priority_create();
   
ds_priority_copy(NewPriority, PlayerList);
   
for (i=0;i<ds_priority_size(PlayerList);i+=1)
{
ds_list_add(NewList[0], ds_priority_find_min(NewPriority));
ds_list_add(NewList[1], ds_priority_find_priority(NewPriority, ds_priority_find_min(NewPriority)));
ds_priority_delete_min(NewPriority);
}


for (i=0;i<global.MaxPlayers;i+=1)
{
if ds_list_find_index(NewList[1],i) == -1
  Timeout[i] = TIMEOUT;
}

for (ji=0;ji<ds_list_size(NewList[1]);ji+=1)
{
ID = ds_list_find_value(NewList[1],ji);

if ID != -1 && ID <= 7
{
  Timeout[ID] -= 1;
 
  if Timeout[ID] <= 0
  {   
   // Write to all
   
   for (i=0;i<ds_list_size(NewList[0]);i+=1)
   {
    Socket = ds_list_find_value(NewList[0], i); 
    fct_write_ubyte(Socket, 4 + 4);
    fct_write_ushort(Socket, PACK_DISCONNECT);
    fct_write_ubyte(Socket, ID);
    fct_write_ubyte(Socket, 4);
    fct_write_string(Socket, "TIME");
    fct_socket_send(Socket);
   }   

   ds_priority_delete_value(PlayerList, ds_list_find_value(NewList[0],ji));
     
   Timeout[ID] = TIMEOUT;
  }
}
}

ds_priority_destroy(NewPriority);
ds_list_destroy(NewList[0]);
ds_list_destroy(NewList[1]);



Horribly unoptimized.