Kivy виджет некорректно координирует с collide_point - PullRequest
1 голос
/ 24 мая 2019

Очевидно, что я просто скучаю по некоторым знаниям, но в любом случае я задам свой вопрос.

Я пытаюсь сделать круглую точку касания на экране, чтобы имитировать джойстик. Чтобы реализовать это, я начинаю с кругового вида виджета. Итак, я нарисовал круг в виджете и переопределил Widget.collide_point().

Однако на тестировании:
(a) мой виджет никогда не использует подсказку местоположения внизу справа и ...
(б) кажется, что его центральная точка находится за пределами экрана.

Я думаю, что это какая-то проблема с координатами виджета, которые не были завершены во время построения (поскольку я предполагаю, что виджет контейнера перемещает его), но я не совсем понимаю, как решить эту проблему дальше.

[В сторону] Если я создаю круг с центром вокруг self.center_x & self.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()

Stdout - в этом случае мне пришлось растянуть окно, чтобы фактически получить клик 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 Ответ

2 голосов
/ 24 мая 2019

Несколько предложений по созданию этой работы. Я бы поставил макет в кв. И используйте 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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...