Участник
Активность: 7 г. назад
Нашел в интернете пример проверки коллизий линии с линией и линии с кругом.
Плюс вычисляется много всяких параметров.
Формулы не мои. Я только перегнал все под Манки и сделал удобные классы.
Примерчик в наличии, код можно запускать и экспериментировать.
есть понятные комментарии
Strict
Import mojo
Import monkey.math
Class Game Extends App
Field MyLine:cLine ' линия для примера
Field MyCirc:cCircle ' круг дла примера
Field MyRezu:cCollidedData ' тут данные о столкновении
Method OnCreate:Int()
MyLine=New cLine(10,10,200,100)
MyCirc=New cCircle(200,200,20)
MyRezu=New cCollidedData()
SetUpdateRate 60
Return 0
End
Method OnUpdate:Int()
' Круг следует за мышкой
MyCirc.p.x= MouseX();
MyCirc.p.y= MouseY();
Return 0
End
Method OnRender:Int()
Cls()
'рисуем линию для примера
SetColor(255,255,255)
DrawLine(MyLine.p1.x,MyLine.p1.y,MyLine.p2.x,MyLine.p2.y)
'Если было столкновение, то круг становится красным
If LineOverlapCircle( MyLine, MyCirc, MyRezu ) Then
SetColor(200,0,0)
Else
SetColor(255,255,255)
Endif
'рисуем наш круг
DrawCircle(MyCirc.p.x,MyCirc.p.y,MyCirc.r)
Return 0
End
End
Function Main:Int()
New Game()
Return 0
End
'======================================================================
'======================================================================
'======================================================================
'======================================================================
'======================================================================
Class cPoint 'Точка
Field x:Float
Field y:Float
Method New(x1:Float,y1:Float)
x=x1
y=y1
End
End
Class cLine 'Отрезок
Field p1:cPoint
Field p2:cPoint
Method New(x1:Float,y1:Float,x2:Float,y2:Float)
p1=New cPoint(x1,y1)
p2=New cPoint(x2,y2)
End
End
Class cCircle 'Круг
Field p:cPoint
Field r:Int
Method New (x:Float,y:Float,rad:Int)
p=New cPoint(x,y)
r=rad
End
End
'Функция определяет расстояние между двумя точками
Function Distance2D:Float ( p1: cPoint, p2: cPoint)
Local nx:Float = p1.x - p2.x
Local ny:Float = p1.y - p2.y
Return Sqrt( (nx*nx) + (ny*ny) )
End Function
'=======================================
' Line - Line
' Проверка пересечения двуз линий. Возвращает точку пересечения
' функция возвращает True если две линии пересекаются
' в экземпляр класса Rezult:cPoint заполняется точка места пересечения
Function LineIntersect:Bool ( L1: cLine, L2: cLine , Rezult:cPoint)
Local t1: Float = L2.p2.x - L2.p1.x
Local t2: Float = L2.p2.y - L2.p1.y
Local t3: Float = L1.p2.x - L1.p1.x
Local t4: Float = L1.p2.y - L1.p1.y
Local Den:Float = ( t2 * t3 )-( t1 * t4 )
If Den<>0 'есть пересечение
Local t5: Float = L1.p1.x - L2.p1.x
Local t6: Float = L1.p1.y - L2.p1.y
Local Ua: Float = ( t1 * t6 - t2 * t5 ) / Den
Local Ub: Float = ( t3 * t6 - t4 * t5 ) / Den
If (Ua>0) And (Ua<1.0) And (Ub>0) And (Ub<1.0) Then
Rezult.x = L1.p1.x + Ua * t3
Rezult.y = L1.p1.y + Ua * t4
Return True
Endif
Endif
Return False
End Function
Class cCollidedData 'Данные о сталкновении круга с отрезком
Field depth : Float 'глубина проникновения круга за линию
Field point : cPoint 'точка соприкосновения
Field lineAng : Float 'угол отрезка
Field ang : Float 'угол нормали отражения
Field direct : cPoint 'вектор нормали отражения
Method New ()
point=New cPoint(0,0)
direct=New cPoint(0,0)
End
End
'=======================================
' Line - Circle
' Функция проверяет пересечение линии с кругом
' в экземпляр класса Rezult:cCollidedData заполняются все данные о сталкновении
Function LineOverlapCircle : Bool ( l : cLine, c: cCircle, Rezult:cCollidedData )
Local Ang : Float, Dist1 : Float , Dist2 : Float
Local Nx : Float, Ny : Float
Local dx31: Float = c.p.x - l.p1.x
Local dx21: Float = l.p2.x - l.p1.x
Local dy31: Float = c.p.y - l.p1.y
Local dy21: Float = l.p2.y - l.p1.y
Local d: Float = ( (dx21*dx21) + (dy21*dy21) )
If d <> 0 d = ( (dx31*dx21) + (dy31*dy21) ) / d
If d < 0 d = 0
If d > 1 d = 1
Local tp: cPoint = New cPoint( l.p1.x + (dx21*d) , l.p1.y + (dy21*d) )
Dist1 = Distance2D( c.p, tp )
If c.r >= Dist1 Then
' Есть пересечение !!!
Rezult.lineAng = (270-ATan2((l.p2.x - l.p1.x),(l.p2.y-l.p1.y)))
Nx = Cos(Rezult.lineAng-90) * c.r
Ny = Sin(Rezult.lineAng-90) * c.r
Local tl: cLine = New cLine( c.p.x-Nx , c.p.y-Ny , c.p.x+Nx , c.p.y+Ny )
If Not LineIntersect(l, tl, Rezult.point) Then
Dist1 = Distance2D(l.p1, c.p)
Dist2 = Distance2D(l.p2, c.p)
If Dist1<Dist2 Then
Rezult.point.x = l.p1.x
Rezult.point.y = l.p1.y
Else
Rezult.point.x = l.p2.x
Rezult.point.y = l.p2.y
Endif
Endif
Rezult.ang = ( 180.0 - ATan2( (c.p.x - Rezult.point.x), (c.p.y - Rezult.point.y) ) )
Rezult.depth = c.r - Distance2D( Rezult.point, c.p )
Rezult.direct.x = Cos(Rezult.ang-90)
Rezult.direct.y = Sin(Rezult.ang-90)
Return True
Endif
Return False
End Function