Python 海龟模块:Onkeypress 仅在 if 语句已满时在循环中可用

问题描述 投票:0回答:1

我正在尝试改进“过马路”风格的游戏(在 Angela Yu 的 Python 课程范围内),其中某些玩家操作只能执行有限次数。

我想要实现的第一个是“Nitro”,这是一种在使用时消耗的瞬时速度提升。玩家开始时拥有 0 硝基,每获得 2 分就获得 1 硝基。

首先,以下代码提供了所需的结果,在接收第一个硝基单位之前按空格键不会执行任何操作。一旦硝基达到 1,if 语句就不会再关闭,并且玩家可以使用硝基任意次数。移除硝基功能正常工作,每次使用都会移除一个单位的硝基,导致内置硝基指示器显示负数。

我尝试在循环中放置一个打印函数,它的行为与预期一致(只有当硝基达到 1 时才开始打印,当它下降到更低时再次停止)。

为什么 onkeypress 函数的行为不同?

while game_is_on:
screen.update()
time.sleep(.025)
screen.onkeypress(fun=player.move, key='Up')
if scoreboard.nitro >= 1:
    screen.onkeypress(fun=player.nitro, key='space')
    screen.onkeyrelease(fun=scoreboard.remove_nitro, key='space')
car_manager.drive()

提前致谢

python loops python-turtle onkeypress
1个回答
0
投票

我不确定你的完整游戏上下文是什么样的,但正如Jason提到的,键处理程序通常应该在游戏循环之前注册一次。

此外,只有更新循环应该处理当前按下的键触发的操作。处理程序纯粹用于跟踪在给定时间按下了哪些键。

最后,动作函数是游戏逻辑所在。这些可以使用计时器来确定“硝基”持续多长时间,或者玩家在给定帧上移动多远。

这是一个一般概念证明,是对 这个实时海龟样板 的修改,您可以根据您的特定用例进行调整。为了举例,我假设每 6 秒免费提供一次硝基,并将玩家的速度加倍,持续 4 秒。如果硝基在您的特定应用中是可收集的,那么基本要点仍然是相同的。我想避免涉及多个实体和碰撞检测,这与我的要点相切。

import turtle
from time import perf_counter

def tick():
    global last_nitro_given
    global last_nitro_activated
    global nitros
    t.clear()

    if perf_counter() - last_nitro_given > nitro_given_interval:
        last_nitro_given = perf_counter()
        nitros += 1

    nitro_active = perf_counter() - last_nitro_activated < nitro_duration
    if nitro_active:
        t.write(f"nitros: {nitros} [NITRO ACTIVE!]", font=("Arial", 16))
    else:
        t.write(f"nitros: {nitros}", font=("Arial", 16))

    for action in keys_pressed:
        actions[action]()

    turtle.update()
    win.ontimer(tick, frame_delay_ms)


def use_nitro():
    global nitros
    global last_nitro_activated

    nitro_active = perf_counter() - last_nitro_activated < nitro_duration
    if nitros > 0 and not nitro_active:
        nitros -= 1
        last_nitro_activated = perf_counter()


t = turtle.Turtle()
t.shapesize(2, 2, 2)
turtle.tracer(0)
frame_delay_ms = 1000 // 30
step_speed = 10
nitro_duration = 3
nitro_given_interval = 5
nitros = 0
last_nitro_given = perf_counter()
last_nitro_activated = 0

actions = dict(
    Left=lambda: t.left(step_speed),
    Right=lambda: t.right(step_speed),
    Up=lambda: t.forward(
        step_speed * 2
        if perf_counter() - last_nitro_activated < nitro_duration
        else step_speed
    ),
    space=use_nitro,
)
win = turtle.Screen()
keys_pressed = set()

def bind(key):
    win.onkeypress(lambda: keys_pressed.add(key), key)
    win.onkeyrelease(lambda: keys_pressed.remove(key), key)

for key in actions:
    bind(key)

win.listen()
tick()
win.exitonclick()

请注意,

global
是糟糕的设计,仅在此处使用以保持示例的合理范围。在较大的应用程序中,使用某种闭包(例如类或函数)来避免全局变量。

© www.soinside.com 2019 - 2024. All rights reserved.