|
| 1 | +"""Track and control game time and framerate. |
| 2 | +
|
| 3 | +.. note:: |
| 4 | +
|
| 5 | + This is a **MODIFIED**, pure Python implementation of time-related functions |
| 6 | + from `PyGameSDL2's time`_, in Cython, released under zlib license. |
| 7 | +
|
| 8 | +.. code-block:: none |
| 9 | +
|
| 10 | + PygameSDL2 Notice / zlib License: |
| 11 | +
|
| 12 | + -------------------------------------------------------------------------- |
| 13 | + Original work: |
| 14 | + Copyright 2014 Tom Rothamel <[email protected]> |
| 15 | + Copyright 2014 Patrick Dawson <[email protected]> |
| 16 | + Modified work: |
| 17 | + Copyright 2017 Lucas Siqueira <[email protected]> |
| 18 | +
|
| 19 | + This software is provided 'as-is', without any express or implied |
| 20 | + warranty. In no event will the authors be held liable for any damages |
| 21 | + arising from the use of this software. |
| 22 | +
|
| 23 | + Permission is granted to anyone to use this software for any purpose, |
| 24 | + including commercial applications, and to alter it and redistribute it |
| 25 | + freely, subject to the following restrictions: |
| 26 | +
|
| 27 | + 1. The origin of this software must not be misrepresented; you must not |
| 28 | + claim that you wrote the original software. If you use this software |
| 29 | + in a product, an acknowledgment in the product documentation would be |
| 30 | + appreciated but is not required. |
| 31 | + 2. Altered source versions must be plainly marked as such, and must not |
| 32 | + be misrepresented as being the original software. |
| 33 | + 3. This notice may not be removed or altered from any source |
| 34 | + distribution. |
| 35 | + -------------------------------------------------------------------------- |
| 36 | +
|
| 37 | +.. _`PyGameSDL2's time`: https://www.github.com/renpy/pygame_sdl2/blob/\ |
| 38 | + master/src/pygame_sdl2/pygame_time.pyx |
| 39 | +""" |
| 40 | + |
| 41 | +import math |
| 42 | +from ..timer import SDL_Delay, SDL_GetTicks |
| 43 | + |
| 44 | + |
| 45 | +__all__ = ('Clock', 'wait', 'get_time', 'get_delta') |
| 46 | + |
| 47 | + |
| 48 | +def get_delta(t0): |
| 49 | + """Get the time elapsed since the passed time.""" |
| 50 | + return get_time - t0 |
| 51 | + |
| 52 | + |
| 53 | +def get_time(): |
| 54 | + """Get the current time from SDL clock.""" |
| 55 | + return SDL_GetTicks() |
| 56 | + |
| 57 | + |
| 58 | +def wait(milliseconds): |
| 59 | + """Pause the program for an amount of time. |
| 60 | +
|
| 61 | + Will pause for a given number of milliseconds. This function sleeps the |
| 62 | + process to share the processor with other programs. A program that waits |
| 63 | + for even a few milliseconds will consume very little processor time. |
| 64 | +
|
| 65 | + Usage: |
| 66 | + wait(milliseconds) |
| 67 | +
|
| 68 | + Returns: |
| 69 | + int (the actual number of milliseconds used) |
| 70 | + """ |
| 71 | + start = SDL_GetTicks() |
| 72 | + SDL_Delay(int(milliseconds)) |
| 73 | + return SDL_GetTicks() - start |
| 74 | + |
| 75 | + |
| 76 | +class Clock: |
| 77 | + """Clock is used track and control the framerate of a game. |
| 78 | +
|
| 79 | + The clock can be used to limit the framerate of a game, as well as track |
| 80 | + the time used per frame. |
| 81 | +
|
| 82 | + Usage: |
| 83 | + clock = time.Clock() |
| 84 | + """ |
| 85 | + |
| 86 | + def __init__(self): |
| 87 | + """Initialization.""" |
| 88 | + self.last = SDL_GetTicks() |
| 89 | + self.last_frames = [] |
| 90 | + self.frametime = 0 |
| 91 | + self.raw_frametime = 0 |
| 92 | + |
| 93 | + def tick(self, framerate=0): |
| 94 | + """Update the Clock. |
| 95 | +
|
| 96 | + This method should be called once per frame. It will compute how many |
| 97 | + milliseconds have passed since the previous call. |
| 98 | +
|
| 99 | + If you pass the optional framerate argument the function will delay |
| 100 | + to keep the game running slower than the given ticks per second. This |
| 101 | + can be used to help limit the runtime speed of a game. By calling |
| 102 | + clock.tick(40) once per frame, the program will never run at more |
| 103 | + than 40 frames per second. |
| 104 | +
|
| 105 | + Usage: |
| 106 | + tick(framerate=0) |
| 107 | +
|
| 108 | + Returns: |
| 109 | + float (milliseconds) |
| 110 | + """ |
| 111 | + now = SDL_GetTicks() |
| 112 | + self.raw_frametime = now - self.last |
| 113 | + while len(self.last_frames) > 9: |
| 114 | + self.last_frames.pop(0) |
| 115 | + if framerate == 0: |
| 116 | + self.last = now |
| 117 | + self.last_frames.append(self.raw_frametime) |
| 118 | + return self.raw_frametime |
| 119 | + frame_duration = 1.0 / framerate * 1000 |
| 120 | + if self.raw_frametime < frame_duration: |
| 121 | + wait(frame_duration - self.raw_frametime) |
| 122 | + now = SDL_GetTicks() |
| 123 | + self.frametime = now - self.last |
| 124 | + self.last = now |
| 125 | + self.last_frames.append(self.frametime) |
| 126 | + return self.frametime |
| 127 | + |
| 128 | + def get_time(self): |
| 129 | + """Time used in the previous tick. |
| 130 | +
|
| 131 | + Returns the parameter passed to the last call to Clock.tick(). |
| 132 | +
|
| 133 | + Usage: |
| 134 | + clock.get_time() |
| 135 | +
|
| 136 | + Returns: |
| 137 | + int (milliseconds) |
| 138 | + """ |
| 139 | + return self.frametime |
| 140 | + |
| 141 | + def get_rawtime(self): |
| 142 | + """Actual time used in the previous tick. |
| 143 | +
|
| 144 | + Similar to Clock.get_time(), but this does not include any time used |
| 145 | + while clock.tick() was delaying to limit the framerate. |
| 146 | +
|
| 147 | + Usage: |
| 148 | + clock.get_rawtime() |
| 149 | +
|
| 150 | + Returns: |
| 151 | + int (milliseconds) |
| 152 | + """ |
| 153 | + return self.raw_frametime |
| 154 | + |
| 155 | + def get_fps(self): |
| 156 | + """Compute the clock framerate. |
| 157 | +
|
| 158 | + Compute your game's framerate (in frames per second). It is computed |
| 159 | + by averaging the last ten calls to Clock.tick(). |
| 160 | +
|
| 161 | + Usage: |
| 162 | + get_fps() |
| 163 | +
|
| 164 | + Returns: |
| 165 | + float |
| 166 | + """ |
| 167 | + total_time = sum(self.last_frames) |
| 168 | + average_time = total_time / 1000.0 / len(self.last_frames) |
| 169 | + average_fps = 1.0 / average_time |
| 170 | + return 0 if math.isnan(average_fps) else average_fps |
0 commit comments