Kivy小部件坐标与collide_point不正确

时间:2019-05-24 00:47:31

标签: python kivy

很明显,只是我在这里缺少一些知识,但是无论如何,我会问我一个问题。

我正在尝试在屏幕上制作一个圆形接触点,以模拟操纵杆。为了实现这一点,我从一个圆形的小部件开始。因此,我在小部件中绘制了一个圆圈,并覆盖了Widget.collide_point()

但是在测试中:
(a)我的小部件从不使用右下位置提示,并且...
(b)似乎认为其中心点位置不在屏幕上。

我认为这是某种问题,即在构建期间未最终确定小部件的坐标(因为我假设容器小部件将其移动了),但是我真的不了解如何进一步解决此问题。

[在旁边]如果我创建一个以self.center_xself.center_y为中心的圆,则它在屏幕的左下方变得部分不在屏幕上。我一点都不明白。

在容器小部件定位完成后,我尝试设置带有时钟的回调以重新调整圆圈,但这也无济于事。

#! /usr/bin/env python3
import kivy
kivy.require('1.9.1')

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Rectangle, Color, Rotate, PushMatrix, PopMatrix, Line, Ellipse
from kivy.core.window import Window
from kivy.clock import Clock

import random

WINDOW_WIDTH, WINDOW_HEIGHT = Window.size

class JoyStick( Widget ):

    def __init__( self, dial_width, **kwargs ):
        super( JoyStick, self ).__init__( **kwargs )
        self.radius     = dial_width // 2
        self.radius_sq  = self.radius * self.radius

        with self.canvas:
            Color( 200, 200, 20 )
            #Ellipse( pos=( self.center_x , self.center_y ), size=(self.radius * 2, self.radius * 2))
            Line( circle=( dial_width, dial_width, self.radius ) )

        self.size_hint  = ( None, None )  
        self.pos_hint   = { 'right':1, 'top':0 } 

    def collide_point( self, x, y ):
        centre_x = self.center_x
        centre_y = self.center_x
        print("JoyStick.collide_point( %d, %d ) -> cx=%d, cy=%d, r=%d" % ( x, y, centre_x, centre_y, self.radius ) )
        # Point-in-Circle Formula: if ((x-centre_x)^2 + (y - centre_y)^2 < radius^2) -> TRUE
        x_minus_cx = x - centre_x
        y_minus_cy = y - centre_y
        result = ( ( x_minus_cx * x_minus_cx ) + ( y_minus_cy * y_minus_cy ) < self.radius_sq ) 
        print("JoyStick.collide_point( %d, %d ) -> %s" % ( x, y, str( result ) ) )
        return result


class Screen( FloatLayout ):
    def __init__(self, **kwargs):
        super( Screen, self).__init__(**kwargs)
        # Controller
        self.joystick = JoyStick( 150 )
        self.add_widget( self.joystick )

    def on_touch_down( self, touch ):
        if ( self.joystick.collide_point( *touch.pos ) ):
            print("Joystick Handled point")

    def update( self, dt ):
        pass


class MainApp( App ):
    def build( self ):
        screen = Screen()
        Clock.schedule_interval( screen.update, 1.0 / 60.0 )
        return screen



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

标准输出-在这种情况下,我必须拉伸窗口才能真正获得750x750的点击。

JoyStick.collide_point( 531, 582 ) -> cx=750, cy=750, r=75
JoyStick.collide_point( 531, 582 ) -> False
JoyStick.collide_point( 672, 712 ) -> cx=750, cy=750, r=75
JoyStick.collide_point( 672, 712 ) -> False
JoyStick.collide_point( 737, 721 ) -> cx=750, cy=750, r=75
JoyStick.collide_point( 737, 721 ) -> True
Joystick Handled point

main.png

1 个答案:

答案 0 :(得分:1)

仅提供一些有关这项工作的建议。我会把布局放在kv中。并改用on_touch_move。至少那是我期望操纵杆工作的方式,在移动中。
然后有一些错字,例如centre_y = self.center_x
好吧,让我在这里举个例子。看起来仍然像您在做什么,只是添加了一些标签进行调试,而不是打印。

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty

class JoyStick(Widget):
    radius = 70

    def collide_point( self, x, y ):
        result = (x-self.center_x) ** 2 + (y-self.center_y) ** 2 < self.radius ** 2
        return result

class MyLayout(FloatLayout):
    handling = StringProperty("")
    xt = StringProperty("")
    yt = StringProperty("")

    def on_touch_move( self, touch ):
        self.xt, self.yt = str(round(touch.pos[0])), str(round(touch.pos[1]))
        if ( self.js.collide_point( *touch.pos ) ):
            self.handling = "True"
        else:
            self.handling = "False"


KV = """

MyLayout:
    js: js
    JoyStick:
        id: js
        canvas:
            Line:
                circle: root.center_x, root.center_y, self.radius

    Label:
        font_size: "30sp"
        text: root.handling
    BoxLayout:
        orientation: "vertical"
        Label:
            text: "x: {}".format(root.xt)
        Label:
            text: "y: {}".format(root.yt)
"""


class MyApp(App):
    def build(self):
        return Builder.load_string(KV)


MyApp().run()