GroverSuper

Участник

Активность: 3 г. назад

  1. 3 г. назад
    Thu Sep 25 09:42:38 2014
    GroverSuper начал обсуждение Коллизия линий и круга с примером.

    Нашел в интернете пример проверки коллизий линии с линией и линии с кругом.
    Плюс вычисляется много всяких параметров.
    Формулы не мои. Я только перегнал все под Манки и сделал удобные классы.
    Примерчик в наличии, код можно запускать и экспериментировать.

    есть понятные комментарии

    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
  2. Thu Sep 25 09:37:58 2014
    GroverSuper присоединился к форуму.