Home > Software engineering >  How can I add a delay between keyboard button presses?
How can I add a delay between keyboard button presses?

Time:01-13

I'm trying to add a "shoot" function to my game, where the player -a drone- would shoot a bullet upon pressing the space bar on the keyboard.

I've done that successfully but I also want the function to be on delay after executing it once. For example the player could press spacebar once then have to wait 2-3 seconds before being able to execute the function again. Hence my question, how could I make that work?

This is the current functional code.

main.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()

I tried importing the time library and adding a time.sleep() function in the function in controls.py, but that froze the entire program.

import time

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

Any help would be appreciated! Thanks in advance!

CodePudding user response:

Try this:

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

Basically, it checks whether the time between the last shot and now is greater or equal to the cooldown, then records the time of the last shot.

time.time() doesn't sleep, so it doesn't stop your program. This makes sure that your program keeps running, even when waiting for the cooldown to finish.

CodePudding user response:

The best choice for async events in kivy is to use asyncio. First at all you have to be sure your app runs from asyncio.run() instead of App.run(). To do this, you have to import asyncio and also you have to add a method to your App class. See the example below:

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

The code above will make your kivyApp to run as a "Task" (a task it's something that's gonna be concurrently executed). A task or coroutine can call another task within itself, so you can have another async task running during the execution of your kivyApp.

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

Finally you just have to call that async function as a task, to do that from your shoot function:

def shoot(self):
    # This is how you call the async func
    task = asyncio.create_task(delayWithoutFreeze(), name='shootTask')  

For more info about coroutines and tasks: https://docs.python.org/3/library/asyncio-task.html

  •  Tags:  
  • Related