I have a code with an image that I can move with my keyboard. At first I had a very jerky movement and so I added a kivy clock. Now when you press a key to move the image the image moves 30 times per second and then stops, which allows for a rather fluid movement.
But when I keep the key, which allows to move the image, pressed the image no longer moves.
I also tried to have a smooth movement with the speed of kivy ( as in the pong game tutorial https://kivy.org/doc/stable/tutorials/pong.html) but it does not work
How to fix this problem please? ( or how to have a smooth image movement)
I hope my question is clear :),
Thank you in advance for your help
Here is my code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.properties import (
NumericProperty, ReferenceListProperty, ObjectProperty
)
from kivy.vector import Vector
class character(Widget):
pass
class MoveableImage(Image):
def __init__(self, **kwargs):
super(MoveableImage, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
if not self._keyboard:
return
self._keyboard.bind(on_key_down=self.on_keyboard_down)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'right':
Clock.schedule_interval(self.droite, 1.0 / 30.0)
Clock.schedule_once(self.stop_droite , 0.1)
elif keycode[1] == 'left':
Clock.schedule_interval(self.gauche, 1.0 / 30.0)
Clock.schedule_once(self.stop_gauche , 0.1)
elif keycode[1] == 'up':
Clock.schedule_interval(self.up, 1.0 / 30.0)
Clock.schedule_once(self.stop_up, 0.1)
Clock.schedule_once(self.down1, 0.2)
else:
return False
return True
def saut(self, keyboard):
self.y -= 70
def droite(self, keyboard):
self.x += 12
def stop_droite(self, dt):
Clock.unschedule(self.droite)
def gauche(self, keyboard):
self.x -= 12
def stop_gauche(self, dt):
Clock.unschedule(self.gauche)
def up(self, keyboard):
self.y += 50
def stop_up(self, dt):
Clock.unschedule(self.up)
def down1(self, keyboard):
Clock.schedule_interval(self.down2, 1.0 / 30.0)
Clock.schedule_once(self.stop_down, 0.1)
def down2(self, keyboard):
self.y -= 50
def stop_down(self, dt):
Clock.unschedule(self.down2)
class gameApp(App):
def build(self):
wimg = MoveableImage(source='tools/theming/defaulttheme/slider_cursor.png')
m = character()
m.add_widget(wimg)
return m
if __name__ == '__main__':
gameApp().run()
You are scheduling the repeating functions for movement and at the same time you schedule a function that unschedules the repeating fuction after 0.1 s, which will behave somewhat weird.
If you look at the pong tutorial more closely, the code they use is Clock.schedule_interval(game.update, 1.0/60.0)
and that's it basically.
So for your needs, you would call Clock.schedule_interval(self.update, 1.0/30.0)
in your __init__
. From that point on, the self.update
would be called 30 times per second. The self.update
would look something like this:
def update(self):
if self.rightPressed:
self.x += 12
if self.leftPressed:
self.x -= 12
if self.upPressed:
self.y += 50
We should make sure to unschedule the self.update
at some point. A destructor is convenient for this:
def __del__(self):
self.unschedule(self.update)
And finally utilizing self._keyboard.bind(on_key_down=self.on_keyboard_down, on_key_up=self.on_keyboard_up)
:
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'right':
self.rightPressed = True
elif keycode[1] == 'left':
self.leftPressed = True
elif keycode[1] == 'up':
self.upPressed = True
else:
return False
return True
def on_keyboard_up(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'right':
self.rightPressed = False
elif keycode[1] == 'left':
self.leftPressed = False
elif keycode[1] == 'up':
self.upPressed = False
else:
return False
return True
So your code might look like this:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.properties import (
NumericProperty, ReferenceListProperty, ObjectProperty
)
from kivy.vector import Vector
class character(Widget):
pass
class MoveableImage(Image):
def __init__(self, **kwargs):
super(MoveableImage, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
if not self._keyboard:
return
self._keyboard.bind(on_key_down=self.on_keyboard_down, on_key_up=self.on_keyboard_up)
Clock.schedule_interval(self.update, 1.0/30.0)
def __del__(self):
Clock.unschedule(self.update);
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'right':
self.rightPressed = True
elif keycode[1] == 'left':
self.leftPressed = True
elif keycode[1] == 'up':
self.upPressed = True
else:
return False
return True
def on_keyboard_up(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'right':
self.rightPressed = False
elif keycode[1] == 'left':
self.leftPressed = False
elif keycode[1] == 'up':
self.upPressed = False
else:
return False
return True
def update(self):
if self.rightPressed:
self.x += 12
if self.leftPressed:
self.x -= 12
if self.upPressed:
self.y += 50
class gameApp(App):
def build(self):
wimg = MoveableImage(source='tools/theming/defaulttheme/slider_cursor.png')
m = character()
m.add_widget(wimg)
return m
if __name__ == '__main__':
gameApp().run()