【问题标题】:How can I add a delay between keyboard button presses?如何在键盘按钮按下之间添加延迟?
【发布时间】:2022-01-12 06:54:03
【问题描述】:

我正在尝试在我的游戏中添加“射击”功能,玩家(无人机)会在按下键盘上的空格键时发射子弹。

我已经成功地做到了,但我也希望函数在执行一次后延迟。例如,玩家可以按一次空格键,然后必须等待 2-3 秒才能再次执行该功能。因此我的问题是,我怎样才能使它起作用?

这是当前的功能代码。

ma​​in.py

    def shoot(self):
        self.get_drone_coordinates()

        x = self.drone_coordinates[0][0]
        y = self.drone_coordinates[0][1] - 20

        self.drone_bullet = Image(source="images/drone_bullet.png",
                                  pos=(x, y))

        self.add_widget(self.drone_bullet)
        self.bullets.append(self.drone_bullet)

controls.py

def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
    elif keycode[1] == 'spacebar':
        self.shoot()

我尝试导入时间库并在controls.py中的函数中添加一个time.sleep()函数,但这冻结了整个程序。

import time

def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
    elif keycode[1] == 'spacebar':
        self.shoot()
        time.sleep(3)

任何帮助将不胜感激!提前致谢!

【问题讨论】:

  • 使用Clock.schedule_once 有帮助吗?

标签: python python-3.x kivy


【解决方案1】:

kivy 中异步事件的最佳选择是使用asyncio。首先,您必须确保您的应用程序从asyncio.run() 而不是App.run() 运行。为此,您必须导入 asyncio 并且您必须向您的 App 类添加一个方法。请看下面的例子:

import asyncio

######## MAIN APP ######## 
class ExampleApp(App):
    def build(self):
        #Your  app stuff here

    async def kivyCoro(self):  #This is the method that's gonna launch your kivy app
        await self.async_run(async_lib='asyncio')
        print('Kivy async app finished...')

    # This func will start all the "tasks", in this case the only task is the kivy app
    async def base(self):
        (done, pending) = await asyncio.wait({self.kivyCoro()}, 
    return_when='FIRST_COMPLETED')

if __name__ == '__main__':
    instanceApp = ExampleApp() #You have to instanciate your App class
    asyncio.run(instanciaApp.base()) # Run in async mode

上面的代码将使您的 kivyApp 作为“任务”运行(这是一个将同时执行的任务)。一个任务或协程可以在自身内部调用另一个任务,因此您可以在执行 kivyApp 期间运行另一个异步任务。

# Here you create a coroutine (global scope)
async def delayWithoutFreeze():
    print('Wait 3 segs...')
    await asyncio.sleep(3)
    print('3 segs elapsed...')

最后,您只需将该异步函数作为任务调用,即可从您的 _on_keyboard_down 函数中执行此操作:

def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
    j = 0 #This is a counter to know if a delay task is running
    elif keycode[1] == 'spacebar':
        for task in asyncio.all_tasks(): #This loop checks if there's a delay already running
            if task.get_name()=='shootTask':
                j+=1
                print('Theres already {} shootTask'.format(j))
        if j==0: #If j == 0 means that no delay is running so you can press and action again
            # This is how you call the async func
            asyncio.create_task(delayWithoutFreeze(), name='shootTask') 
            self.shoot()
        

注意:我知道为什么你在 _on_keyboard_down 中使用 elif 而不是 if。您只有 1 个条件。不需要elif

有关协程和任务的更多信息: https://docs.python.org/3/library/asyncio-task.html

【讨论】:

  • 不幸的是,这不起作用。它不会将拍摄功能置于延迟上,而是将其后的功能置于 delayWithhoutFreeze 函数中。
  • 你是对的,但这就是让它工作所需的一切。你必须把你的射击动作放在 delayWithhoutFreeze 函数中,所以每次你调用 _on_keyboard_down 它都会调用射击函数......你只需要验证它是否已经运行(以避免同时创建超过 1 个任务)。我遇到了同样的问题,我就是这样解决的
  • 我可以帮助你,但首先让我知道当你从你的拍摄功能中调用“delayWithoutFreeze”时,程序会打印“Wait 3 segs...”并在 3 segs 后打印“3 segs”已过...'...如果可行,则表示一切正常,我可以指导您进行进一步的步骤
  • 我已经修改了答案中的代码。看它。您必须在函数“_on_keyboard_down”中添加延迟。这应该可以,如果您有任何问题,请告诉我
  • 太完美了!谢谢,只是为了澄清我使用 elif 的原因是因为更多控制涉及更多条件,我已将 WASD 连接到所述无人机的运动
【解决方案2】:

试试这个:

import time
def _on_keyboard_down(self, keyboard, keycode, text, modifiers,cooldown==3):
  elif keycode[1] == 'spacebar':
      try:
            LastShot
      except:
            LastShot=0
      if time.time()-LastShot>=cooldown:
            self.shoot()
            LastShot=time.time()

基本上,它检查最后一次射击和现在之间的时间是否大于或等于冷却时间,然后记录最后一次射击的时间。

time.time() 不会休眠,因此它不会停止您的程序。这可确保您的程序继续运行,即使在等待冷却结束时也是如此。

【讨论】:

  • 使用 time.sleep() 会冻结程序
  • @EdherCarbajal 拍摄,忘记编辑了。感谢您指出这一点!
  • 我建议在elif-block 中捕获time.time()-LastShot<cooldown inside 的情况。 (所以我建议嵌套if。)否则程序将处理所有其他elif 请求,尽管'spacebar' 不再有问题。
  • 这并不完全有效。我得到一个 UnboundLocalError 因为变量 LastShot 显然超出了赋值范围。
  • @Pyro 现在应该没问题了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-18
  • 2012-04-22
  • 1970-01-01
相关资源
最近更新 更多