In Pygame, normalizing game-speed across different

2020-03-18 21:03发布

I'm messing around with Pygame, making some simple games just to learn it. However, I'm having a hard time implementing fps the way that I want.

From what I understand, fps is generally set with:

import pygame
...
clock = pygame.time.Clock()
while True:
    clock.tick(60)

And then throughout the program, I make sure that every loop/frame is written to take 1/60th of a second, so I can, for example, make objects move at the speed I want them too. Increasing the tick to 120 fps will make the game run too fast, while decreasing it will make the game run too slow.

However, this is not how I'm familiar with fps working for any other game. In most games, fps can vary as much as you want (usually based on how well the system is running the application), but the game will always run at the same speed (e.g. moving 100 pixels across the screen will take 1 second no matter how many frames happened in that second).

The only way I can think of getting it to work the way I want is to grab the current fps every frame, and factor that into the calculations of every movement or time based event. But that seems needlessly complicated, and I'm wondering if I'm completely missing a part of pygame functionality that figures that out for me.

标签: python pygame
4条回答
一夜七次
2楼-- · 2020-03-18 21:08

You can define the speed of your objects in pixels/second, then use the returned value from tick to know how much every object should move.

Example

import pygame
...
player_speed = (20, 0)   # (x,y) pixels/second
...
pygame.time.Clock() = clock
elapsed = 0.
while True:
    seconds = elapsed/1000.0
    update_player(seconds)
    ...
    elapsed = clock.tick(60)

def update_player(seconds):
    player.position = (player.position[0] + int(player_speed[0]*seconds), 
                       player.position[1] + int(player_speed[1]*seconds))
查看更多
趁早两清
3楼-- · 2020-03-18 21:28

If you want to move an object at a fixed speed at every FPS you can indicate speed not with an absolute value, but with a value relative to the movement to be done in a second, then divide that by the number of frames per second.

For example, if you want your object to move at a speed of 2 pixels per frame, let's say at 30 FPS, and you want this speed to be the same at every FPS, you can indicate it as the pixel movement in a second, which would be 60. In the game loop, when you need to update the speed, you'll use this speed divided by FPS, thus resulting in the relative speed used in every frame update. In this way, at 30 FPS you'll get a 2 pixel movement for each frame, while at 60 FPS you'll get a 1 pixel movement, but after 1 second you will have the same amount of pixel movement, which is 60.

查看更多
Emotional °昔
4楼-- · 2020-03-18 21:33

Games use a fixed-timestep for physics, while allowing the video timestep (fps) to vary. This means your update(delta) function gets called with a constant delta value. This maintains stability.

This means in practice, update may end up being called multiple times on average per single call of draw(), depending on how much time elapses.

For details see: Gaffer's "fix your timestep"

A larger (python) example is at cookbook: ConstantGametime

查看更多
beautiful°
5楼-- · 2020-03-18 21:35

While @monkey's answer is the complete datadump, you should probably have a look over the pygame docs on time.Clock again. The optional framerate argument to Clock.tick() sets a ceiling on FPS, not a fixed FPS; in other words, if your game loop takes longer than that amount of time to complete, the game will lag if you are assuming that passing that value ensures a fixed game speed. It looks like Clock.get_time() and Clock.get_raw_time() are the things to use to get the execution time of the last game loop, then you can calculate the behavior of your game elements from that.

查看更多
登录 后发表回答