在 Pygame 中每隔几秒移动一个对象

Posted

技术标签:

【中文标题】在 Pygame 中每隔几秒移动一个对象【英文标题】:Move an object every few seconds in Pygame 【发布时间】:2014-06-15 15:31:43 【问题描述】:

我正在使用 pygame 制作街机游戏,我试图让精灵每隔几秒改变一次位置。

我尝试使用 time.sleep(1) 并将帧速率更改为 .5 (clock.tick(.5))。

两者都在时间间隔过后才使对象改变位置,但是它们也使精灵以相同的速度跟随我的鼠标更新坐标。

我一直在研究,似乎找不到另一种方法来使精灵移动,而不会使我的程序每次运行时刷新速度变慢或“休眠”。

【问题讨论】:

您可以跳过精灵的更新,也可以跳过(在精灵内)。跳过 5 次后,移动精灵并重置该计数器。但我认为真正(游戏)基于时间的方法会更好。 【参考方案1】:

您可以将Eventpygame.time.set_timer() 一起使用:

pygame.time.set_timer()在事件队列中重复创建一个事件set_timer(eventid, milliseconds) -> None

将事件类型设置为每隔给定的毫秒数出现在事件队列中


这是一个简单而完整的示例。请注意敌人如何每 1000 毫秒向侧面移动,每 3500 毫秒向下移动一次,并且您可以每 450 毫秒射击一次(全部使用事件)。


import pygame

# you'll be able to shoot every 450ms
RELOAD_SPEED = 450

# the foes move every 1000ms sideways and every 3500ms down
MOVE_SIDE = 1000
MOVE_DOWN = 3500

screen = pygame.display.set_mode((300, 200))
clock = pygame.time.Clock()

pygame.display.set_caption("Micro Invader")

# create a bunch of events 
move_side_event = pygame.USEREVENT + 1
move_down_event = pygame.USEREVENT + 2
reloaded_event  = pygame.USEREVENT + 3

move_left, reloaded = True, True

invaders, colors, shots = [], [] ,[]
for x in range(15, 300, 15):
    for y in range(10, 100, 15):
        invaders.append(pygame.Rect(x, y, 7, 7))
        colors.append(((x * 0.7) % 256, (y * 2.4) % 256))

# set timer for the movement events
pygame.time.set_timer(move_side_event, MOVE_SIDE)
pygame.time.set_timer(move_down_event, MOVE_DOWN)

player = pygame.Rect(150, 180, 10, 7)

while True:
    clock.tick(40)
    if pygame.event.get(pygame.QUIT): break
    for e in pygame.event.get():
        if e.type == move_side_event:
            for invader in invaders:
                invader.move_ip((-10 if move_left else 10, 0))
            move_left = not move_left
        elif e.type == move_down_event:
            for invader in invaders:
                invader.move_ip(0, 10)
        elif e.type == reloaded_event:
            # when the reload timer runs out, reset it
            reloaded = True
            pygame.time.set_timer(reloaded_event, 0)

    for shot in shots[:]:
        shot.move_ip((0, -4))
        if not screen.get_rect().contains(shot):
            shots.remove(shot)
        else:
            hit = False
            for invader in invaders[:]:
                if invader.colliderect(shot):
                    hit = True
                    i = invaders.index(invader)
                    del colors[i]
                    del invaders[i]
            if hit:
                shots.remove(shot)

    pressed = pygame.key.get_pressed()
    if pressed[pygame.K_LEFT]: player.move_ip((-4, 0))
    if pressed[pygame.K_RIGHT]: player.move_ip((4, 0))

    if pressed[pygame.K_SPACE]: 
        if reloaded:
            shots.append(player.copy())
            reloaded = False
            # when shooting, create a timeout of RELOAD_SPEED
            pygame.time.set_timer(reloaded_event, RELOAD_SPEED)

    player.clamp_ip(screen.get_rect())

    screen.fill((0, 0, 0))

    for invader, (a, b) in zip(invaders, colors): 
        pygame.draw.rect(screen, (150, a, b), invader)

    for shot in shots: 
        pygame.draw.rect(screen, (255, 180, 0), shot)

    pygame.draw.rect(screen, (180, 180, 180), player)    
    pygame.display.flip()

【讨论】:

我理解除了player.clamp_ip(screen.get_rect())这行之外的所有这些——你能解释一下吗,或者有没有很好的解释为什么要使用它? @marienbad 如果 Rect 播放器在屏幕的 Rect 之外(例如 x 坐标为负或 x 坐标 + 宽度大于屏幕宽度),clamp 函数将“移动它”回来”,所以它在屏幕内。 Rect 类的大多数函数将返回一个新的 Rect,但它们有一个 _ip(就地)版本,它将改变原始 Rect。所以这条线基本上只是确保玩家不能移动到屏幕之外。 谢谢,我明白了! @marienbad 我知道这是一个老问题,但我仍然感兴趣。你能解释一下for循环吗?基本上这行for x in range(15, 300, 15): 内的所有内容。为什么 range 函数中有 3 个值,它们的作用是什么? for x in range(15, 300, 15) 以 15 为步长从 15 循环到 300,例如 15、30、45、60、75、90 等。【参考方案2】:

怎么样

var = 0

while True:
    event_handling()

    game_logic()

    if var == 5:
        sprite.update.position()
        var = 0

    pygame.display.flip()
    var += 1

显然,这只是伪代码,但你明白了。

【讨论】:

忘了说,我也试过了。它使它以良好的时间间隔发生变化,但它只显示精灵一瞬间。 这是有道理的。使用此代码,它会显示一次,当它以 60 fps 的速率达到 60 时(因为我以 60 fps 的速度运行,所以鼠标精灵以适当的速度移动)。 好的,那么您需要在每个循环结束时对精灵进行 blit,但仅在 var == 5. 或 60 或您最终使用的任何数字时更新位置。

以上是关于在 Pygame 中每隔几秒移动一个对象的主要内容,如果未能解决你的问题,请参考以下文章

相机跟随刚体抖动每隔几秒与背景对象

SpriteKit - 创建随机对象并使用 deltatime 移动它们

在 jupyter 中 [每隔几秒] 更新 plotly 图形

WebSocket 消息每隔几秒就会断断续续

Android:FusedLocationProvider,每隔几秒获取一次位置

位置值每隔几秒更改一次 - navigator.geolocation.getCurrentPosition