Moin,
Überall tauchen immer mal wieder die Probleme auf: Ich möchte wissen, ob mein Mauszeiger in folgendem Viereck/Dreieck/Kreis/ usw. ist.
Wie stelle ich das an ?
Meistens werden große Gebilde mit Lokalen Variablen und mehreren If Abfragen angeboten, die das Problem meistens lösen, allerdings weder elegant noch schnell.
Deshalb habe ich mir überlegt eine Sammlung anzufertigen, die ausschließlich Kollisionskontrollen enthält an denen (erstmal nur) ein Punkt beteiligt ist.
(d.H. Kollisionen 2er Kreise/Vierecke, Kreis/Viereck usw sind nicht dabei, folgen aber irgendwann...)
Ist nix großes jetzt, aber ich denke es kann helfen, wenn man eigene Buttons erstellt, oder kleine Spiele schreibt in denen etwas zusammenstößt (z.B Schüsse auf Gegner).
Vllt gibts auch Sachen die ich übersehen habe, und die Praktische Anwendungen haben...
Beispiel
; Kollisionen für den 2 Dimensionalen Raum
; Autor: Mars
; AutoIt: 3.3.8.1
; Datum: 28.03.2012
;
; - Hinzufügen von _Kollision_Strecke_Punkt
; | Autor: Christoph54
; | Datum: 02.09.2012
;
; - Anpassung von _Kollision_Strecke_Punkt
; | Autor: Mars
; | Datum: 05.11.2012
;
; - Funktionen
; | _Kollision_Dreieck_Punkt
; | _Kollision_Ellipse_Punkt
; | _Kollision_Kreis_Punkt
; | _Kollision_Rechteck_Punkt
; | _Kollision_Strecke_Punkt
;
#include <GDIPlus.au3>
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]Opt('GUIOnEventMode', 1)
Opt('MouseCoordMode', 2)
Global Const $iB = 640, $iH = 480
[/autoit] [autoit][/autoit] [autoit]Global $hGUI, $hGFX, $hBuf, $hBmp, $aPos[2], $hBru, $hBr2, $hPen, $hPe2
[/autoit] [autoit][/autoit] [autoit]_Main()
[/autoit] [autoit][/autoit] [autoit]Func _Main()
[/autoit] [autoit][/autoit] [autoit]Local $Rect[4] = [Int($iB / 8), Int($iH / 8), Int($iB / 4), Int($iH / 16)]
Local $Circ[3] = [Int($iB / 2), Int($iH / 2), Int(($iB ^ 2 + $iH ^ 2) ^ 0.5 / 4)]
Local $Elli[4] = [Int($iB * 0.75), Int($iH * 0.75), Int($iB / 3), Int($iH / 5)]
Local $Tria[6] = [Int($iB * 0.3), Int($iH * 0.7), Int($iB / 9), Int($iH / 2), Int($iB / 4), Int($iH * 0.9)]
Local $Line[4] = [Int($iB*0.75),Int($iH*0.2),Int($iB*0.85),Int($iH*0.5)]
Local $nWidth = Int(($iB ^ 2 + $iH ^ 2) ^ 0.5 / 16)
[/autoit] [autoit][/autoit] [autoit]Local $aPoints[4][2]
$aPoints[0][0] = 3
For $i = 0 To 2 Step 1
$aPoints[$i + 1][0] = $Tria[$i * 2]
$aPoints[$i + 1][1] = $Tria[$i * 2 + 1]
Next
$hGUI = GUICreate('Kollisionen', $iB, $iH)
GUISetBkColor(0x000000, $hGUI)
_GDIPlus_Startup()
$hGFX = _GDIPlus_GraphicsCreateFromHWND($hGUI)
$hBmp = _GDIPlus_BitmapCreateFromGraphics($iB, $iH, $hGFX)
$hBuf = _GDIPlus_ImageGetGraphicsContext($hBmp)
$hBru = _GDIPlus_BrushCreateSolid(0xFFA0A0A0)
$hBr2 = _GDIPlus_BrushCreateSolid(0xFFFFFFFF)
$hPen = _GDIPlus_PenCreate(0xFFA0A0A0, $nWidth)
$hPe2 = _GDIPlus_PenCreate(0xFFFFFFFF, $nWidth)
_GDIPlus_GraphicsSetSmoothingMode($hBuf, 4)
[/autoit] [autoit][/autoit] [autoit]GUISetOnEvent(-3, '_Exit', $hGUI)
GUIRegisterMsg(0xF, 'WM_PAINT')
OnAutoItExitRegister('_Ende')
GUISetState(@SW_SHOW, $hGUI)
While Sleep(10)
_GDIPlus_GraphicsClear($hBuf)
$aPos = MouseGetPos()
[/autoit] [autoit][/autoit] [autoit]If _Kollision_Rechteck_Punkt($Rect[0], $Rect[1], $Rect[2], $Rect[3], $aPos[0], $aPos[1]) Then
_GDIPlus_GraphicsFillRect($hBuf, $Rect[0], $Rect[1], $Rect[2], $Rect[3], $hBr2)
Else
_GDIPlus_GraphicsFillRect($hBuf, $Rect[0], $Rect[1], $Rect[2], $Rect[3], $hBru)
EndIf
If _Kollision_Kreis_Punkt($Circ[0], $Circ[1], $Circ[2], $aPos[0], $aPos[1]) Then
_GDIPlus_GraphicsFillEllipse($hBuf, $Circ[0] - $Circ[2] / 2, $Circ[1] - $Circ[2] / 2, $Circ[2], $Circ[2], $hBr2)
Else
_GDIPlus_GraphicsFillEllipse($hBuf, $Circ[0] - $Circ[2] / 2, $Circ[1] - $Circ[2] / 2, $Circ[2], $Circ[2], $hBru)
EndIf
If _Kollision_Ellipse_Punkt($Elli[0], $Elli[1], $Elli[2], $Elli[3], $aPos[0], $aPos[1]) Then
_GDIPlus_GraphicsFillEllipse($hBuf, $Elli[0] - $Elli[2] / 2, $Elli[1] - $Elli[3] / 2, $Elli[2], $Elli[3], $hBr2)
Else
_GDIPlus_GraphicsFillEllipse($hBuf, $Elli[0] - $Elli[2] / 2, $Elli[1] - $Elli[3] / 2, $Elli[2], $Elli[3], $hBru)
EndIf
If _Kollision_Dreieck_Punkt($Tria[0], $Tria[1], $Tria[2], $Tria[3], $Tria[4], $Tria[5], $aPos[0], $aPos[1]) Then
_GDIPlus_GraphicsFillPolygon($hBuf, $aPoints, $hBr2)
Else
_GDIPlus_GraphicsFillPolygon($hBuf, $aPoints, $hBru)
EndIf
If _Kollision_Strecke_Punkt($Line[0], $Line[1], $Line[2], $Line[3], $aPos[0], $aPos[1], $nWidth) Then
_GDIPlus_GraphicsDrawLine($hBuf, $Line[0], $Line[1], $Line[2], $Line[3], $hPe2)
Else
_GDIPlus_GraphicsDrawLine($hBuf, $Line[0], $Line[1], $Line[2], $Line[3], $hPen)
EndIf
WM_PAINT()
[/autoit] [autoit][/autoit] [autoit]WEnd
[/autoit] [autoit][/autoit] [autoit]EndFunc
[/autoit] [autoit][/autoit] [autoit]Func _Kollision_Dreieck_Punkt($x1, $y1, $x2, $y2, $x3, $y3, $px, $py)
Return ((($x1 - $px) * ($x2 - $px) + ($y1 - $py) * ($y2 - $py)) / ((($x1 - $px) ^ 2 + ($y1 - $py) ^ 2) ^ 0.5 * (($x2 - $px) ^ 2 + ($y2 - $py) ^ 2) ^ 0.5) + (($x2 - $px) * ($x3 - $px) + ($y2 - $py) * ($y3 - $py)) / ((($x2 - $px) ^ 2 + ($y2 - $py) ^ 2) ^ 0.5 * (($x3 - $px) ^ 2 + ($y3 - $py) ^ 2) ^ 0.5) + (($x3 - $px) * ($x1 - $px) + ($y3 - $py) * ($y1 - $py)) / ((($x3 - $px) ^ 2 + ($y3 - $py) ^ 2) ^ 0.5 * (($x1 - $px) ^ 2 + ($y1 - $py) ^ 2) ^ 0.5)) <= -1
EndFunc
Func _Kollision_Ellipse_Punkt($x, $y, $b, $h, $px, $py)
Return ((($px - $x) * 2 / $b) ^ 2 + (($py - $y) * 2 / $h) ^ 2) <= 1
EndFunc
Func _Kollision_Kreis_Punkt($x, $y, $d, $px, $py)
Return (($x - $px) ^ 2 + ($y - $py) ^ 2) ^ 0.5 <= ($d / 2)
EndFunc
Func _Kollision_Rechteck_Punkt($x, $y, $b, $h, $px, $py)
Return ($px > $x And $py > $y And $px < $x + $b And $py < $y + $h)
EndFunc
Func _Kollision_Strecke_Punkt($x1, $y1, $x2, $y2, $px, $py, $nAbs = 1)
Local $x = (($y2 - $y1) / (($x2 - $x1)^2 + ($y2 - $y1)^2)^0.5) * $nAbs / 2, $y = (($x2 - $x1) / (($x2 - $x1)^2 + ($y2 - $y1)^2)^0.5) * $nAbs / 2
Return _Kollision_Dreieck_Punkt($x1 - $x, $y1 + $y, $x1 + $x, $y1 - $y, $x2 + $x, $y2 - $y, $px, $py) Or _Kollision_Dreieck_Punkt($x1 - $x, $y1 + $y, $x2 - $x, $y2 + $y, $x2 + $x, $y2 - $y, $px, $py)
EndFunc
Func _Round($n, $a)
Return Round($n*10^$a,0)/10^$a
EndFunc
Func WM_PAINT()
_GDIPlus_GraphicsDrawImage($hGFX, $hBmp, 0, 0)
EndFunc
Func _Exit()
Exit
EndFunc
Func _Ende()
[/autoit] [autoit][/autoit] [autoit]_GDIPlus_PenDispose($hPe2)
_GDIPlus_PenDispose($hPen)
_GDIPlus_BrushDispose($hBr2)
_GDIPlus_BrushDispose($hBru)
_GDIPlus_GraphicsDispose($hBuf)
_GDIPlus_BitmapDispose($hBmp)
_GDIPlus_GraphicsDispose($hGFX)
_GDIPlus_Shutdown()
EndFunc
[/autoit]
Bisher vorhanden:
_Kollision_Rechteck_Punkt - Kollision mit einem Rechteck. (x und y beschreiben die obere Linke Ecke, b und h sind Breite und Höhe)
_Kollision_Kreis_Punkt - Kollision mit einem Kreis. (x und y beschreiben den Kreismittelpunkt, d den Durchmesser)
_Kollision_Ellipse_Punkt - Kollision mit einer Ellipse. (x und y beschreiben den Ellipsemittelpunkt, b und h die Breite und Höhe)
_Kollision_Dreieck_Punkt - Kollision mit einem beliebigen Dreieck (xn und yn beschreiben die Koordinaten der Eckpunkte)
_Kollision_Strecke_Punkt - Kollision mit einer beliebigen Strecke (xn und yn beschreiben die Koordinaten der Punkte)
Edit: 05.11.2012
Überarbeitung der Strecke Punkt Kollision.
Vorher: Mathematisch korrekte Lösung, die aber nicht alltagstauglich ist. Die Linie wurde als unendlich dünn angenommen und konnte nur durch "Zufall" getroffen werden.
Nachher: Die Linie wird als Fläche statt als Linie interpretiert. Diese Fläche wird in 2 Dreiecke unterteilt und per _Kollision_Dreieck_Punkt analysiert. Diese Methode ist relativ rechenintensiv. Linien erhalten hiermit einen Parameter um die Breite der Linie anzugeben.
lg
M