在 Kivy 中创建方向键(限制移动)

Creating a D-pad in Kivy (constrain movement)

我对使用 Kivy 进行作业还很陌生,我对一个特定问题感到困惑。我的目标是创建一个如下图所示的方向键,蓝色圆圈将从图像的中心开始并且可以被拖动,但圆圈只能沿着箭头所描绘的方向移动(向上,下、左、右)并且不能超过箭头。现在,我只关心图形布局,所以我所做的只是一个具有下面拖动行为的小部件。有什么方法可以限制圆圈的运动吗?

图片: The current achievable graphical layout for the d-pad

Python代码:

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 文件:

<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

这只是一些提示,蓝色圆圈并不完全限制在轴上

.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

产出