python-2.7layoutpycharmkivyd-pad

Creating a D-pad in Kivy (constrain movement)


I am very new to using Kivy for an assignment and I am stumped on one specific issue. My goal is to create a directional pad as shown in the image below whereby the blue circle will start out at the center of the image and is able to be dragged, but the circle can only travel in the directions imaged by the arrows(up, down, left, right) and cannot go further than the arrows. Right now, I am only concerned with the graphical layout so what I have done is simply a widget with drag behaviour below. Is there some way that could constrain the movements of the circle?

Image: The current achievable graphical layout for the d-pad

Python code:

from kivy.uix.widget import Widget
from kivy.uix.behaviors import DragBehavior
from kivy.app import App

class Circle(DragBehavior, Widget):

    def on_touch_move(self, touch):
        tx, ty = touch.pos
        sx, sy = self.pos
        return super(Circle, self).on_touch_move(touch)

class Test(Widget):
    pass

class TestApp(App):
    def build(self):
        return Test()

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

Kivy file:

<Circle>:
    size: 100,74
    drag_rectangle: self.x+36, self.y+28, 16, 25
    drag_timeout: 10000000
    drag_distance: 0
    canvas:
        Color:
            rgba: 0,0,1,.5
        Ellipse:
            pos: self.pos
            size: self.size


<Test>:
    canvas.before:
        Color:
            rgba: 1,1,1,1
       Rectangle:
            size: root.width,root.height
            pos: 0,0
    canvas:
        Color:
            rgba: 1,1,1,1
        Rectangle:
            size: root.width,root.height
            pos: 0,0
            source: 'icons/XY_bar.png'
    Circle:
        pos: root.width/2.3,root.height/2.25

Solution

  • This is just some hints the blue circle is not exactly restricted to the axes

    .py

    from kivy.uix.widget import Widget
    from kivy.uix.behaviors import DragBehavior
    from kivy.app import App
    from kivy.properties import ObjectProperty, NumericProperty
    from kivy.clock import Clock
    
    
    class Circle(DragBehavior, Widget):
    
        def on_touch_move(self, touch):
            if self.collide_point(*touch.pos):
                if self.parent.redliney <= touch.pos[1] <= self.parent.redliney + 100:
                    return super(Circle, self).on_touch_move(touch)
                elif self.parent.greenlinex <= touch.pos[0] <= self.parent.greenlinex + 100:
                    return super(Circle, self).on_touch_move(touch)
    
        def on_touch_down(self, touch):
            if self.collide_point(*touch.pos):
                if self.parent.redliney <= touch.pos[1] <= self.parent.redliney + 100:
                    return super(Circle, self).on_touch_down(touch)
                elif self.parent.greenlinex <= touch.pos[0] <= self.parent.greenlinex + 100:
                    return super(Circle, self).on_touch_down(touch)
    
        def on_touch_up(self, touch):
            if self.collide_point(*touch.pos):
                if self.parent.redliney <= touch.pos[1] <= self.parent.redliney + 100:
                    return super(Circle, self).on_touch_up(touch)
                elif self.parent.greenlinex <= touch.pos[0] <= self.parent.greenlinex + 100:
                    return super(Circle, self).on_touch_up(touch)
    
    
    class Test(Widget):
        c = ObjectProperty()
        joystick_x = NumericProperty(0)
        joystick_y = NumericProperty(0)
        redlinex = NumericProperty(0)
        redliney = NumericProperty(0)
        greenlinex = NumericProperty(0)
        greenliney = NumericProperty(0)
    
        def __init__(self, **kwargs):
            super(Test, self).__init__(**kwargs)
            Clock.schedule_interval(self.update, 1/10.0)
    
        def update(self, *args):
            self.joystick_x = self.c.pos[0]
            self.joystick_y = self.c.pos[1]
    
    
    class TestApp(App):
        def build(self):
            return Test()
    
    if __name__ == '__main__':
        TestApp().run()
    

    kv

    <Test>:
        c: c
        redlinex: self.pos[0] + self.size[0]/8.0
        redliney: self.pos[1] + self.size[1]/2.0 - 50
        greenlinex: self.pos[0] +self.size[0]/2.0 - 50
        greenliney: self.pos[1] + self.size[1]/8.0
        canvas.before:
            Color:
                rgba: 1,1,1,1
            Rectangle:
                size: self.size
                pos: self.pos
            Color:
                rgba: .75,.75,.75,1
            Ellipse:
                pos: root.joystick_x - 50, root.joystick_y - 50
                size: 200, 200
            Color:
                rgba: 1,0,0,1
            Rectangle:
                pos: root.redlinex, root.redliney
                size: 3 * self.size[0]/4.0, 100
            Triangle:
                points: root.redlinex, root.redliney, root.redlinex - 50, root.redliney + 50, root.redlinex, root.redliney + 100
            Triangle:
                points: root.redlinex + 3 * self.size[0]/4.0, root.redliney, root.redlinex + 3 * self.size[0]/4.0 + 50, root.redliney + 50, root.redlinex + 3 * self.size[0]/4.0, root.redliney + 100
            Color:
                rgba: .33, .51, .21, 1
            Rectangle:
                pos: root.greenlinex, root.greenliney
                size: 100, 3 * self.size[1]/4.0
            Triangle:
                points: root.greenlinex, root.greenliney, root.greenlinex + 50, root.greenliney - 50, root.greenlinex + 100, root.greenliney
            Triangle:
                points: root.greenlinex, root.greenliney + 3 * self.size[1]/4.0, root.greenlinex + 50, root.greenliney + 3 * self.size[1]/4.0 + 50, root.greenlinex + 100, root.greenliney + 3 * self.size[1]/4.0
        Circle:
            canvas:
                Color:
                    rgba: .16, .25, .6, 1
                Ellipse:
                    pos: self.pos
                    size: self.size
            id: c
            pos: root.pos[0] + root.size[0]/2.0 - 50, root.pos[1] + root.size[1]/2.0 - 50
            size: 100, 100
            drag_rectangle: self.x, self.y, self.width, self.height
            drag_timeout: 10000000
            drag_distance: 0
    

    Outputs

    pic1

    pic2