There is a main game loop in my program, which calls game update every frame. However, to make better animation and better control, there is a need to implement a function like updateEveryNFrames(n, func)
.
I am considering implementing a counter for each update. The counter will be added by one each frame. The update function will be invoked according to the counter % n
.
For example, in a sequence of sprites animation, I can use the above function to control the speed of the animation.
Can some give some advice or other solutions?
Answer
So what you want is one loop to run slow (say 10 fps or hz), and another loop for animation to run faster (30fps or hz), yes?
You can do it the way you say but actually it's much simpler when done something like:
//we are working in ms for setTimeout's sake; 1000ms per second
var ANIMATION_FREQ = 33;
var ANIMATION_PERIOD = 1000 / ANIMATION_FREQ;
var LOGIC_FREQ = 10;
var LOGIC_PERIOD = 1000 / LOGIC_FREQ;
setTimeout(ANIMATION_PERIOD, updateAnimation);
setTimeout(ANIMATION_PERIOD, updateGameLogic);
void updateAnimation() { ... do animation stuff... }
void updateGameLogic() { ... do game logic stuff... }
There is nothing wrong with just running two separate timers in parallel like this -- since your view should be well decoupled from your data and control logic anyway.
An excellent source on how best to implement timing is Gaffer's Fix Your Timestep.
As to what you do inside updateGameLogic
:
- Accept input from player(s) (via input devices, eg. pressing up arrow might equate to input code "up")
- Accept input from AIs (via either functions or classes that produce same as input codes for player, eg. FSM AI wants to go up means it will produce output "up")
- Based on inputs, perform your basic physics or otherwise do movement per entity, and add new entities. You must not add or remove entities directly to your entity list in this phase, because you are still in the midst of processing the entity list. You can add eg. new bullet entities in this phase by adding them to an "additions" list.
- Run through entities, testing each against every other for a possible collision (see 2nd part of my answer here). Any entities that get expired (eg. due to a collision) must still not be removed immediately, but rather added to a "removals" list (because otherwise you will break the list while it's being processed for physics.
- Finally, add everything in the additions list to the main entity list, and remove everything in the removals list from the main entity list. Then flush those two auxiliary lists so they are ready to be used for the next update.
You're using a separate loop for animation / rendering, so you don't need to worry about including it here, but many people put that in as a final step (which causes issues as Gaffer notes in his article.)
You can also refer to this question for some overview of the order inside your update function.
No comments:
Post a Comment