Search code examples
pythonpython-3.xpygamegame-enginegame-development

Get the frame number for a looping animation range based only on system time


I'm looking for a way to animate a sprite using just the system time, without having to increment and store the active frame or time passed as a variable. I should be able to achieve this by properly stretching and looping the ms to get a range, accounting for animation speed the total number of frames and the range I want to fetch. My project is based on Pygame, unless it has a more useful function for this I'm trying to achieve it with the generic Python time.time() value.

Let's say I have a sprite with 30 frames and I currently want to loop frames 10 to 20 at a speed of 2 frames per second (advance every 0.5 seconds). I have my "milliseconds passed since 1 January 1970" value: I need to convert it into an integer between 10 and 19 to indicate what the current frame is. For example: If I call the function now I get 18, if 0.25 seconds pass I still get 18, if another 0.25 seconds pass this time I get 19, I call the function again 0.5 seconds later and get 10 as it restarts, if I wait a full second then call it again I now get 12.

Please suggest the cheapest solution if possible, I will use this in a place where calculations are frequent and expensive. In normal circumstances I'd store the old time then compare how much time passed since the last call, but I'm doing this in a thread pool which can't affect outside variables so I can't store permanent changes on the main thread. Only disadvantage to this technique is the count can start from anywhere so animations won't always play from the beginning of the range... this could be worked around by giving my sprite class the current time before threads start working then offsetting based on that, but this isn't a big deal so if it's too complex this part can be left out.


Solution

  • Someone provided the solution on Reddit, credits to @txuby for the math. I tried it out and this works exactly as intended.

    start_idx = 10
    end_idx = 20
    ms_per_frame = 500
    
    t = int(time.time() * 1000)
    current_idx = start_idx + (t // ms_per_frame) % (end_idx - start_idx)