Looks good,
I was trying to make something like that but based on polygons for a game but I can’t work out collision responses with rotation (and heaps of other stuff)
It is poorly made (it is was only meant for me), but it might help?
I would like to help too, if I can
I was trying to make something like that but based on polygons for a game but I can’t work out collision responses with rotation (and heaps of other stuff)
It is poorly made (it is was only meant for me), but it might help?
Strict ' -------------------------------------------------------------------- ' --------------------------- Test ------------------------------- ' -------------------------------------------------------------------- Type Grounds Field Body:p2D_Body Global List:TList Field Link:TLink Method New() If List=Null Then List=CreateList() Link=ListAddLast(List,Self) Body=New p2D_Body Body._BodyType=2 'Static Body Body.InvMass#=0 Body.CollisionType=Ground_Collision Body.AddShape( p2D_Shape.CreateConvex(Rnd(10,40), Rand(3,6) ) ) End Method Method Draw() SetColor 255,0,0 Body.Shapes[0].Draw(Body.Position.X#,Body.Position.Y#) 'Tmp only End Method End Type Type Blocks Field Body:p2D_Body Global List:TList Field Link:TLink Field MouseMove=False Method New() If List=Null Then List=CreateList() Link=ListAddLast(List,Self) Body=New p2D_Body Body._BodyType=1 'Rigid Body Body.InvMass#=1 Body.AddShape( p2D_Shape.CreateConvex(Rnd(10,40), Rand(3,6) ) ) Body.CollisionType=Block_Collision End Method Method Draw() SetColor 0, 255,0 Body.Shapes[0].Draw(Body.Position.X#,Body.Position.Y#) 'Tmp only End Method End Type 'Setup... Graphics 640,480,0 p2D_Simulator.CreateSimulator(0,0.5) Const Block_Collision=2 Const Ground_Collision=3 p2D_Simulator.SetCollisionResponse(Block_Collision, Ground_Collision, 1) p2D_Simulator.SetCollisionResponse(Block_Collision, Block_Collision, 1) 'Create Blocks... For Local n=0 To 40 Local Block:Blocks=New Blocks Block.Body.Position.X#=Rnd(10,630) Block.Body.Position.Y#=Rnd(10,300) Block.Body.AngRotation#=Rand(0,360) If n=0 Then Block.MouseMove=True Next 'Create Ground... For Local n=0 To 30 Local Ground:Grounds=New Grounds Ground.Body.Position.X#=Rnd(10,630) Ground.Body.Position.Y#=Rnd(200,450) Ground.Body.AngRotation#=Rand(0,360) Next 'Main loop... Local Delta_OldTime#=MilliSecs() While Not KeyDown(KEY_ESCAPE) Cls Local Time#=MilliSecs() Local Speed#=(Time#-Delta_OldTime#)/30 If (Time#-Delta_OldTime#)<10 Then Delay 10-(Time#-Delta_OldTime#) Delta_OldTime#=Time# If Speed#<0 Then Speed#=0 If Speed#>5 Then Speed#=5 p2D_Simulator.Advance(Speed#) For Local Block:Blocks = EachIn Blocks.List If KeyDown(KEY_LEFT) Block.Body.AngRotation#:+Speed# If KeyDown(KEY_RIGHT) Block.Body.AngRotation#:-Speed# If Block.MouseMove=True Block.Body.Position.X#=MouseX() Block.Body.Position.Y#=MouseY() End If Block.Draw() Next For Local Ground:Grounds = EachIn Grounds.List Ground.Draw() Next SetColor 255,255,255 DrawText "Press Left and right | Move Mouse",20,20 FlushMem() Flip Wend ' -------------------------------------------------------------------- ' ------------------------- Physics ------------------------------ ' -------------------------------------------------------------------- Rem bbdoc: BlitzMax 2D Polygon based Rigid body Collision and Physics about: Baa Baa Baa End Rem Rem Module Pub.PolygonPhysics'? ModuleInfo "Version: 0.0" ModuleInfo "Author: Luke Hoschke, and other people's code from blitz basic, and the web" End Rem' Rem bbdoc: 2D Physics Engine about: #p2D_Simulator wrapper holds the main Functions for the Physics Engine<br> You need to call CreateSimulator before calling anything else<br> End Rem Type p2D_Simulator Global _Created:Byte=False Global _BodyList:TList Global Gravity:p2D_Vector Rem bbdoc: Create the Simulater Returns: True if started about: Starts the Physics Engine, and sets the Gravity <br> <br> <b>Note:</b> No new type of p2D is ever made, it is only used as a namespace End Rem Function CreateSimulator(GravityX#=0,GravityY#=1) _BodyList=CreateList() _Collision_Response_List=New Byte[255*255] Gravity=New p2D_Vector Gravity.Set(GravityX#,GravityY#) _Created=True Return True End Function Rem bbdoc: Advances all bodys in the Physics Engine about: Advances all bodys by the timestep (GameSpeed) and responds to collions End Rem Function Advance(GameSpeed#=1) If _Created=False Then RuntimeError "Simulator not created" Local Body:p2D_Body For Body:p2D_Body = EachIn _BodyList For Local Shape:p2D_Shape=EachIn Body.Shapes Shape.Rotate(Body.AngRotation#) Next Next Local Found=0 For Body:p2D_Body = EachIn _BodyList If Body._BodyType<>2 Then 'A bad spot for check... Please Fix For Local OtherBody:p2D_Body = EachIn _BodyList If OtherBody<>Body Then If Body.Collide(OtherBody)=True Then 'Body.Velocity.X#=-Body.Velocity.X# 'Body.Velocity.Y#=-Body.Velocity.Y# 'OtherBody.Velocity.X#=-OtherBody.Velocity.X# 'OtherBody.Velocity.Y#=-OtherBody.Velocity.Y# End If End If Next '---Gravity---' Body.Velocity.Add(Gravity,GameSpeed#) Num_Lower(Body.AngVelocity#,0.1*GameSpeed#) Num_Lower(Body.Velocity.X,0.1*GameSpeed#) Num_Lower(Body.Velocity.Y,0.1*GameSpeed#) Body.Velocity.X#=Body.Velocity.X#*0.9^GameSpeed#'Fix Body.Velocity.Y#=Body.Velocity.Y#*0.9^GameSpeed# '---Move---' Body.Position.Add(Body.Velocity,GameSpeed#) Body.AngRotation#:+Body.AngVelocity#*GameSpeed# End If Next End Function Rem bbdoc: Frees the Simulator about: You might want to do this each level End Rem Function DestroySimulator() 'Clear _Created=False End Function Global _Collision_Response_List:Byte[] Rem bbdoc: Set the Collision Response of a Type colliding with another type about: <i> source_type% = The collision ID For the source body <br> target_type% = The collision ID For the target body <br> Response% = The collision Response mode. <br> 0 = No impulse Or feedback<br> 1 = Impulse only <br> 2 = Feedback only <br> 3 = Impulse & Feedback <br> </i> <b>Description:</b> The collosion in one way if the target type does not <br> collide with the source type as well End Rem Function SetCollisionResponse(source_type%, target_type%, Response%) If _Created=False Then RuntimeError "Simulator not created" If source_type%>255 Or source_type%<0 Then RuntimeError "type must be 1-255" If target_type%>255 Or target_type%<0 Then RuntimeError "type must be 1-255" '_Collision_Response_List[source_type-1]=target_type _Collision_Response_List[ (source_type-1)*255+ (target_type-1) ]=1 End Function Rem bbdoc: Resets all Responses End Rem Function ResetCollisionResponses() If _Created=False Then RuntimeError "Simulator not created" For Local target:Int = EachIn _Collision_Response_List target=0 Next End Function Rem bbdoc: Collision Type Collides End Rem Function CollisionTypeCollides(source_type%, target_type%) Return _Collision_Response_List[ (source_type-1)*255+ (target_type-1) ] End Function Method New() Final RuntimeError "p2D cannot be made" End Method End Type Rem ClearCollisions src_type - entity Type To be checked For collisions. dest_type - entity Type To be collided with. Method - collision detection method. 1: ellipsoid-To-ellipsoid collisions 2: ellipsoid-To-polygon collisions 3: ellipsoid-To-box collisions response - what the source entity does when a collision occurs. 1: stop 2: slide1 - full sliding collision 3: slide2 - prevent entities from sliding down slopes End Rem Rem bbdoc: Physics Body about: The main type used for objects in to the physic engine End Rem Type p2D_Body Field Position:p2D_Vector=New p2D_Vector Field Velocity:p2D_Vector=New p2D_Vector Field AngRotation# =0 Field AngVelocity# =0 Rem bbdoc: 0: Unpickable (default), 1: Polygon End Rem Field PickMode:Byte=1'0 Rem bbdoc: (0-255) A collision type value of 0 indicates that no collision checking will occur with that entity. 1-255 indicates that collision checking will occur End Rem Field CollisionType:Byte=0 Rem bbdoc: None End Rem Field InvMass# =1 'Inverse mass Rem bbdoc: None End Rem Field InvInertia# =1 'Inverse Inertia, Mass for Rotations Rem bbdoc: None End Rem Field Friction# =0.5 '{0-1}, Rem bbdoc: None End Rem Field Elasticity =0.5 '{0-1}, Bounce Field _Dead:Byte=False Field _Link:TLink Field _Size#=-1 Field _BodyType:Byte=1 '{0-None, 1-Rigid Body, 2-Static Body Field _Active:Byte=True Field _Active_Timer:Float=0 Field CountCollisions Field CollisionBody[Max_Collisions] Field Shapes:p2D_Shape[] Method Kill() RemoveLink(_Link) _Dead=True End Method Method New() If p2D_Simulator._Created=False Then RuntimeError "Simulator not created" _Link=ListAddLast(p2D_Simulator._BodyList,Self) End Method Method Delete() End Method Rem bbdoc: AddShape about: Add a shape to the Rigid Body (convex only) End Rem Method AddShape(Shape:p2D_Shape) 'I bet there is an easier way? Local Tmp:p2D_Shape[Shapes.Length] Tmp=Shapes[..] Shapes=New p2D_Shape[Shapes.Length+1] For Local n=0 To Tmp.Length-1 Shapes[n]=Tmp[n] Next Shapes[Shapes.Length-1]=Shape 'Fix Bounding Info UpdateBoundingInfo() End Method Rem bbdoc: Updates to Bounding Info of the Rigid Body End Rem Method UpdateBoundingInfo() '-Find Size- For Local Shape:p2D_Shape=EachIn Shapes Shape.UpdateBoundingInfo() If Shape._Size>_Size Then _Size=Shape._Size Next End Method Rem bbdoc: SetForce End Rem Method SetForce(_X#,_Y#) Velocity.Set(_X#*InvMass#,_Y#*InvMass#) End Method Rem bbdoc: SetForce2 End Rem Method SetForce2(_X#,_Y#) 'Doto... non-center point force, Twists End Method Rem bbdoc: SetTwist End Rem Method SetTwist(_Rotation#) AngVelocity#:+_Rotation#*InvMass# End Method Method BodyDistance#(Other:p2D_Body) Return Distance#(Position.X#,Position.Y#,Other.Position.X#,Other.Position.Y#) End Method Method BodyDistance_Squared#(Other:p2D_Body) Return Distance_Squared#(Position.X#,Position.Y#,Other.Position.X#,Other.Position.Y#) End Method Function LinePick:p2D_Body(_x#,_y#,_x2#,_y2#) Local vOffset:p2D_Vector = New p2D_Vector Local vAxis:p2D_Vector = New p2D_Vector For Local Body:p2D_Body = EachIn p2D_Simulator._BodyList 'Sort based on Distance!! If Body.Pickmode=1 Then If Body.Shapes.Length<>0 Then '### Get closest point on the line, (from "SSwift", I think) ###' Local U# = (Body.Position.X# - _X#) * (_X2# - _X#) + (Body.Position.Y# - _Y#) * (_Y2# - _Y#) U# = U# / ((_X2# - _X#)*(_X2# - _X#) + (_Y2# - _Y#)*(_Y2# - _Y#)) 'Stop it coming of the ends If U#<0 Then U#=0; If U#>1 Then U#=1 'Calculate coordinates of said point. Local Px# = _X# + (U# * (_X2# - _X#)) Local Py# = _Y# + (U# * (_Y2# - _Y#)) If Distance_Squared#(Body.Position.X#,Body.Position.Y#,Px#,Py#) < (Body._size#*Body._size#) Then vOffset.Set( _X# - Body.Position.X# , _Y# - Body.Position.Y#) Local Found_seperating=False For Local Polygon:p2D_Shape=EachIn Body.Shapes For Local i= 0 To (Polygon.Vertices.Length-1)+1 Local n If i=0 Then vAxis.Set(_X-_X2,_Y-_Y2) vAxis.Normalize() n=-1 Else n=i-1 If n=Polygon.Vertices.Length - 1 vAxis.Set(Polygon.Vertices[0].X-Polygon.Vertices[n].X,Polygon.Vertices[0].Y-Polygon.Vertices[n].Y) Else vAxis.Set(Polygon.Vertices[n+1].X-Polygon.Vertices[n].X,Polygon.Vertices[n+1].Y-Polygon.Vertices[n].Y) End If vAxis.Normalize() End If vAxis.Set(-vAxis.y,vAxis.x)'Make perpendicular '- Get Projected Interval -' Local Min0#,Max0# Local Min1#,Max1# 'Projected Polygon Polygon.CalculateInterval(vAxis,min0,max0) 'Projected Line (0 - 'End of line') it is in local space CalculateIntervalPlot(vAxis, _X-_X2 , _Y-_Y2 ,min1,max1) If min1 > 0 Then min1=0 If max1 < 0 Then max1=0 'Turn it in to global space (relative) Local sOffset# = vAxis.DotProduct(vOffset) min0 = min0 + sOffset;max0 = max0 + sOffset '- Get intersections -' Local d0# = min0 - max1 '\ Test for intersections Local d1# = min1 - max0 '/ If (d0# > 0) Or (d1# > 0) Then'seperating axis found Found_seperating=True Exit End If Next Next If Found_seperating=False Return Body End If End If End If End If Next Return Null End Function Rem bbdoc: Uses #Pickmode to cheak if any body is overlap a point return: The overlaping body or NULL End Rem Function PlotPick:p2D_Body(_X#,_Y#) Local vOffset:p2D_Vector = New p2D_Vector Local vAxis:p2D_Vector = New p2D_Vector For Local Body:p2D_Body = EachIn p2D_Simulator._BodyList If Body.Pickmode=1 Then If Body.Shapes.Length<>0 Then If Distance_Squared#(Body.Position.X#,Body.Position.Y#,_X#,_Y#)<(Body._size#*Body._size#) Then vOffset.Set( _X# - Body.Position.X# , _Y# - Body.Position.Y#) Local Found_seperating=False For Local Polygon:p2D_Shape=EachIn Body.Shapes For Local n= 0 To (Polygon.Vertices.Length-1) If n=Polygon.Vertices.Length - 1 vAxis.Set(Polygon.Vertices[0].X-Polygon.Vertices[n].X,Polygon.Vertices[0].Y-Polygon.Vertices[n].Y) Else vAxis.Set(Polygon.Vertices[n+1].X-Polygon.Vertices[n].X,Polygon.Vertices[n+1].Y-Polygon.Vertices[n].Y) End If vAxis.Normalize() vAxis.Set(-vAxis.y,vAxis.x)'Make perpendicular '- Get Projected Interval -' Local Min0#,Max0# Polygon.CalculateInterval(vAxis,min0,max0) '- Get intersections -' Local sOffset# = vAxis.DotProduct(vOffset) min0 = min0 + sOffset max0 = max0 + sOffset If (min0 > 0) Or (-max0 > 0) Then'seperating axis found Found_seperating=True Exit End If Next Next If Found_seperating=False Return Body End If End If End If End If Next Return Null End Function Method Collide(Other:p2D_Body) 'Do the body types collide... If (CollisionType=0 Or Other.CollisionType=0) Then Return False If p2D_Simulator.CollisionTypeCollides(CollisionType, Other.CollisionType)=0.. And p2D_Simulator.CollisionTypeCollides(Other.CollisionType,CollisionType)=0 Then Return False 'Do the bodys have shapes... If Shapes.Length=0 Or Other.Shapes.Length=0 Then Return False 'Can the bodys possibly collide at there distance... Local Min_Distance#=_size#+Other._size# If BodyDistance_Squared#(Other)>(Min_Distance#*Min_Distance#) Then Return False Local vOffset:p2D_Vector = New p2D_Vector vOffset.Set(Position.X - Other.Position.X, Position.Y - Other.Position.Y) Local vAxis:p2D_Vector = New p2D_Vector Local MTD:p2D_Vector Local MTD_Intersect# Local MTD_min0# Local MTD_max0# Local MTD_min1# Local MTD_max1# Local MTD_PolygonA:p2D_Shape Local MTD_PolygonB:p2D_Shape For Local PolygonA:p2D_Shape=EachIn Shapes For Local PolygonB:p2D_Shape=EachIn Other.Shapes For Local i = 0 To (PolygonA.Vertices.Length-1)+(PolygonB.Vertices.Length-1) '--- Get vAxis ---' Local n If i=<(PolygonA.Vertices.Length-1) Then n=i If n=PolygonA.Vertices.Length - 1 vAxis.Set(PolygonA.Vertices[0].X-PolygonA.Vertices[n].X,PolygonA.Vertices[0].Y-PolygonA.Vertices[n].Y) Else vAxis.Set(PolygonA.Vertices[n+1].X-PolygonA.Vertices[n].X,PolygonA.Vertices[n+1].Y-PolygonA.Vertices[n].Y) End If vAxis.Normalize() Else n=(i-(PolygonA.Vertices.Length)) If n=(PolygonA.Vertices.Length-1)+(PolygonB.Vertices.Length-1)+1 vAxis.Set(PolygonB.Vertices[0].X-PolygonB.Vertices[n].X,PolygonB.Vertices[0].Y-PolygonB.Vertices[n].Y) Else vAxis.Set(PolygonB.Vertices[n+1].X-PolygonB.Vertices[n].X,PolygonB.Vertices[n+1].Y-PolygonB.Vertices[n].Y) End If vAxis.Normalize() End If vAxis.Set(-vAxis.y,vAxis.x)'Make perpendicular '- Get Projected Interval -' Local min0#,max0# Local min1#,max1# PolygonA.CalculateInterval(vAxis,min0,max0) PolygonB.CalculateInterval(vAxis,min1,max1) '- Get intersections -' Local sOffset# = vAxis.DotProduct(vOffset) min0 = min0 + sOffset max0 = max0 + sOffset Local d0# = min0 - max1 '\ Test for intersections Local d1# = min1 - max0 '/ If (d0 > 0) Or (d1 > 0) Then'seperating axis found Return False 'Found a seperating axis, they can't possibly be touching Else Local push#=0 If d0<d1 Then push=d0 Else push=d1 End If If MTD=Null Then MTD=New p2D_Vector 'Use... 'MTD.Set(vAxis.x,vAxis.y) 'Local axis_lengh_squared=MTD.DotProduct(MTD) 'MTD.X:*(Push/axis_lengh_squared) 'MTD.Y:*(Push/axis_lengh_squared) MTD.Set(Cos(vAxis.GetAngle()) ,Sin(vAxis.GetAngle()) ) MTD_Intersect=push MTD_PolygonA=PolygonA MTD_PolygonB=PolygonB MTD_min0#=min0# MTD_max0#=max0# MTD_min1#=min1# MTD_max1#=max1# Else If MTD_Intersect>push Then MTD.Set(vAxis.x,vAxis.y) Local axis_lengh_squared#=MTD.DotProduct(MTD) 'MTD.X:*(Push/axis_lengh_squared) 'MTD.Y:*(Push/axis_lengh_squared) MTD.Set(Cos(vAxis.GetAngle()) ,Sin(vAxis.GetAngle()) ) MTD_Intersect=push MTD_PolygonA=PolygonA MTD_PolygonB=PolygonB MTD_min0#=min0# MTD_max0#=max0# MTD_min1#=min1# MTD_max1#=max1# End If End If End If Next Next Next 'Local PolygonA:p2D_Shape=ShapeA 'Local PolygonB:p2D_Shape=ShapeB Local Temp:p2D_Vector=New p2D_Vector Temp.Set(Position.X,Position.Y) Temp.Subtract(Other.Position) If Temp.DotProduct(MTD)<0 Then MTD.X=-MTD.X MTD.Y=-MTD.Y End If 'DebugLog "min0:"+MTD_min0#+" min1:"+MTD_min1#+" max0:"+MTD_max0#+" max1:"+MTD_max1# '- Get Projected Interval -' Local min0#,max0# Local min1#,max1# MTD.Normalize() MTD_PolygonA.CalculateInterval(MTD,min0,max0) MTD_PolygonB.CalculateInterval(MTD,min1,max1) Local sOffset# = MTD.DotProduct(vOffset) 'min0=Sqr( (min0*MTD.x)+(min0*MTD.y) ) 'min1=Sqr( (min1*MTD.x)+(min1*MTD.y) ) 'max0=Sqr( (max0*MTD.x)+(max0*MTD.y) ) 'max1=Sqr( (max1*MTD.x)+(max1*MTD.y) ) min0 = min0 + sOffset max0 = max0 + sOffset Local d0# = max1# - min0# '\ Test for intersections Local d1# = max0# - min1# '/ Local push# If Abs(d0#)>Abs(d1#) Then push=d1# Else push=d0# End If MTD.X#:*Sqr(Abs(push)) MTD.Y#:*Sqr(Abs(push)) Local TotalMass#=InvMass#+Other.InvMass# If TotalMass=0 Then TotalMass=1 Local OtherCollide=0 Local SelfCollide=0 SelfCollide=p2D_Simulator.CollisionTypeCollides(CollisionType, Other.CollisionType) OtherCollide=p2D_Simulator.CollisionTypeCollides( Other.CollisionType, CollisionType) SelfCollide= (SelfCollide=1) Or (SelfCollide=3) OtherCollide= (OtherCollide=1) Or (OtherCollide=3) Local ForceVector:p2D_Vector = New p2D_Vector ForceVector.Add(Velocity) ForceVector.Subtract(Other.Velocity) Local Collision_Normal:p2D_Vector = MTD.Copy() Collision_Normal.Normalize() Local num= (ForceVector.X*Collision_Normal.X) + (ForceVector.Y*Collision_Normal.Y) Collision_Normal.X:*num Collision_Normal.Y:*num Collision_Normal.X:*2 Collision_Normal.Y:*2 ForceVector.X= (ForceVector.X-Collision_Normal.X) ForceVector.Y= (ForceVector.Y-Collision_Normal.Y) If SelfCollide Then If _BodyType<>2 Then Position.Add(MTD, (InvMass#/TotalMass) ) If _BodyType<>2 Then 'Velocity.Set(0,0) 'Velocity.Add(ForceVector, (InvMass#/TotalMass) ) End If Else If Other._BodyType<>2 Then Other.Position.Subtract(MTD, (InvMass#/TotalMass)) If Other._BodyType<>2 Then 'Other.Velocity.Set(0,0) 'Other.Velocity.Subtract(ForceVector, (InvMass#/TotalMass)) End If End If If OtherCollide Then If Other._BodyType<>2 Then Other.Position.Subtract(MTD, (Other.InvMass#/TotalMass) ) If Other._BodyType<>2 Then 'Other.Velocity.Set(0,0) 'Other.Velocity.Subtract(ForceVector, (Other.InvMass#/TotalMass) ) End If Else If _BodyType<>2 Then Position.Add(MTD, (Other.InvMass#/TotalMass) ) If _BodyType<>2 Then 'Velocity.Set(0,0) 'Velocity.Add(ForceVector, (Other.InvMass#/TotalMass) ) End If End If If SelfCollide Then Velocity.Add(MTD,0.4) If OtherCollide Then Other.Velocity.Subtract(MTD,0.4) If SelfCollide Then Num_Lower(Velocity.X,0.03) Num_Lower(Velocity.Y,0.03) End If If OtherCollide Then Num_Lower(Other.Velocity.X,0.03) Num_Lower(Other.Velocity.Y,0.03) End If Return True End Method End Type Type p2D_Joint Field BodyA:p2D_Body Field BodyB:p2D_Body Field Typ:Byte Method Create() End Method End Type Type p2D_Vector Field X#,Y# Method Set(_X#,_Y#) X#=_X# Y#=_Y# End Method Method Rotate(angle#) 'local tx=x'? 'x = x * Cos(angle) - y * Sin(angle); 'y = tx * Sin(angle) + y * Cos(angle); 'Dis#=GetDistance#() 'x= Cos(angle)*X# 'y= Sin(angle)*Y# x= Cos(GetAngle#()+angle#)*GetDistance#() y= Sin(GetAngle#()+angle#)*GetDistance#() End Method Method Add(Other:p2D_Vector,Scalar#=1) X#:+(Other.X#*Scalar) Y#:+(Other.Y#*Scalar) End Method Method Subtract(Other:p2D_Vector,Scalar#=1) X#:-(Other.X#*Scalar) Y#:-(Other.Y#*Scalar) End Method Method DotProduct#(Other:p2D_Vector) Return (X * Other.X)+(Y * Other.Y) End Method Method GetAngle#() Return ATan2(Y#,X#) End Method Method GetDistance#() Return Sqr(X# * X# + Y# * Y#) End Method Method GetDistance_Squared#() Return X# * X# + Y# * Y# End Method Method Normalize() Local Tmp_L#=GetDistance() If Tmp_L#=0 Then Return X#:* (1/Tmp_L#) Y#:* (1/Tmp_L#) End Method Method NormalizeVar(_X# Var, _Y# Var) Local Tmp_L#=GetDistance() If Tmp_L#=0 Then Return _X#=X#/ Tmp_L# _Y#=Y#/ Tmp_L# End Method Method MultiScalar(Scalar#) X#:* Scalar Y#:* Scalar End Method Method Slope#() Return Y#/X# End Method Method Copy:p2D_Vector() Local Vector:p2D_Vector=New p2D_Vector Vector.X=X Vector.Y=Y Return Vector End Method End Type Type p2D_Shape Field Vertices:p2D_Vector[] Field _Vertices:p2D_Vector[] Field _size# Function CreateBox:p2D_Shape(Width:Float, Height:Float) Local Shape:p2D_Shape=New p2D_Shape Shape._Vertices=New p2D_Vector[4] Shape._Vertices[0]=New p2D_Vector Shape._Vertices[0].Set(-Width/2,-Height/2) Shape._Vertices[1]=New p2D_Vector Shape._Vertices[1].Set(Width/2,-Height/2) Shape._Vertices[2]=New p2D_Vector Shape._Vertices[2].Set(Width/2,Height/2) Shape._Vertices[3]=New p2D_Vector Shape._Vertices[3].Set(-Width/2,Height/2) Shape.SetVertices() Return Shape End Function Function CreateConvex:p2D_Shape(Radius:Float, NumPoints:Int) If NumPoints<2 Then Return Null Local Shape:p2D_Shape=New p2D_Shape Shape._Vertices=New p2D_Vector[NumPoints] For Local n=0 To NumPoints-1 Shape._Vertices[n]=New p2D_Vector Local Dir#=(Float(n)/Float(NumPoints))*360 Shape._Vertices[n].Set(Cos(Dir#)*Radius,Sin(Dir#)*Radius) Next Shape.SetVertices() Return Shape End Function Rem bbdoc: Recalculate the shape's size for collisions (you should not need this) End Rem Method UpdateBoundingInfo() '---Get size (Squared)---' Local tmp#=0 Local tmp2#=0 For Local Vertice:p2D_Vector=EachIn _Vertices tmp2=Vertice.GetDistance() If tmp<tmp2 Then tmp=tmp2 Next _size=tmp End Method Rem private doc: Sets Vertices to _Vertices End Rem Method SetVertices() Local n If Vertices.Length<>_Vertices.Length Then For n=0 To Vertices.Length - 1 Vertices[n]=Null Next Vertices=New p2D_Vector[_Vertices.Length] For n=0 To Vertices.Length - 1 Vertices[n]=New p2D_Vector Next End If For n=0 To _Vertices.Length - 1 Vertices[n].Set(_Vertices[n].x,_Vertices[n].y) Next End Method Rem bbdoc: Rotates all the Vertices of the Shape an absolute angle End Rem Method Rotate(_Dir#) SetVertices() For Local Vertice:p2D_Vector=EachIn Vertices Local Dir#=Vertice.GetAngle() Local Dis#=Vertice.GetDistance() Dir#=Dir#+_Dir# Vertice.X=Cos(Dir#)*Dis# Vertice.Y=Sin(Dir#)*Dis# Next End Method Rem bbdoc: Move to shape to an average point End Rem Method Center() Local TotalX#=0 Local TotalY#=0 For Local Vertice:p2D_Vector=EachIn Vertices TotalX:+Vertice.X; TotalY:+Vertice.Y Next Move(TotalX/Vertices.length,TotalY/Vertices.length) End Method Rem bbdoc: Move all the vertices in the shape End Rem Method Move(_X#,_Y#) For Local Vertice:p2D_Vector=EachIn Vertices Vertice.X:+_X#; Vertice.Y:+_Y# Next End Method Rem bbdoc: Draws to the Vertices (for debug only) End Rem Method Draw(_X#,_Y#) SetBlend ALPHABLEND 'SetColor 255,255,255 SetTransform 0,1,1 SetAlpha 0.5 Local Poly#[Vertices.Length *2] For Local i=0 To Vertices.Length - 1 Poly[ (i*2) ]=Vertices[i].X+_X# Poly[ (i*2) +1 ]=Vertices[i].Y+_Y# Next DrawPoly( Poly ) SetAlpha 1 'SetViewport 0,0,graphics_width,graphics_height For Local i=0 To Vertices.Length - 1 If i=Vertices.Length - 1 DrawLine Vertices[i].X+_X#, Vertices[i].Y+_Y#, Vertices[0].X+_X#, Vertices[0].Y+_Y# Else DrawLine Vertices[i].X+_X#, Vertices[i].Y+_Y#, Vertices[i+1].X+_X#, Vertices[i+1].Y+_Y# End If Next End Method Method CalculateInterval(_Axis:p2D_Vector, _Min# Var, _Max# Var ) 'Project polygon _min = _Axis.DotProduct(Vertices[0]) _max = _min Local d# For Local i = 0 To (Vertices.Length - 1) d = _Axis.DotProduct(Vertices[i]) If d < _Min Then _Min = d If d > _Max Then _Max = d Next End Method End Type Private Const Max_Collisions=100 Function CalculateIntervalPlot(_Axis:p2D_Vector, _X#, _Y# , _Min# Var, _Max# Var ); 'Project polygon _min = (_Axis.X# * _X#) + (_Axis.Y# * _Y#) _max = _min End Function Function Num_Lower(_Num# Var, _By#=1,_To#=0) If _Num#>_To# Then _Num#:-_By# If _Num#<_To# Then _Num#:+_By# If Abs(_Num#-_To#)<_By# Then _Num#=_To# End Function Function Distance#(X1#,Y1#,X2#,Y2#) Local X#=X2#-X1#, Y#=Y2#-Y1# Return Sqr(X#*X#+Y#*Y#) End Function Function Distance_Squared#(X1#,Y1#,X2#,Y2#) Local X#=X2#-X1#, Y#=Y2#-Y1# Return X#*X#+Y#*Y# End Function Function GetLength_Squared#(_X#,_Y#) Return (_X# * _X#) + (_Y# * _Y#) End Function Function GetBit(_Byte:Byte, _BitN:Byte) 'Fix speed... Local _tmp:Byte=_Byte For Local n=0 To 7 If 0>_tmp-2^n Then If n<>_BitN Then _tmp:-2^n End If Next If _tmp=2^_BitN Then Return True Return False End Function Function SetBitArray(_Bit:Byte[]) Return _Bit[0]*2^0 + _Bit[1]*2^1 + _Bit[2]*2^2 + _Bit[3]*2^3 + _Bit[4]*2^4 + _Bit[5]*2^5 + _Bit[6]*2^6 + _Bit[7]*2^7 End Function Function SetBit(_Bit0,_Bit1,_Bit2,_Bit3,_Bit4,_Bit5,_Bit6,_Bit7) Return _Bit0*2^0 + _Bit1*2^1 + _Bit2*2^2 + _Bit3*2^3 + _Bit4*2^4 + _Bit5*2^5 + _Bit6*2^6 + _Bit7*2^7 End Function Function SetBitByByte(_Byte:Byte, _BitN:Byte, _value:Byte) Local _tmp:Byte=_Byte For Local n=0 To 7 If _BitN<>n Then _tmp:+GetBit(_Byte, n)*2^n Next _tmp:+ _value*2^ _BitN Return _tmp End Function Public 'End Rem
I would like to help too, if I can