Restore previous oldxp/oldyp variables in favor of lerpoldxp/lerpoldyp

I was investigating a desync in my Nova TAS, and it turns out that
the gravity line collision functions check for the `oldxp` and `oldyp`
of the player, i.e. their position on the previous frame, along with
their position on the current frame. So, if the player either collided
with the gravity line last frame or this frame, then the player collided
with the gravity line this frame.

Except, that's not actually true. It turns out that `oldxp` and `oldyp`
don't necessarily always correspond to the `xp` and `yp` of the player
on the previous frame. It turns out that your `oldyp` will be updated if
you stand on a vertically moving platform, before the gravity line
collision function gets ran. So, if you were colliding with a gravity
line on the previous frame, but you got moved out of there by a
vertically moving platform, then you just don't collide with the gravity
line at all.

However, this behavior changed in 2.3 after my over-30-FPS patch got
merged (#220). That patch took advantage of the existing `oldxp` and
`oldyp` entity attributes, and uses them to interpolate their positions
during rendering to make everything look real smooth.

Previously, `oldxp` and `oldyp` would both be updated in
`entityclass::updateentitylogic()`. However, I moved it in that patch to
update right before `gameinput()` in `main.cpp`.

As a result, `oldyp` no longer gets updated whenever the player stands
on a vertically moving platform. This ends up desyncing my TAS.

As expected, updating `oldyp` in `entityclass::movingplatformfix()` (the
function responsible for moving the player whenever they stand on a
vertically moving platform) makes it so that my TAS syncs, but the
visuals are glitchy when standing on a vertically moving platform. And
as much as I'd like to get rid of gravity lines checking for whether
you've collided with them on the previous frame, doing that desyncs my
TAS, too.

In the end, it seems like I should just leave `oldxp` and `oldyp` alone,
and switch to using dedicated variables that are never used in the
physics of the game. So I'm introducing `lerpoldxp` and `lerpoldyp`, and
replacing all instances of using `oldxp` and `oldyp` that my over-30-FPS
patch added, with `lerpoldxp` and `lerpoldyp` instead.

After doing this, and applying #503 as well, my Nova TAS syncs after
some minor but acceptable fixes with Viridian's walkingframe.
This commit is contained in:
Misa 2020-10-09 20:58:58 -07:00 committed by Ethan Lee
parent e8084fe699
commit b8a4b4dfe7
9 changed files with 56 additions and 50 deletions

View File

@ -56,6 +56,8 @@ entclass::entclass()
actionframe = 0;
realcol = 0;
lerpoldxp = 0;
lerpoldyp = 0;
}
bool entclass::outside()

View File

@ -49,6 +49,7 @@ public:
int yp;int xp;
Uint32 realcol;
int lerpoldxp, lerpoldyp;
};
#endif /* ENT_H */

View File

@ -1213,8 +1213,8 @@ void entityclass::createentity( float xp, float yp, int t, float vx /*= 0*/, flo
entclass entity;
entity.xp = xp;
entity.yp = yp;
entity.oldxp = xp;
entity.oldyp = yp;
entity.lerpoldxp = xp;
entity.lerpoldyp = yp;
entity.type = t;
switch(t)
{
@ -1783,7 +1783,7 @@ void entityclass::createentity( float xp, float yp, int t, float vx /*= 0*/, flo
entity.tile = 188 + vx;
entity.colour = 37;
entity.h += 3;
entity.oldyp -= 3;
entity.lerpoldyp -= 3;
entity.yp -= 3;
}
break;
@ -2440,20 +2440,20 @@ bool entityclass::updateentities( int i )
{
entities[i].tile = 120;
entities[i].yp = (28*8)-62;
entities[i].oldyp = (28*8)-62;
entities[i].lerpoldyp = (28*8)-62;
}
else
{
entities[i].tile = 96;
entities[i].yp = 24;
entities[i].oldyp = 24;
entities[i].lerpoldyp = 24;
}
//now, x position
if (INBOUNDS_VEC(player, entities) && entities[player].xp > 20 * 8)
{
//approach from the left
entities[i].xp = -64;
entities[i].oldxp = -64;
entities[i].lerpoldxp = -64;
entities[i].state = 2;
bool entitygone = updateentities(i); //right
if (entitygone) return true;
@ -2462,7 +2462,7 @@ bool entityclass::updateentities( int i )
{
//approach from the left
entities[i].xp = 320;
entities[i].oldxp = 320;
entities[i].lerpoldxp = 320;
entities[i].state = 3;
bool entitygone = updateentities(i); //left
if (entitygone) return true;
@ -2491,7 +2491,7 @@ bool entityclass::updateentities( int i )
{
entities[i].statedelay = 6;
entities[i].xp -= int(entities[i].para);
entities[i].oldxp -= int(entities[i].para);
entities[i].lerpoldxp -= int(entities[i].para);
}
break;
case 18: //Special for ASCII Snake (right)
@ -2499,7 +2499,7 @@ bool entityclass::updateentities( int i )
{
entities[i].statedelay = 6;
entities[i].xp += int(entities[i].para);
entities[i].oldxp += int(entities[i].para);
entities[i].lerpoldxp += int(entities[i].para);
}
break;
}
@ -4422,6 +4422,9 @@ void entityclass::updateentitylogic( int t )
return;
}
entities[t].oldxp = entities[t].xp;
entities[t].oldyp = entities[t].yp;
entities[t].vx = entities[t].vx + entities[t].ax;
entities[t].vy = entities[t].vy + entities[t].ay;
entities[t].ax = 0;

View File

@ -1987,8 +1987,8 @@ void Game::updatestate()
{
obj.entities[i].xp = obj.entities[j].xp+44;
obj.entities[i].yp = obj.entities[j].yp+44;
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
}
obj.entities[i].ay = -6;
obj.entities[i].ax = 6;
@ -3361,8 +3361,8 @@ void Game::updatestate()
{
obj.entities[i].xp = obj.entities[j].xp+44;
obj.entities[i].yp = obj.entities[j].yp+44;
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
obj.entities[j].tile = 2;
obj.entities[j].colour = 101;
}
@ -3492,8 +3492,8 @@ void Game::updatestate()
{
obj.entities[i].xp = obj.entities[j].xp+44;
obj.entities[i].yp = obj.entities[j].yp+44;
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
obj.entities[j].tile = 2;
obj.entities[j].colour = 101;
}
@ -3605,8 +3605,8 @@ void Game::updatestate()
{
obj.entities[i].xp = obj.entities[j].xp+44;
obj.entities[i].yp = obj.entities[j].yp+44;
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
obj.entities[j].tile = 2;
obj.entities[j].colour = 101;
}
@ -3718,8 +3718,8 @@ void Game::updatestate()
{
obj.entities[i].xp = obj.entities[j].xp+44;
obj.entities[i].yp = obj.entities[j].yp+44;
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
obj.entities[j].tile = 2;
obj.entities[j].colour = 101;
}
@ -3836,8 +3836,8 @@ void Game::updatestate()
{
obj.entities[i].xp = obj.entities[j].xp+44;
obj.entities[i].yp = obj.entities[j].yp+44;
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
obj.entities[j].tile = 2;
obj.entities[j].colour = 101;
}
@ -3954,8 +3954,8 @@ void Game::updatestate()
{
obj.entities[i].xp = obj.entities[j].xp+44;
obj.entities[i].yp = obj.entities[j].yp+44;
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
obj.entities[j].tile = 2;
obj.entities[j].colour = 101;
}
@ -4070,8 +4070,8 @@ void Game::updatestate()
{
obj.entities[i].xp = obj.entities[j].xp+44;
obj.entities[i].yp = obj.entities[j].yp+44;
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
obj.entities[j].tile = 2;
obj.entities[j].colour = 101;
}
@ -4183,8 +4183,8 @@ void Game::updatestate()
{
obj.entities[i].xp = obj.entities[j].xp+44;
obj.entities[i].yp = obj.entities[j].yp+44;
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
obj.entities[j].tile = 2;
obj.entities[j].colour = 101;
}
@ -4296,8 +4296,8 @@ void Game::updatestate()
{
obj.entities[i].xp = obj.entities[j].xp+44;
obj.entities[i].yp = obj.entities[j].yp+44;
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
obj.entities[j].tile = 2;
obj.entities[j].colour = 101;
}

View File

@ -1633,8 +1633,8 @@ void Graphics::drawentities()
continue;
}
int xp = lerp(obj.entities[i].oldxp, obj.entities[i].xp);
int yp = lerp(obj.entities[i].oldyp, obj.entities[i].yp);
int xp = lerp(obj.entities[i].lerpoldxp, obj.entities[i].xp);
int yp = lerp(obj.entities[i].lerpoldyp, obj.entities[i].yp);
switch (obj.entities[i].size)
{

View File

@ -1070,7 +1070,7 @@ void gamelogic()
obj.moveblockto(obj.entities[i].xp, obj.entities[i].yp, obj.entities[i].xp + 400, obj.entities[i].yp, obj.entities[i].w, obj.entities[i].h);
}
obj.entities[i].xp += 400;
obj.entities[i].oldxp += 400;
obj.entities[i].lerpoldxp += 400;
}
else if (obj.entities[i].xp > 320)
{
@ -1079,7 +1079,7 @@ void gamelogic()
obj.moveblockto(obj.entities[i].xp, obj.entities[i].yp, obj.entities[i].xp - 400, obj.entities[i].yp, obj.entities[i].w, obj.entities[i].h);
}
obj.entities[i].xp -= 400;
obj.entities[i].oldxp -= 400;
obj.entities[i].lerpoldxp -= 400;
}
}
else
@ -1091,7 +1091,7 @@ void gamelogic()
obj.moveblockto(obj.entities[i].xp, obj.entities[i].yp, obj.entities[i].xp + 320, obj.entities[i].yp, obj.entities[i].w, obj.entities[i].h);
}
obj.entities[i].xp += 320;
obj.entities[i].oldxp += 320;
obj.entities[i].lerpoldxp += 320;
}
else if (obj.entities[i].xp > 310)
{
@ -1100,7 +1100,7 @@ void gamelogic()
obj.moveblockto(obj.entities[i].xp, obj.entities[i].yp, obj.entities[i].xp - 320, obj.entities[i].yp, obj.entities[i].w, obj.entities[i].h);
}
obj.entities[i].xp -= 320;
obj.entities[i].oldxp -= 320;
obj.entities[i].lerpoldxp -= 320;
}
}
}
@ -1119,7 +1119,7 @@ void gamelogic()
obj.moveblockto(obj.entities[i].xp, obj.entities[i].yp, obj.entities[i].xp, obj.entities[i].yp + 232, obj.entities[i].w, obj.entities[i].h);
}
obj.entities[i].yp += 232;
obj.entities[i].oldyp += 232;
obj.entities[i].lerpoldyp += 232;
}
else if (obj.entities[i].yp > 226)
{
@ -1128,7 +1128,7 @@ void gamelogic()
obj.moveblockto(obj.entities[i].xp, obj.entities[i].yp, obj.entities[i].xp, obj.entities[i].yp - 232, obj.entities[i].w, obj.entities[i].h);
}
obj.entities[i].yp -= 232;
obj.entities[i].oldyp -= 232;
obj.entities[i].lerpoldyp -= 232;
}
}
}
@ -1149,7 +1149,7 @@ void gamelogic()
obj.moveblockto(obj.entities[i].xp, obj.entities[i].yp, obj.entities[i].xp + 350, obj.entities[i].yp, obj.entities[i].w, obj.entities[i].h);
}
obj.entities[i].xp += 350;
obj.entities[i].oldxp += 350;
obj.entities[i].lerpoldxp += 350;
}
else if (obj.entities[i].xp > 320)
{
@ -1158,7 +1158,7 @@ void gamelogic()
obj.moveblockto(obj.entities[i].xp, obj.entities[i].yp, obj.entities[i].xp - 350, obj.entities[i].yp, obj.entities[i].w, obj.entities[i].h);
}
obj.entities[i].xp -= 350;
obj.entities[i].oldxp -= 350;
obj.entities[i].lerpoldxp -= 350;
}
}
}
@ -1256,12 +1256,12 @@ void gamelogic()
if (obj.entities[i].xp <= -10)
{
obj.entities[i].xp += 320;
obj.entities[i].oldxp += 320;
obj.entities[i].lerpoldxp += 320;
}
else if (obj.entities[i].xp > 310)
{
obj.entities[i].xp -= 320;
obj.entities[i].oldxp -= 320;
obj.entities[i].lerpoldxp -= 320;
}
}
}

View File

@ -894,8 +894,8 @@ void mapclass::warpto(int rx, int ry , int t, int tx, int ty)
{
obj.entities[t].xp = tx * 8;
obj.entities[t].yp = (ty * 8) - obj.entities[t].h;
obj.entities[t].oldxp = obj.entities[t].xp;
obj.entities[t].oldyp = obj.entities[t].yp;
obj.entities[t].lerpoldxp = obj.entities[t].xp;
obj.entities[t].lerpoldyp = obj.entities[t].yp;
}
game.gravitycontrol = 0;
}
@ -1100,8 +1100,8 @@ void mapclass::gotoroom(int rx, int ry)
temp = obj.getplayer();
if(INBOUNDS_VEC(temp, obj.entities))
{
obj.entities[temp].oldxp = obj.entities[temp].xp - int(obj.entities[temp].vx);
obj.entities[temp].oldyp = obj.entities[temp].yp - int(obj.entities[temp].vy);
obj.entities[temp].lerpoldxp = obj.entities[temp].xp - int(obj.entities[temp].vx);
obj.entities[temp].lerpoldyp = obj.entities[temp].yp - int(obj.entities[temp].vy);
}
for (size_t i = 0; i < obj.entities.size(); i++)

View File

@ -3447,8 +3447,8 @@ void scriptclass::teleport()
obj.entities[i].xp = 150;
obj.entities[i].yp = 110;
if(game.teleport_to_x==17 && game.teleport_to_y==17) obj.entities[i].xp = 88; //prevent falling!
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
}
if (game.teleportscript == "levelonecomplete")

View File

@ -542,11 +542,11 @@ void inline fixedloop()
script.run();
}
//Update old positions of entities - has to be done BEFORE gameinput!
//Update old lerp positions of entities - has to be done BEFORE gameinput!
for (size_t i = 0; i < obj.entities.size(); i++)
{
obj.entities[i].oldxp = obj.entities[i].xp;
obj.entities[i].oldyp = obj.entities[i].yp;
obj.entities[i].lerpoldxp = obj.entities[i].xp;
obj.entities[i].lerpoldyp = obj.entities[i].yp;
}
gameinput();