Friday, January 10, 2020

architecture - Game actions that take multiple frames to complete


I've never really done much game programming before, pretty straightforward question.


Imagine I'm building a Tetris game, with the main loop looking something like this.


for every frame
handle input
if it's time to make the current block move down a row
if we can move the block
move the block
else
remove all complete rows

move rows down so there are no gaps
if we can spawn a new block
spawn a new current block
else
game over

Everything in the game so far happens instantly - things are spawned instantly, rows are removed instantly etc. But what if I don't want things to happen instantly (i.e animate things)?


for every frame
handle input
if it's time to make the current block move down a row

if we can move the block
move the block
else
?? animate complete rows disappearing (somehow, wait over multiple frames until the animation is done)
?? animate rows moving downwards (and again, wait over multiple frames)
if we can spawn a new block
spawn a new current block
else
game over


In my Pong clone this wasn't an issue, as every frame I was just moving the ball and checking for collisions.


How can I wrap my head around this issue? Surely most games involves some action that takes more than a frame, and other things halt until the action is done.



Answer



The traditional solution to this is a finite state machine, which is being suggested in several comments.


I hate finite state machines.


Sure, they're simple, they're supported in every language, but they're such an amazing pain to work with. Every manipulation takes a ton of bugprone copy-and-paste code, and tweaking the effect in small ways can be a huge change to code.


If you can use a language that supports them, I recommend coroutines. They let you write code that looks like:


function TetrisPieceExplosion()
for brightness = 0, 1, 0.2 do
SetExplosionBrightness(brightness)

coroutine.yield()
end

AllowNewBlockToFall()

SpawnABunchOfParticles()

RemoveBlockPhysics()

for transparency = 0, 1, 0.5 do

SetBlockTransparency(transparency)
coroutine.yield()
end

RemoveBlockGraphics()
end

Obviously rather pseudocodey, but it should be clear that not only is this a simple linear description of the special effect, but it easily lets us drop a new block while the animation is still finishing. Accomplishing this with a state machine will generally be ghastly.


To the best of my knowledge, this functionality isn't easily available in C, C++, C#, Objective C, or Java. This is one of the main reasons I use Lua for all my game logic :)


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...