Issue
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!
Solution
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 _on_keyboard_down
function:
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()
NOTE: Idk why u use elif
instead if
in the _on_keyboard_down
. You only have 1 condition. no elif
needed
For more info about coroutines and tasks: https://docs.python.org/3/library/asyncio-task.html
Answered By - Edher Carbajal
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.