在 pygame 中每隔 x (毫秒)秒执行某项操作

2025-02-14 09:49:00
admin
原创
48
摘要:问题描述:我正在学习 Python 和 Pygame,我要做的第一件事是一个简单的贪吃蛇游戏。我试图让蛇每 0.25 秒移动一次。这是我的代码循环部分:while True: check_for_quit() clear_screen() draw_snake() draw...

问题描述:

我正在学习 Python 和 Pygame,我要做的第一件事是一个简单的贪吃蛇游戏。我试图让蛇每 0.25 秒移动一次。这是我的代码循环部分:

while True:
    check_for_quit()

    clear_screen()

    draw_snake()
    draw_food()

    check_for_direction_change()

    move_snake() #How do I make it so that this loop runs at normal speed, but move_snake() only executes once every 0.25 seconds?

    pygame.display.update()

我希望所有其他函数都能正常运行,但 move_snake() 仅每 0.25 秒发生一次。我查了一下,找到了一些答案,但对于第一次编写 Python 脚本的人来说,它们似乎都太复杂了。

是否可以实际获得我的代码应该是什么样子的示例,而不是仅仅告诉我需要使用哪个函数?谢谢!


解决方案 1:

有几种方法,例如跟踪系统时间或使用Clock和计数滴答。

但最简单的方法是使用事件队列并每 x 毫秒创建一个事件,使用pygame.time.set_timer()

pygame.time.set_timer()

在事件队列中重复创建事件

set_timer(eventid, milliseconds) -> None

设置一个事件类型,每隔指定的毫秒数出现在事件队列中。第一个事件直到经过该时间后才会出现。

每种事件类型都可以附加一个单独的计时器。最好使用 pygame.USEREVENT 和 pygame.NUMEVENTS 之间的值。

要禁用事件的计时器,请将毫秒参数设置为 0。

这是一个运行的小示例,其中蛇每 250 毫秒移动一次:

import pygame
pygame.init()
screen = pygame.display.set_mode((300, 300))
player, dir, size = pygame.Rect(100,100,20,20), (0, 0), 20
MOVEEVENT, t, trail = pygame.USEREVENT+1, 250, []
pygame.time.set_timer(MOVEEVENT, t)
while True:
    keys = pygame.key.get_pressed()
    if keys[pygame.K_w]: dir = 0, -1
    if keys[pygame.K_a]: dir = -1, 0
    if keys[pygame.K_s]: dir = 0, 1
    if keys[pygame.K_d]: dir = 1, 0
    
    if pygame.event.get(pygame.QUIT): break
    for e in pygame.event.get():
        if e.type == MOVEEVENT: # is called every 't' milliseconds
            trail.append(player.inflate((-10, -10)))
            trail = trail[-5:]
            player.move_ip(*[v*size for v in dir])
            
    screen.fill((0,120,0))
    for t in trail:
        pygame.draw.rect(screen, (255,0,0), t)
    pygame.draw.rect(screen, (255,0,0), player)
    pygame.display.flip()

在此处输入图片描述


从 pygame 2.0.1 开始,安排事情变得非常容易,因为pygame.time.set_timer现在允许触发一次自定义事件。

这是一个在未来 X 秒内运行一次函数的简单示例:

import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
ACTION = pygame.event.custom_type() # our custom event that contains an action
clock = pygame.time.Clock()


def main():
    shield = 0

    # function to activate the shield
    # note that shield is NOT just a boolean flag,
    # but an integer. Everytime we activate the shield,
    # we increment it by 1. If we want to deactivate the 
    # shield later, we can test if the deactivate event
    # is the latest one. If not, then nothing should happen.
    def activate_shield():
        nonlocal shield
        shield += 1
        return shield

    # function that creates the function that is triggered
    # after some time. It's nested so we can pass and capture
    # the id variable to check if the event is actually the
    # last deactivate event. If so, we reset shield to 0.
    def remove_shield(id):
        def action():
            nonlocal shield
            if shield == id:
                shield = 0
        return action

    while True:
        for e in pygame.event.get():
            if e.type == pygame.QUIT: return
            
            if e.type == pygame.KEYDOWN: 
                # activate the shield
                id = activate_shield()
                # deactivate it 2000ms in the future
                # pygame will post this event into the event queue at the right time
                pygame.time.set_timer(pygame.event.Event(ACTION, action=remove_shield(id)), 2000, 1)
                
            if e.type == ACTION:
                # if there's an ACTION event, invoke its action!!!
                e.action()
                
        screen.fill('black')
          
        # is the shield active?
        if shield:
            pygame.draw.circle(screen, 'red', (320, 220), 35, 4)
            
        # our green little guy
        pygame.draw.rect(screen, 'green', (300, 200, 40, 40))
        pygame.display.flip()
        clock.tick(60)

main()

最小示例:![IT科技](https://i.sstatic.net/5jD0C.png) repl.it@queueseven/Simple-Scheduler

解决方案 2:

使用Pygame 的 Clock 模块来跟踪时间。具体来说,tick该类的方法Clock将向您报告自上次调用以来的毫秒数tick。因此,您可以tick在游戏循环中每次迭代的开始(或结束时)调用一次,并将其返回值存储在名为的变量中dt。然后使用dt来更新与时间相关的游戏状态变量。

time_elapsed_since_last_action = 0
clock = pygame.time.Clock()

while True: # game loop
    # the following method returns the time since its last call in milliseconds
    # it is good practice to store it in a variable called 'dt'
    dt = clock.tick() 

    time_elapsed_since_last_action += dt
    # dt is measured in milliseconds, therefore 250 ms = 0.25 seconds
    if time_elapsed_since_last_action > 250:
        snake.action() # move the snake here
        time_elapsed_since_last_action = 0 # reset it to 0 so you can count again

解决方案 3:

如果你想在 Pygame 中随时间控制某些东西,你有两个选择:

  1. 用于pygame.time.get_ticks()测量时间并实现根据时间控制对象的逻辑。

  2. 使用计时器事件。用于在事件队列中pygame.time.set_timer()重复创建USEREVENT。当事件发生时更改对象状态。

以下问题答案中的示例显示了如何使用它:

  • 在python中同时生成同一对象的多个实例

PYGBAG demo

IT科技

  • 有没有办法让 pygame 中代码的不同部分具有不同的滴答率?

  • 当碰撞发生时如何显示爆炸图像?

PYGBAG demo

IT科技

  • 如何创建一个可视计时器?

IT科技


选项 1 的最小示例:PYGBAG demo

import pygame

pygame.init()
window = pygame.display.set_mode((400, 200))
clock = pygame.time.Clock()
rect = pygame.Rect(0, 80, 20, 20)

time_interval = 500 # 500 milliseconds == 0.5 seconds
next_step_time = 0

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

    current_time = pygame.time.get_ticks()
    if current_time > next_step_time:
        next_step_time += time_interval
        rect.x = (rect.x + 20) % window.get_width()

    window.fill(0)
    pygame.draw.rect(window, (255, 0, 0), rect)
    pygame.display.flip()
    clock.tick(100)

pygame.quit()
exit()

选项 2 的最小示例:PYGBAG demo

import pygame

pygame.init()
window = pygame.display.set_mode((400, 200))
clock = pygame.time.Clock()
rect = pygame.Rect(0, 80, 20, 20)

time_interval = 500 # 500 milliseconds == 0.5 seconds
timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, time_interval) 

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

        if event.type == timer_event:
            rect.x = (rect.x + 20) % window.get_width()

    window.fill(0)
    pygame.draw.rect(window, (255, 0, 0), rect)
    pygame.display.flip()
    clock.tick(100)

pygame.quit()
exit()

IT科技

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用