Search code examples
python-3.xlayoutwidgetkivykivy-language

How can I just make my widget move in Kivy?


I'm not having an awful lot of XP with programming and just starting with Kivy. I can't manage to find my way in the Kivy docs and youtube to combine everything, in this case make my widget move. Specially with the mix of kv and python and different layouts.

Right now I managed to print 'working' if I press the left button. Instead, I want to make my widget (car image) move automatically forward and rotate left and right with the 2 buttons as a car should turn.

Looking forward to see some suggestions. Also I hope somebody with a lot of Kivy experience have some tips of how to approach the kivy docs and kivy in general.

Here is my Python code:

import kivy
kivy.require('1.11.1')
from kivy.app import App
from kivy.uix.label import Label # add some text
from kivy.uix.stacklayout import StackLayout
from kivy.uix.gridlayout import GridLayout #
from kivy.uix.textinput import TextInput #for textinput ;)
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.pagelayout import PageLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.image import Image, AsyncImage
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.button import Button
from kivy.uix.behaviors import ButtonBehavior
from kivy.graphics import Rectangle, Color
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.scatterlayout import ScatterLayout
from kivy.config import Config
from kivy.core.window import Window
from kivy.properties import ObjectProperty, NumericProperty, ReferenceListProperty, ListProperty
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.lang import Builder
import os

Window.size = (450, 750)

print(dir(Widget))

class myGame(FloatLayout):

    def leftButton(self, *args):
        btnLeft = self.ids['btnLeft']
        Car.moveCar(self)

    def rightButton(self, *args):
        btnRight = self.ids['btnLeft']
        print('right button')


class Car(Widget):
    def moveCar(self):
        car = self.ids['car']
        print('working')




class myApp(App): #name your .kv file 'my.kv'
    def build(self): # initialization method, like __init__
        game = myGame()
        return game

if __name__ == '__main__':
    myApp().run()

Here is my kv code:

#:kivy 1.11.1


#<Button>:
    #size_hint: 0.5, 0.27

<FloatLayout>:
    Button:
        id: btnLeft
        pos_hint: {'x': 0, 'bottom': 1}
        size_hint: 0.5, 0.27
        on_press: root.leftButton()
        Image:
            source: 'images/arrow_left.png'
            allow_stretch: True
            keep_ratio: False
            center_x: self.parent.center_x
            center_y: self.parent.center_y  
            size: root.width * 0.5, root.height * 0.27


    Button:
        id: btnRight
        pos_hint: {'x': 0.5, 'bottom': 1}
        size_hint: 0.5, 0.27
        on_press: root.rightButton()
        Image:
            source: 'images/arrow_right.png'
            allow_stretch: True
            keep_ratio: False
            center_x: self.parent.center_x
            center_y: self.parent.center_y  
            size: root.width * 0.5, root.height * 0.27


    Car:      # the Car
        id: car
        canvas:
            Rectangle:
                source: 'images/car_blue_5.png'
                size: root.width * 0.15, root.height * 0.15
                pos: root.width * 0.425, root.height * 0.44

Solution

  • One way to make a Widget move is to use Animation, but if you want to keep changing the movement (steer), then you would probably want to do the animation yourself. Here is a version of your code that does that:

    import kivy
    kivy.require('1.11.1')
    from kivy.app import App
    from kivy.uix.floatlayout import FloatLayout
    from kivy.uix.widget import Widget
    from kivy.core.window import Window
    from kivy.properties import NumericProperty, ListProperty
    from kivy.clock import Clock
    from kivy.lang import Builder
    
    import math
    
    Window.size = (450, 750)
    
    class myGame(FloatLayout):
    
        def leftButton(self, *args):
            self.ids.car.direction_angle += 2
    
        def rightButton(self, *args):
            self.ids.car.direction_angle -= 2
    
    
    class Car(Widget):
        speed = NumericProperty(20)
        direction_angle = NumericProperty(0)   # degrees
        direction = ListProperty([0,1])
    
        def __init__(self, **kwargs):
            super(Car, self).__init__(**kwargs)
            Clock.schedule_interval(self.moveCar, 0.1)
    
        def moveCar(self, dt):
            radians = self.direction_angle * math.pi / 180.0
            self.direction = math.sin(-radians), math.cos(-radians)
            self.pos = (self.x + dt * self.speed * self.direction[0], self.y + dt * self.speed * self.direction[1])
    
    
    Builder.load_string('''
    #:kivy 1.11.1
    
    
    #<Button>:
        #size_hint: 0.5, 0.27
    
    <FloatLayout>:
        Button:
            id: btnLeft
            pos_hint: {'x': 0, 'bottom': 1}
            size_hint: 0.5, 0.27
            on_press: root.leftButton()
            Image:
                source: 'images/arrow_left.png'
                allow_stretch: True
                keep_ratio: False
                center_x: self.parent.center_x
                center_y: self.parent.center_y  
                size: root.width * 0.5, root.height * 0.27
    
    
        Button:
            id: btnRight
            pos_hint: {'x': 0.5, 'bottom': 1}
            size_hint: 0.5, 0.27
            on_press: root.rightButton()
            Image:
                source: 'images/arrow_right.png'
                allow_stretch: True
                keep_ratio: False
                center_x: self.parent.center_x
                center_y: self.parent.center_y  
                size: root.width * 0.5, root.height * 0.27
    
    
        Car:      # the Car
            id: car
            size_hint: None, None
            size: root.width * 0.15, root.height * 0.15
            pos: root.width * 0.425, root.height * 0.44
            canvas.before:
                PushMatrix
                Rotate:
                    angle: self.direction_angle
                    origin: self.center
            canvas:
                Rectangle:
                    source: 'images/car_blue_5.png'
                    size: self.size
                    pos: self.pos
            canvas.after:
                PopMatrix
    ''')
    
    
    class myApp(App): #name your .kv file 'my.kv'
        def build(self): # initialization method, like __init__
            game = myGame()
            return game
    
    if __name__ == '__main__':
        myApp().run()
    

    The __init__() method of the Car starts the animation using a Clock.schedule_interval() call to update the Car position 10 times per second.

    The movement of the Car is calculated in the moveCar() method and uses the direction_angle and speed to update the position.

    The Buttons adjust the direction_angle property, which is used in the canvas of the Car to change its orientation.