By "frame" here I'm referring to the fixed-timestep, not a visual
delta-timestep.
Anyway, the problem is because crewmates' drawframes wait for
entityclass::animateentities() to be called in gamelogic(). In the
old, 30-FPS-only system, this entityclass::animateentities() would be
called in gamerender(), before any actual rendering would take place.
However, I've had to move it out of gamerender() because otherwise
entities would animate too fast. As a result, since gamerender() could
be called in between the entity creation and gamelogic(), a
less-than-1-frame visual glitch could happen.
The solution is to set the entity's drawframe as well when fixing facing
the player in Map.cpp.
Incidentally enough, this de-duplicates the amount of times this code
has been copy-pasted from 4 times to 2.
Anyways, this makes it so the crew don't go lightning fast on the
summary screen, the NDM game-over screen, the NDM win screen, and the
pause screen in the main game. It was slightly hilarious seeing them go
really quickly, actually. It was like they were running away from a
giant monster or something.
Just to make sure it's extra smooth. Not that it will be noticeable, and
you can't access the Secret Lab in slowmode without modifying the game,
but it's nice to have this.
Otherwise it'll go by really fast and rapidly pulsate. To the point
where it seems like it would be an epilepsy trigger, although I
wouldn't know anything about epilepsy other than that it's bad.
Ok, now THIS takes the cake for "only really noticeable in slowmode",
because it only ever moves at 1 pixel per second. And even then,
slowmode shouldn't apply on the title screen, so it won't even show up
there once I get around to doing that change.
This is so the background doesn't NYOOOOM past at light speed. Although
for a game set in space like VVVVVV, light speed ain't bad.
And this finally requires that editorlogic() have a call to
Graphics::updatebackground().
To make it real smooth, just in case it was noticeable that it only
updated at 1000/34 FPS before (well, except in slowmode, it's really
noticeable THERE).
Also this removes the re-typing out of (game.act_fade/10.0f) for every
single R, G, and B in gamerender().
This makes text boxes fade in and out pretty smoothly.
This requires that the textboxclass::setcol() be in Graphics::drawgui(),
so now it's moved there.
Text box fading is only really noticeable if you're playing in slowmode.
This has to be done in order to fix rendering when on a conveyor or
moving platform and actively moving with or against it. Pretty sure this
shouldn't break anything, oldxp/oldyp is mostly visual after all (and by
the time it's used for gravity line collision checking,
updateentitylogic() would've already gotten around to it anyway).
Incidentally, this also fixes a jitter that would occur if you were
moving at the time you died or collected a trinket or custom crewmate,
due to the game temporarily freezing and either doing deathsequence or
completestop.
Now it's really, really smooth. Except for like the last frame when it
goes down, which I sometimes didn't notice (but maybe it didn't happen
every time due to being lucky on the delta timesteps or something,
whatevs.)
Since "if (graphics.resumegamemode)" and "if (menuoffset > 0)" both do
the same thing, they've been combined with an "or" conjunction.
As well, the map.extrarow check in maplogic() has been refactored to use
a variable instead of duplicating the entire code block. Not that it
matters anyway, because the difference between 240 and 230 is only 10
pixels, far short of the 25 pixel increment that bringing the menu up
and down uses, and both 240 and 230 integer-divided by 25 have the same
non-remainder value of 9.
Otherwise the screen will shake too fast for my liking.
Also I'm planning to add an FPS limiting option later (because right
now, un-capping the FPS is pretty wasteful and eats up lots of
resources, especially since I have only a 60hz monitor), and it'd feel
weird if screen shaking updated every delta timestep.
This fixes entities being drawframe 0 for 1 frame when being first
created. Incidentally, this also fixes entities created during
completestop being the player sprite, too, which is something not many
people notice.
For some reason, it was put near the start of gamerender(), even though
since it handles edge-flipping it seems like it should be in the logic
function already.
This makes sure entity animations don't animate as fast as possible, and
also fixes edge-flipping on normal surfaces.
This prevents undefined behavior because we use oldxp/oldyp to do linear
interpolation.
It's also initialized in entclass::entclass(), just to be sure. And I've
deduplicated the regular xp/yp initialization in createentity(), too.
I've added a function Graphics::lerp() which simply interpolates between
two values given a certain alpha value. It's just like drawing a
straight line between two points.
Also, Graphics now has an `alpha` attribute, and it is set on every
deltatime update to be used in linear interpolation.
Ok, and this is where the fun starts.
In an ideal world, this would be the end of this patch. However, of
course, there are many, MANY places in the game that update
fixed-timestep timers DIRECTLY inside the render function, which is not
ideal because it means those timers go super fast.
I'll have to fix those later.
Ok, NOW indent it. I didn't indent it previously because the diffs are
annoying to read if there's an indent that doesn't otherwise change
anything (and even now it's pretty annoying to read).
Alright, this is the start of the over-30-FPS patch!
First things first, we'll need to make it possible to have a separate
deltatime loop outside of the fixed timestep loop. And for that, we
can't be using SDL_Delay(), as SDL_Delay() (as you might imagine) blocks
the whole program.
Instead we'll be using this thing called an accumulator. It looks at how
long the previous poll took (the raw deltatime), and lets timesteps pass
accordingly.
On a side note, I've had to split the `time` and `timePrev` declaration
each onto their own separate line, otherwise there's undefined behavior
from `time` not being initialized.
I use `accumulator = fmodf(...)` instead of `accumulator -=
timesteplimit` because otherwise it'll fast-forward if it's behind,
which is a jarring thing to see.
Also in preparation for what's going to come down the over-30-FPS road,
I've also added `deltatime` and `alpha`. `deltatime` is going to be used
if the game is in slowdown mode, and `alpha` is going to be used for
linear interpolation of animations.
By the way, what was the main game loop previously (and is now the new
timestep loop) is now in an extra set of curly braces, but I haven't
indented it yet to reduce the noise in this commit.
This prevents being able to "roll over" the amount of minutes to 0 (by
simply waiting for the timer to tick past one hour) and being able to
get a result of 00:13 when your result is really 01:00:13.
By looking only at the minutes, the game would read 01:00:13 as 00:13
instead. So simply add the amount of hours to the time trial result.
This is needed for MinGW when compiling C++98, apparently. I put it in
an if-guard because otherwise there'll be a warning from MY compiler
about redefinitions.