Pygame:每隔x秒重复一次某个动作

3

我是一名Python初学者,正在学习使用Pygame构建简单游戏,在游戏中玩家(猴子)试图从屏幕顶部接住尽可能多的香蕉。

我的问题是如何让香蕉在每个x秒内单独生成并下落。不管是它们同时产生,还是如果我使用time.sleep,会暂停香蕉在空中。甚至在彻底迷失后使用了线程。

我的代码中相关组件如下:

catch_game

import sys

import pygame
from pygame.sprite import Group

from settings import Settings
# from background import Background
from monkey import Monkey
from banana import Banana

import functions

def run_game():
    pygame.init()
    settings = Settings()
    screen = pygame.display.set_mode((settings.screen_width, settings.screen_height))
    pygame.display.set_caption('Monkey Catch')

    monkey = Monkey(screen, settings)
    # background = Background((0, 0), screen)
    bananas = Group()

    functions.create_banana(screen, settings, bananas)

    while True:
        monkey.movement()
        functions.check_events(monkey)
        functions.update_screen(screen, settings, monkey, bananas)
        functions.update_banana(monkey, bananas)





run_game()

香蕉

import pygame
from pygame.sprite import Sprite
from random import randint


class Banana(Sprite):
    def __init__(self, screen, settings):
        super(Banana, self).__init__()
        self.screen = screen
        self.settings = settings


        self.image = pygame.image.load('E:\PycharmProjects\catch\images/banana.png')
        self.rect = self.image.get_rect()
        self.screen_rect = self.screen.get_rect()

        self.y = self.screen_rect.top
        self.y = float(self.rect.y)

        self.x = randint(0, 1150)

        self.speed = settings.banana_fallspeed

    def update(self):
        '''Banana falls down'''
        self.y += self.settings.banana_fallspeed

        self.rect.y = self.y
        self.rect.x = self.x

    def blit(self):
        self.screen.blit(self.image, self.rect)

函数

import pygame
import sys
from banana import Banana
import threading
import time


def update_screen(screen, settings, monkey, bananas):
    screen.fill([255, 255, 255])
    # background.blit()
    monkey.blit()

    for banana in bananas:
        banana.update()
        bananas.draw(screen)

    pygame.display.flip()


def keydown_events(event, monkey):
    if event.key == pygame.K_RIGHT:
        monkey.moving_right = True
    if event.key == pygame.K_LEFT:
        monkey.moving_left = True


def keyup_events(event, monkey):
    if event.key == pygame.K_RIGHT:
        monkey.moving_right = False
    if event.key == pygame.K_LEFT:
        monkey.moving_left = False


def check_events(monkey):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN:
            keydown_events(event, monkey)
        if event.type == pygame.KEYUP:
            keyup_events(event, monkey)


def create_banana(screen, settings, bananas):
        banana = Banana(screen, settings)
        bananas.add(banana)


def update_banana(monkey, bananas):
    '''kill bananas, collisions with monkey'''
    for banana in bananas.copy():
        if banana.rect.bottom >= 720:
            bananas.remove(banana)
    collision = pygame.sprite.spritecollide(monkey, bananas, True)
    if collision:
        bananas.remove(banana)


        # time.sleep(2)
        # fall_interval = banana.threading.Timer(3, create_banana(screen, settings, bananas))
        # fall_interval.start()




2个回答

2

我建议使用计时器事件。使用pygame.time.set_timer()重复创建一个USEREVENT。例如:

banana_delay = 500 # 0.5 seconds
banana_event = pygame.USEREVENT + 1
pygame.time.set_timer(banana_event, banana_delay)

注意,在pygame中可以定义自定义事件。每个事件都需要一个唯一的ID。用户事件的ID必须在pygame.USEREVENT(24)和pygame.NUMEVENTS(32)之间。在本例中,pygame.USEREVENT+1是定时器事件的事件ID,用于生成子弹。
在事件循环中发生事件时,创建一个新的香蕉:
def check_events(screen, settings, bananas, monkey):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        # [...]

        if event.type == banana_event:
            create_banana(screen, settings, bananas)

计时器事件可以通过将时间参数设为0来停止。
如果您想按随机时间生成香蕉,则必须随机更改时间间隔(以毫秒为单位)。使用random.randint(a, b)生成随机时间:
if event.type == banana_event:
    create_banana(screen, settings, bananas)
    banana_delay = random.randint(500, 3000) # random from 0.5 to 3 seconds
    pygame.time.set_timer(banana_event, banana_delay)

谢谢您提供的绝妙建议!我已经成功将计时器添加到check_events中,它运行得非常完美。此外,今天早些时候我正好正在研究这个定时器事件,我对USEREVENT是一个数字值感到困惑,具体在NOEVENT(0)和NUMEVENTS(32)之间。您能否详细解释一下这个概念?先谢谢了。 - ngong123
@ngong123 请查看pygame.event。每个事件类型都与一个唯一的ID相关联,范围从NOEVENT(0)到NUMEVENTS(32)。事件ID范围从USEREVENT(24)到NUMEVENTS(32)保留给“用户”,可以由计时器使用(参见pygame.time.set_timer())。 - Rabbid76
我明白了。所以我相信人们可以创建自己的事件类型USEREVENT + 0...直到USEREVENT +8,因为NUMEVENTS(32)是上限。谢谢你帮我理解这个概念。 - ngong123

0

您可以使用协程来同时运行函数,使用asyncio。例如:

import asyncio
import time

async def main():
    task1 = asyncio.create_task(
        say_after(1, 'hello'))

    task2 = asyncio.create_task(
        say_after(2, 'world'))

    print(f"started at {time.strftime('%X')}")

    # Wait until both tasks are completed (should take
    # around 2 seconds.)
    await task1
    await task2

    print(f"finished at {time.strftime('%X')}")

如果你为每个香蕉创建一个新任务,你应该能够在不同的时间将它们显示在屏幕上。
来源:https://docs.python.org/3/library/asyncio-task.html

1
请尊重问题标记为pygame - Rabbid76
感谢建议!虽然比较难以理解,但我会研究协程作为一种技术。 - ngong123

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接