Seite 1 von 1

gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Sonntag 7. März 2021, 21:58
von MupfSpace
Hallo,

Ich versuche gerade gedrehte zu erkennen, ob ein gedrehtes Rechteck mit einem Punkt kollidiert.

Ich habe dazu folgendes beim suchen gefunden:
https://gamedev.stackexchange.com/quest ... -rectangle

Das Funktioniert aber nicht richtig :(
jenachdem welche größe und drehung ich nehme, klappt es manchmal und manchmal nicht..

ich habe folgenden Code:

Code: Alles auswählen

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import Color, Rectangle, Rotate, PushMatrix, PopMatrix
import math

def collides(point_x, point_y, x_rect, y_rect, width_rect, height_rect, center_rect_x, center_rect_y, angle_rect):
    angle_sin = math.sin(angle_rect)
    angle_cos = math.cos(angle_rect)

    x = ((point_x - center_rect_x) * angle_cos - (point_y - center_rect_y) * angle_sin) + center_rect_x
    y = ((point_x - center_rect_x) * angle_sin + (point_y - center_rect_y) * angle_cos) + center_rect_y

    return x > x_rect and x < x_rect + width_rect and y > y_rect and y < y_rect + height_rect

class TestApp(App):
    def __init__(self, **kwargs):
        super(TestApp, self).__init__(**kwargs)
    def build(self):
        layout = BoxLayout()
        widget = Widget()

        with widget.canvas.before:
            PushMatrix()
            Rotate(angle=75, origin=(200, 150))
        with widget.canvas:
            Color(1, 0, 0, 1)
            self.rect = Rectangle(pos=(100, 100), size=(200, 100))
        with widget.canvas.after:
            PopMatrix()

        widget.bind(on_touch_down=self.check)
        layout.add_widget(widget)

        return layout

    def check(self, root, touch):
        print(collides(*touch.pos, *self.rect.pos, *self.rect.size, self.rect.pos[0] + self.rect.size[0]/2, self.rect.pos[1] + self.rect.size[1]/2, 75))

if __name__ ==  "__main__":
    app = TestApp()
    app.run()

wo liegt der fehler und was muss ich anders machen?

Re: gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Sonntag 7. März 2021, 22:18
von einfachTobi
Hab mir ehrlich gesagt nicht genau angesehen, aber beim Überfliegen fiel mir auf: Sinus/Kosinus benötigen den Winkel im Bogenmaß.

Re: gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Sonntag 7. März 2021, 22:31
von MupfSpace
Hm...
ich hab das aber eigentlich genau so gemacht wie das auf der Seite steht. 🤔

Re: gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Sonntag 7. März 2021, 23:38
von __blackjack__
@MupfSpace: Auf der Seite steht kein konkreter Aufruf und Du rufst das halt mit einem falschen Winkelwert auf. 75 liegt nicht im erwarteten Wertebereich und sieht halt deshalb so gar nicht nach einem Winkel im Bogenmass aus sondern eher nach 75°.

Re: gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Montag 8. März 2021, 08:19
von MupfSpace
Was soll ich dann da als r verwenden?
Das ist ja ein Rechteck und kein Kreis...

Re: gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Montag 8. März 2021, 08:23
von __deets__
Wenn du einen Winkel in Grad hast, musst du den ins Bogenmass konvertieren. Ich habe lange nicht geschaut, ob es eine eingebaute Funktion gibt, weil ich die Formel auswendig kenne:

radians = degree / 180.0 * math.pi

Re: gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Montag 8. März 2021, 08:49
von Sirius3
@__deets__: math.radians

Re: gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Montag 8. März 2021, 10:22
von MupfSpace
Das Funktioniert nicht.
Ich habe sowohl math.radians als auch angle / 180 * math.pi versucht.
Es sieht so aus als ob das ein bischen verschoben ist.

Ich habe hier ein Video dazu gemacht: https://youtu.be/Egdh6USHKnA

Code: Alles auswählen

def collides(point_x, point_y, x_rect, y_rect, width_rect, height_rect, center_rect_x, center_rect_y, angle_rect):
    radians = angle_rect / 180.0 * math.pi
    angle_sin = math.sin(radians)
    angle_cos = math.cos(radians)
    

    x = ((point_x - center_rect_x) * angle_cos - (point_y - center_rect_y) * angle_sin) + center_rect_x
    y = ((point_x - center_rect_x) * angle_sin + (point_y - center_rect_y) * angle_cos) + center_rect_y

    return x > x_rect and x < x_rect + width_rect and y > y_rect and y < y_rect + height_rect


Re: gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Montag 8. März 2021, 10:44
von __deets__
Das ist schwierig, das so rauszufummeln. Alternativ kannst du dir auch einfach die aktuelle Transformationsmatrix an der Stelle merken, wo du das Rectangle anlegst. Davon nimmst du die inverse Transformation, und die Mauskoordinate kannst du damit multiplizieren. Damit solltest du eigentlich eine Koordinate im Rectangle-Koordinatensystem bekommen.

Was auch noch sein kann: so wie due gerade vergleichst, koennte es sein, dass du annimmst, das Rectangle waere an einem Eckpunkt (0, 0) definiert. Ich glaube aber eher, dass es um den Mittelpunkt herum definiert ist. Dann saehe die Vergleichsbedingung eher so aus:

Code: Alles auswählen

    return abs(x - x_rect) < width_rect / 2 and abs(y - y_rect) < height_rect

Re: gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Montag 8. März 2021, 11:28
von MupfSpace
Wo muss ich das

Code: Alles auswählen

 return abs(x - x_rect) < width_rect / 2 and abs(y - y_rect) < height_rect
 
genau hinschreiben? anstelle von dem bisherigen?

Code: Alles auswählen

return x > x_rect and x < x_rect + width_rect and y > y_rect and y < y_rect + height_rect
das Funktioniert nicht.

wie würde das mit dem Matrix, was du gesagt hast funktionieren?

Re: gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Montag 8. März 2021, 12:05
von __deets__
Also ich habe damit mal ein bisschen rumgespielt, und ich muss sagen, ich verstehe schon nicht, wie Kivy das rotiert. Ich haette erwartet, dass das um seinen Mittelpunkt rotiert. Oder wegen mir um einen Eckpunkt. Oder um den Szenen-Mittelpuntk. Oder den Koordinatenursprung.

Nichts davon passiert. Das ist zwar rotiert, aber es ist *irgendwo*. Darum hast du wohl auch das "origin" der Rotation explizit angegeben. Das ist natuerlich auch ein Weg, aber wo der sonst steht - man weiss es nicht.

Damit ist aber auch klar, welche Information du hier zugrunde legen musst: rotiert wird der Vektor zwischen Mausposition & origin, und dann geprueft, wie sich das zum Rechteck verhaelt.

Das hier tut fuer mich:

Code: Alles auswählen

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import Color, Rectangle, Rotate, PushMatrix, PopMatrix
import math


def collides(point_x, point_y, rect_x, rect_y, width_rect, height_rect, angle_rect):
    # we need to rotate *against* the rotation of the rectangle
    # to get from world to local coordinates
    s = math.sin(math.radians(-angle_rect))
    c = math.cos(math.radians(-angle_rect))

    rel_x = point_x - rect_x
    rel_y = point_y - rect_y

    local_x = c * rel_x - s * rel_y
    local_y = s * rel_x + c * rel_y
    return abs(local_x) < width_rect / 2 and abs(local_y) < height_rect / 2


class TestApp(App):

    def __init__(self, **kwargs):
        super(TestApp, self).__init__(**kwargs)
        self._origin = (200, 150)
        self._rotation = 75

    def build(self):
        layout = BoxLayout()
        widget = Widget()

        with widget.canvas.before as c:
            PushMatrix()
            Rotate(angle=self._rotation, origin=self._origin)
        with widget.canvas:
            Color(1, 0, 0, 1)
            self.rect = Rectangle(pos=(100, 100), size=(200, 100))
        with widget.canvas.after:
            PopMatrix()

        widget.bind(on_touch_down=self.check)
        layout.add_widget(widget)

        return layout

    def check(self, root, touch):
        print(collides(*touch.pos, *self._origin, *self.rect.size, self._rotation))

if __name__ ==  "__main__":
    app = TestApp()
    app.run()

Re: gedrehte Rechteck - Punk Kollisionserkennung

Verfasst: Montag 8. März 2021, 12:19
von MupfSpace
__deets__ hat geschrieben: Montag 8. März 2021, 12:05 Also ich habe damit mal ein bisschen rumgespielt
Wow, danke schön 😊.
Funktioniert 👍