如何在 pygame 中创建冷却功能?

How to create a cooldown function in pygame?

我正在制作一个游戏,我希望角色只能每 0.4 秒左右射击一次。目前,该角色可以发射子弹,看起来像一条长长的子弹从角色中射出。我怎样才能让角色等到下一颗子弹出来。

我认为这适用于 pygame.time.get_clicks(),但我真的不知道如何。

我试过这样做但是没有子弹出来。我怎样才能让它发挥作用?

def fire():
    last = pygame.time.get_ticks()
    cooldown = 300
    for bullet in bullets:
        if bullet.y < 500 and bullet.y > 0:
            bullet.y -= bullet.vel
        else:
            bullets.pop(bullets.index(bullet))
    if keys[pygame.K_SPACE]:
        now = pygame.time.get_ticks()
        if now - last >= cooldown:
            bullets.append(projectile((man.x + man.width // 2), (man.y - 7), 7, 3, (255, 0, 0)))

如果有人需要的话,这里是完整的代码(我把它变成了一个矩形而不是图片精灵,所以任何人都可以尝试。


pygame.init()

win = pygame.display.set_mode((500, 500))

class player():
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.vel = 4
        self.left = False
        self.right = False

    def draw(self, win):
        pygame.draw.rect(win, (0, 200, 0), (man.x, man.y, man.height, man.width))
        if self.left:
            pygame.draw.rect(win, (0, 200, 0), (man.x, man.y, man.height, man.width))
        elif self.right:
            pygame.draw.rect(win, (0, 200, 0), (man.x, man.y, man.height, man.width))

class projectile():
    def __init__(self, x, y, width, height, color):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color
        self.vel = 7

    def draw(self, win):
        pygame.draw.rect(win, self.color, (self.x, self.y, self.height, self. width))


def move():
    if keys[pygame.K_LEFT] and man.x > man.vel:
        man.x -= man.vel
        man.left = True
        man.right = False

    elif keys[pygame.K_RIGHT] and man.x < 500 - man.width - man.vel:
        man.x += man.vel
        man.left = False
        man.right = True


def fire():
    last = pygame.time.get_ticks() # remove this if you want to try it working
    cooldown = 400 # remove this if you want to try it working
    for bullet in bullets:
        if bullet.y < 500 and bullet.y > 0:
            bullet.y -= bullet.vel
        else:
            bullets.pop(bullets.index(bullet))
    if keys[pygame.K_SPACE]:
        now = pygame.time.get_ticks() # remove this if you want to try it working
        if now - last >= cooldown: # remove this if you want to try it working
            bullets.append(projectile((man.x + man.width // 2), (man.y - 7), 7, 3, (255, 0, 0)))


def re_draw():
    win.fill((0, 0, 0))
    man.draw(win)
    for bullet in bullets:
        bullet.draw(win)
    pygame.display.update()


man = player(400, 400, 64, 64)
bullets = []
run = True
shoot_loop = 0
clock = pygame.time.Clock()


while run:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    keys = pygame.key.get_pressed()
    fire()
    move()
    clock.tick(60)
    re_draw()

pygame.quit()

我认为这个问题是你每次都设置 last,即使发射不成功。移动线

last = pygame.time.get_ticks()

里面

if now - last >= cooldown:

应该可以解决这个问题。这样 last 存储上次成功开火的时间,而不是上次尝试的时间。

正如@gregk 所说,错误是您在 fire 函数中设置了 last = pygame.time.get_ticks(),主循环的每次迭代都会调用该函数。
您是在对程序说最后一次拍摄的时间始终是最后一次迭代的时间,即使没有拍摄。因此 now - last >= cooldown 永远不会为真,因为 last 总是更新到以后的时间。

这个可以有很多方法解决,关键是如何追踪流淌的时间。您不必每次迭代都更新 last

以下是一种接近您当前代码的方法(以避免编辑大量内容)。以这种方式编辑您的 fire() 函数:

def fire():
    global cooldown_tracker
    cooldown_tracker += clock.get_time()
    if cooldown_tracker > 400:
        cooldown_tracker = 0

    for bullet in bullets:
        if bullet.y < 500 and bullet.y > 0:
            bullet.y -= bullet.vel
        else:
            bullets.pop(bullets.index(bullet))

    if keys[pygame.K_SPACE] and cooldown_tracker == 0:
        bullets.append(projectile((man.x + man.width // 2), (man.y - 7), 7, 3, (255, 0, 0)))

并添加

cooldown_tracker = 0

在主循环之前(就在 while run 之前)。
在此解决方案中,我使用的是您已有的 clock 对象,而不是 pygame.time.get_ticks()

我用了一个cooldown_tracker变量,每次迭代(调用fire()函数时)最后一次迭代的时间加入到tracker中,如果这个时间大于400ms , tracker 重置为 0。只有当 tracker 为 0 时,才会将一颗子弹添加到列表中(一枪),这意味着冷却时间已经过去。