【发布时间】:2021-10-06 16:48:42
【问题描述】:
我需要我的游戏能够在屏幕上处理数百发子弹。虽然游戏似乎并没有因为子弹数量较少(大约 50 颗左右)而没有大幅减速,但它确实有它们,当屏幕上同时出现大约 100-200 颗子弹时问题变得更加明显。这引起了我特别担心的一个问题:我希望敌人也发射大量子弹,但如果玩家的射弹已经导致这样的减速,那么这是不可能的。
在我开始展示相关代码之前:
- 我正在使用 pygame 2.0.1(SDL 2.0.14,Python 3.9.6)
- 我在加载的每张图片上都使用 convert_alpha()
- 我为玩家、子弹、敌人和 HUD 类使用脏精灵,并使用 pygame.sprite.LayeredDirty() 组来存储当前游戏中的所有精灵;敌人、子弹和 HUD 有额外的 pygame.sprite.Group() 用于碰撞检测(用于敌人和子弹)和重新排序精灵以在所有内容之上渲染(用于 HUD)。这似乎提高了性能,但大量子弹仍然会导致减速
- 我使用 PyCharm 作为我的 IDE
我对编程很陌生,我不太确定究竟是什么导致了这个问题,所以我会尽量提供尽可能多的相关代码。如果没有一个罪魁祸首似乎是问题的原因,我会提供更多。如果信息不足,我提前道歉。
减速变得很荒谬,主要是因为我正在使用调试超级武器,尽管当我打开许多应用程序时,即使产生的子弹数量几乎没有(28 颗或更多),它有时也很明显。到目前为止,这是一个非常小的游戏,所以我不完全明白为什么。
def init_player_weapon_level(self):
# debug mode
if self.lev_weapon == -1:
self.set_weapon_values(100, 5, 100, True)
self.firing_pattern = [[self.bullet_images["blue"], 0, 0, 90, -24],
[self.bullet_images["blue"], 0, 0, 92, -24],
[self.bullet_images["blue"], 0, 0, 88, -24],
...]
...
下面使用此函数中定义的触发模式列表。它很长。此列表根据玩家的武器等级替换,-1 为最高。该函数仅在创建播放器对象或通过按键手动启动时调用。
def fire(self, now):
if self.check_firing_conditions(now):
self.last_shot = now
for o in self.firing_pattern:
bullet = PlayerBullet01(o[0], self.rect.centerx + o[1], self.rect.top + o[2], o[3], o[4])
all_sprites.add(bullet)
bullets.add(bullet)
self.generate_heat(now)
这是负责发射武器的函数。它创建与self.firing_pattern 中的参数列表一样多的子弹对象,具有图像 [0]、X [1] 和 Y [2] 生成偏移量(然后从玩家的位置添加或减去这些偏移量以产生错觉它们是从船上的大炮发射的),子弹发射的角度 [3](90 度是直线向上)和它穿过的速度 [4](它在发射模式中是负数,因为子弹向上移动) .
因为self.firing_pattern 有 35 个参数列表(我省略了,因为这会占用空间),所以一次创建了 35 个子弹,如果玩家按下开火键,则在两次射击之间有 100 毫秒的延迟发射。这使得在玩家的武器过热之前屏幕上会出现 245 颗子弹,从而导致武器停止射击。很多,但速度变慢似乎是由于屏幕上已经有一些子弹造成的。
class PlayerBullet01(pygame.sprite.DirtySprite):
def __init__(self, image, x, y, deg, speed):
pygame.sprite.DirtySprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.center = self.rect.center
self.position = pygame.math.Vector2(x, y)
self.speed_mod = 0.065
# deg - 90 because we don't want to rotate the image
# by the amount of degrees it's supposed to face,
# we want to rotate it by a much smaller amount
# we also want to rotate it only once
# since player bullets probably shouldn't follow
# any other movement patterns than going straight to the target
if deg != 0:
self.image = pygame.transform.rotate(self.image, -deg + 90)
self.rect = self.image.get_rect()
self.rect.center = self.center
# we only want the bullet to move in a particular direction at a particular speed
self.direction = pygame.math.Vector2(0, 0)
self.direction += self.move(deg, speed)
# spawn bullet at the center of the spaceship
self.rect.centerx = self.position.x
self.rect.bottom = self.position.y
def update(self):
self.dirty = 1
self.position.x += self.direction.x * self.speed_mod * x_clock.delay
self.position.y += self.direction.y * self.speed_mod * x_clock.delay
self.rect.center = (self.position.x, self.position.y)
# die if out of bounds
if self.rect.bottom < 0:
self.kill()
def move(self, degrees, offset):
rads = math.radians(degrees)
x = math.cos(rads) * offset
y = math.sin(rads) * offset
return x, y
这是子弹类。一开始我以为每次更新都会调用move 函数会减慢游戏速度(这是在早期版本的代码中,此处未显示),但实际上并没有改变。
hits_enemy = pygame.sprite.groupcollide(enemies, bullets, True, True)
for hit in hits_enemy:
create_generic_enemy(GFX_ENEMY)
最后,这是检查子弹和敌人(屏幕上总是只有 10 个)之间碰撞的行。我禁用了子弹和敌人的碰撞,但它似乎仍然没有提高游戏的性能。
dirtyupdate = all_sprites.draw(screen)
pygame.display.update(dirtyupdate)
哦,这就是游戏在主游戏循环中在屏幕上绘制所有内容的方式。
最后一个可能的罪魁祸首: 我在 Stack Overflow 上找到了一种方法来阻止 pygame 出现微卡顿。这是一个非常烦人的问题,似乎无缘无故发生。它需要使用自定义时钟。我从这里将这段代码引入我的游戏:Simple Pygame animation stuttering
previous = time.time() * 1000
# this is so it's easy to get out of the game loop
# (you just set GAME_RUNNING to false)
GAME_RUNNING = True
while GAME_RUNNING:
# CLOCK
# a pretty advanced clock that stops pygame from stuttering like a -----
current = time.time() * 1000
elapsed = current - previous
previous = current
x_clock.delay = 1000.0 / MAX_FPS - elapsed
x_clock.delay = max(int(x_clock.delay), 0)
...
# delays the game by delay
# using pygame.time.wait() instead of pygame.time.delay()
# because pygame.time.delay() makes my system fan go -------
pygame.time.wait(x_clock.delay)
为了记录,x_clock 文件中的delay 也被导入到类文件中。这是因为这些类需要将它们的移动调整为 FPS 下降。我不相信这段代码是导致延迟的原因,但我记得当我使用 pygame.time.delay() 而不是 wait() 时,我的粉丝疯了。
是什么导致了这种减速,我该如何解决?我已经考虑了一些可能性(其中一个可能是 Pygame 无法处理这么多弹丸),但我已经看到了一款游戏,它在屏幕上始终如一地创建了类似数量的子弹并且它没有任何减速.看了那个游戏的代码我也想不通。
【问题讨论】: