我正在尝试改进“过马路”风格的游戏(在 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()
提前致谢
我不确定你的完整游戏上下文是什么样的,但正如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
是糟糕的设计,仅在此处使用以保持示例的合理范围。在较大的应用程序中,使用某种闭包(例如类或函数)来避免全局变量。