- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在制作 python 游戏,但我不知道应该将 FPS 设置为多少。我的游戏卡住了,不流畅。我怎么知道 FPS 应该是多少?
这是我的代码:
最佳答案
运行您的代码后,我还注意到帧速率下降,这会影响游戏的流畅度。
这里有两个不同的问题:
<强>1。 FPS 下降
FPS 下降的原因可能是您无法控制的,例如垃圾收集器的工作。即使您无法控制此类问题,您通常也可以提高游戏的性能。请参阅以下游戏分析器运行的屏幕截图:
可以看到大部分时间花在了blit
上。然而,很大一部分时间也花在了 get_y_list
上。 get_y_list
方法还使用大型列表,这会为垃圾收集器稍后收集产生大量垃圾,从而进一步影响性能。
据我了解,get_y_list
方法是您用于碰撞检测的一种非常粗略的方法的一部分,该方法基本上需要二次方时间。您的算法似乎将每个对象划分为大量的二维单元格,然后测试每对单元格之间的碰撞。相反,您可以只测试框与框的交集。如果您希望对象具有复杂的碰撞形状,您可以使用其他算法,互联网上有很多这样的算法。例如:https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
使用其他算法进行碰撞检测将大大提高您的性能。
<强>2。当 FPS 下降时,游戏变得不流畅。
对象的 x
和 y
位置正在更新,例如:player.x -= player.vx
。物理上正确的方法是:player.x -= player.vx * DELTA_T
。其中 DELTA_T 是自上一帧以来耗时。如果您不使用自上一帧以来耗时,则角色的运动速度将取决于 FPS。这正是我们所看到的。
您可能会问,我从哪里得到 DELTA_T
。你在调用 tick 时直接执行:
def main():
global DELTA_T
finish = False
background_x = 0
background_y = 0
background = pygame.image.load(BACKGROUND_IAMGE)
while not finish:
DELTA_T = clock.tick(REFRESH_RATE)
我尝试用 DELTA_T
进行乘法运算,但游戏变得不稳定,因为您假设对象在每一帧中精确地前进 vx
个“单元格”以检测碰撞和地板穿透.请参阅下面的尝试:
import pygame
pygame.init()
WINDOW_WIDTH = 700
WINDOW_HEIGHT = 500
SIZE = (WINDOW_WIDTH, WINDOW_HEIGHT)
SCREEN = pygame.display.set_mode(SIZE)
pygame.display.set_caption("Python Game")
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
PINK = (255, 0, 255)
BACKGROUND_IAMGE = 'back.png'
clock = pygame.time.Clock()
REFRESH_RATE = 30
FRAMES_DELAY = 3
PLAYER_HEIGHT = 72
PLAYER_WIDTH = 40
MUSHROOM_HEIGHT = 31
MUSHROOM_WIDTH = 40
BLOCK_HEIGHT = 30
BLOCK_WIDTH = 30
FLOOR_Y = 435
DELTA_T = 0
class Player:
def __init__(self, x, y):
self.__images = [pygame.image.load('mario1.png'), pygame.image.load('mario2.png'),
pygame.image.load('mario3.png'), pygame.image.load('mario4.png'),
pygame.image.load('mario5.png'), pygame.image.load('mario6.png')]
self.__current_image = self.__images[0]
self.x = x
self.y = y
self.vx = 5/33.
self.vy = 10/33.
self.__is_mid_air = False
self.__direction = "right"
self.__is_jumping = False
self.__MAX_JUMP = 20
self.__is_walking = False
self.__counter = 0
self.__jump_counter = 0
def reset_jump_counter(self):
self.__jump_counter = 0
def get_bottom_y(self):
return int(self.y + PLAYER_HEIGHT)
def set_walk(self, bol):
self.__is_walking = bol
def set_is_mid_air(self, bol):
self.__is_mid_air = bol
def is_mid_air(self):
return self.__is_mid_air
def get_image(self):
if self.__is_mid_air and self.__direction == "right":
self.__current_image = self.__images[4]
return self.__current_image
if self.__is_mid_air and self.__direction == "left":
self.__current_image = self.__images[5]
return self.__current_image
self.__counter += 1
if self.__counter > FRAMES_DELAY:
self.__counter = 0
if self.__counter == FRAMES_DELAY and self.__direction == "right":
if self.__is_walking and self.__current_image == self.__images[0]:
self.__current_image = self.__images[1]
else:
self.__current_image = self.__images[0]
if self.__counter == FRAMES_DELAY and self.__direction == "left":
if self.__is_walking and self.__current_image == self.__images[2]:
self.__current_image = self.__images[3]
else:
self.__current_image = self.__images[2]
return self.__current_image
def stand_still(self):
if self.__direction == "right":
self.__current_image = self.__images[0]
if self.__direction == "left":
self.__current_image = self.__images[2]
def set_jump(self, bol):
self.__is_jumping = bol
if not bol:
self.reset_jump_counter()
def check_jump(self):
if self.__jump_counter != self.__MAX_JUMP and self.__is_jumping:
self.y -= self.vy * DELTA_T
self.__jump_counter += 1
if self.__jump_counter >= self.__MAX_JUMP:
self.__is_jumping = False
self.__jump_counter = 0
def is_jumping(self):
return self.__is_jumping
def fall(self):
if not self.__is_jumping:
self.y += self.vy * DELTA_T
def get_direction(self):
return self.__direction
def turn_around(self):
if self.__direction == "right":
self.__direction = "left"
elif self.__direction == "left":
self.__direction = "right"
def get_x_list(self):
result = []
for i in range(PLAYER_WIDTH + 1):
result.append(self.x + i)
return result
def get_y_list(self):
result = []
for i in range(PLAYER_HEIGHT + 1):
result.append(self.y + i)
return result
def get_right_x(self):
return self.x + PLAYER_WIDTH
def is_crash(self, obj):
is_x_equals = False
for i in range(int(self.vx * DELTA_T+0.5)):
if self.x + PLAYER_WIDTH + i in obj.get_x_list():
is_x_equals = True
if self.x - i in obj.get_x_list():
is_x_equals = True
is_y_equals = False
for i in range(int(self.vy*DELTA_T+0.5)):
if self.y + PLAYER_HEIGHT + i in obj.get_y_list():
is_y_equals = True
if self.y - i in obj.get_y_list():
is_y_equals = True
return is_x_equals and is_y_equals
class Monster:
def __init__(self, x, y, vx, vy, monster_type):
self.__images = [pygame.image.load(monster_type + '1.png').convert(),
pygame.image.load(monster_type + '2.png').convert()]
if monster_type == "mushroom":
self.__width = MUSHROOM_WIDTH
self.__height = MUSHROOM_HEIGHT
self.__current_image = self.__images[0]
self.__FIRST_X = x
self.__FIRST_Y = y
self.__x = x
self.__y = y
self.__vx = vx
self.__vy = vy
self.__direction = "left"
self.__monster_type = monster_type
self.__counter = 0
def get_image(self):
self.__counter += 1
if self.__counter > FRAMES_DELAY:
self.__counter = 0
if self.__monster_type == "mushroom" and self.__counter == FRAMES_DELAY:
if self.__current_image == self.__images[1]:
self.__current_image = self.__images[0]
self.__current_image.set_colorkey(PINK)
else:
self.__current_image = self.__images[1]
self.__current_image.set_colorkey(PINK)
return self.__current_image
elif self.__monster_type == "mushroom" and self.__counter != FRAMES_DELAY:
self.__current_image.set_colorkey(PINK)
return self.__current_image
def get_x(self):
return self.__x
def get_vx(self):
return self.__vx
def get_vy(self):
return self.__vx
def get_y(self):
return self.__y
def step(self):
if self.__direction == "right":
self.__x += self.__vx * DELTA_T
elif self.__direction == "left":
self.__x -= self.__vx * DELTA_T
def get_direction(self):
return self.__direction
def turn_around(self):
if self.__direction == "right":
self.__direction = "left"
elif self.__direction == "left":
self.__direction = "right"
def get_x_list(self):
result = []
for i in range(MUSHROOM_WIDTH + 1):
result.append(self.__x + i)
return result
def get_y_list(self):
result = []
for i in range(MUSHROOM_HEIGHT + 1):
result.append(self.__y + i)
return result
def is_crash(self, obj):
is_x_equals = False
for i in range(int(self.__vx * DELTA_T+0.5)):
if self.__x + self.__width + i in obj.get_x_list():
is_x_equals = True
if self.__x - i in obj.get_x_list():
is_x_equals = True
is_y_equals = False
for i in range(int(self.__vy * DELTA_T+0.5)):
if self.__y + self.__height + i in obj.get_y_list():
is_y_equals = True
if self.__y - i in obj.get_y_list():
is_y_equals = True
return is_x_equals and is_y_equals
class Block:
def __init__(self, x, y, width=1, height=1):
self.__image = pygame.image.load("block.png")
self.__x = x
self.__y = y
self.__width = width
self.__height = height
def load_image(self, background_x):
for i in range(self.__width):
for j in range(self.__height):
SCREEN.blit(self.__image, (self.__x + (i * BLOCK_WIDTH) + background_x, self.__y + (j * BLOCK_HEIGHT)))
def get_x_list(self):
result = []
for i in range(BLOCK_WIDTH * self.__width + 1):
result.append(self.__x + i)
return result
def get_y_list(self):
result = []
for i in range(BLOCK_HEIGHT * self.__height + 1):
result.append(self.__y + i)
return result
def get_y(self):
return self.__y
def get_x(self):
return self.__x
def get_width(self):
return self.__width
def get_height(self):
return self.__height
def get_bottom_y(self):
return self.__y + (BLOCK_HEIGHT * self.__height)
def get_right_x(self):
return self.__x + self.__width * BLOCK_WIDTH
player = Player(140, FLOOR_Y - PLAYER_HEIGHT)
blocks = [Block(270, 280, 1, 1), Block(301, FLOOR_Y - BLOCK_HEIGHT * 8, 1, 8),
Block(600, FLOOR_Y - BLOCK_HEIGHT * 8, 2, 8)]
monsters = [Monster(380, FLOOR_Y - MUSHROOM_HEIGHT, 3/33., 3/33., "mushroom")]
def main():
global DELTA_T
finish = False
background_x = 0
background_y = 0
background = pygame.image.load(BACKGROUND_IAMGE)
while not finish:
DELTA_T = clock.tick(REFRESH_RATE)
SCREEN.blit(background, (background_x, background_y))
for event in pygame.event.get():
if event.type == pygame.QUIT:
finish = True
block_on_right = False
block_on_left = False
is_player_on_block = False
for block in blocks:
block.load_image(background_x)
for i in range(int(player.vy * DELTA_T+0.5)):
for x in player.get_x_list():
if player.get_bottom_y() + i == block.get_y() and x in block.get_x_list():
is_player_on_block = True
player.y += i
if player.y - i == block.get_bottom_y() and x in block.get_x_list():
player.set_jump(False)
player.y -= i
for i in range(int(player.vx*DELTA_T+0.5)):
for y in player.get_y_list():
if player.get_right_x() + i == block.get_x() and y in block.get_y_list():
block_on_right = True
player.x += (i - 1)
background_x -= (i - 1)
if player.x - i == block.get_right_x() and y in block.get_y_list():
block_on_left = True
player.x -= (i - 1)
background_x += (i - 1)
for monster in monsters:
if monster.is_crash(block):
monster.turn_around()
keys = pygame.key.get_pressed()
if (keys[pygame.K_UP] or keys[pygame.K_SPACE] or keys[pygame.K_w]) and not player.is_mid_air():
player.set_jump(True)
if (keys[pygame.K_RIGHT] or keys[pygame.K_d]) and not block_on_right:
if player.get_direction() != "right":
player.turn_around()
player.set_walk(True)
background_x -= player.vx * DELTA_T
player.x += player.vx * DELTA_T
if (keys[pygame.K_LEFT] or keys[pygame.K_a]) and not block_on_left:
if player.get_direction() != "left":
player.turn_around()
player.set_walk(True)
if background_x != 0:
background_x += player.vx * DELTA_T
player.x -= player.vx * DELTA_T
if not any(keys):
player.stand_still()
player.set_walk(False)
for monster in monsters:
monster.step()
SCREEN.blit(monster.get_image(), (background_x + monster.get_x(), monster.get_y()))
is_player_on_ground = False
for i in range(int(player.vy * DELTA_T+0.5)):
if player.get_bottom_y() + i == FLOOR_Y:
player.y += i
is_player_on_ground = True
if is_player_on_block or is_player_on_ground:
player.set_is_mid_air(False)
else:
player.set_is_mid_air(True)
player.fall()
player.check_jump()
player_image = player.get_image().convert()
player_image.set_colorkey(PINK)
SCREEN.blit(player_image, (player.x + background_x, player.y))
pygame.display.flip()
pygame.quit()
if __name__ == '__main__':
main()
关于Python pygame如何设置FPS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59227239/
我有一个计数器可以计算每一帧。我想做的是将其除以时间以确定我的程序的 FPS。但是我不确定如何在 python 中对计时函数执行操作。 我试过将时间初始化为 fps_time = time.time
我发布了我的 original question here .试过suggested solution .但这并不能解决我的问题。 这就是我所做的。下载 this video来自 Youtube 作为
JavaFX UI 线程上限为每秒 60 次更新(1、2)似乎是一种共识。据我了解,更新意味着 pulse。 A pulse is an event that indicates to the Jav
在处理来自相机的帧时,我正在尝试测量每秒帧数。计算没什么特别的,可以在这个问题中找到:How to write function with parameter which type is deduce
我在 Xcode 6.1.1 中使用 OpenGL ES 3.0 开发了一款针对 iPad Air 的游戏。当我捕获 OpenGL ES 帧时,FPS 数字和着色器程序时间始终显示为 0。 我在项目方
我正在尝试通过 ffmpeg 对视频进行编码在 Linux 系统中。原始视频有 60 FPS,我需要将其更改为 25,但是当我这样做时,视频比原始视频慢。 当我将其更改为 30 时,一切都很好(我想编
我正在尝试将视频从 25 fps 加速到 60 fps。我想要完全相同的帧数,只是更快地呈现给我,并且每秒可以让我获得 60 帧。 ffmpeg -i Spider.mov -r 62500/1000
我们如何才能以更高的帧速率(例如 500 - 800 FPS)运行 OpenGL 应用程序(例如游戏)? 例如,AOE 2 的运行速度超过 700 FPS(我知道它与 DirectX 有关)。尽管我只
为了高性能的科学目的,我们需要渲染视频并在设备上以 60fps 的速度播放。我假设 H.264 视频的通常帧率低于该值。 这是可能的,还是帧率是固定的?如果是这样,在设备上全屏播放 H.264 视频时
拥有 50 fps 的 5 秒视频 想要在 10 秒内将其转换为 25 fps 的视频,而且一切都变慢了,即使是音频 是否可以使用 ffmpeg 最佳答案 利用 ffmpeg -i input.mp4
我有下面的代码(移植到 JOGL 2.0 的 Nehe 教程 1 的基本版本)请求一个以 30 FPS 为动画的 FPSAnimator。当我运行代码时,它会打印 21.321962 或 21.413
我在下面有一些非常简单的性能测试代码,用于在 2011 年末的 Macbook Pro 上使用 OpenCV 3.1 + Python3 测量我的网络摄像头的 FPS: cap = cv2.Video
我正在开发 ARKit 应用以及 Vision/AVKit 框架。我正在使用 MLModel 对我的手势进行分类。我的应用程序可以识别Victory、Okey 和¡No pasarán! 手势来控制视
我从其他 SO 问题中使用了这个命令: $ ffmpeg -i obraz%04d.png -framerate 1 -c:v libx265 output.mkv 我告诉它最多 1 FPS,但日志和
我错误地在 iPhone SE (2) 上录制了慢动作视频,而不是延时摄影。 我知道这里有很多关于这个问题的答案,但我一次又一次地尝试并且总是出现问题(比如一个视频的总帧数正确,但持续了 3 个小时并
任何人都可以帮助我默认情况下以 240 fps 或 120 fps 录制视频,使用 AVCapture session 录制 session 需要 30 fps。 用这个库录制视频 https://g
我目前正在用 Java 制作 3D 游戏。我的问题是当我通过 Eclipse 运行它时,我得到了大约 40 fps,这很好。虽然当我在导出的 jar 文件中运行它时,我得到了 18 fps? 我不太确
自从我在 C++ 项目中从 OpenCV 3.x 更改为 4.x(从源代码编译)以来,我遇到了一些麻烦。我在一个小例子中复制了这个行为,这个例子只打开了一个网络摄像头并记录了 5 秒钟。 使用 3.x
我通过 VLC 录制了一个 RTSP 流(4K)大约一个小时,发生了一些奇怪的事情。 文件大小为 6.6 GB,但视频长度只有 12 分钟。 当我在 VLC 上播放时,进度条到达末尾,但视频仍在连续播
我正在尝试运行此命令。 ffmpeg -i out_frames/frame%08d.jpg -i input.mp4 -map 0:v:0 -map 1:a:0 -c:a copy -c:v lib
我是一名优秀的程序员,十分优秀!