Here's a little 2D physics engine based on "Verlet Integration".
I came across the following article: http://www.gamasutra.com/resource_guide ... n_01.shtml and it seemed accessible to me despite my limited knowledge in maths. So I tried to code it in PB.
The goal is not to create an accurate simulation; it's just a little something to include in a platform game (or other) without consuming too much CPU.
The source comes in 3 parts:
- an include containing macros to manage vectors 2;
- an include containing the physics engine itself (which uses the include above);
- A small demo program that uses the physics engine.
Controls:
- F1-F9: create objects
- Mouse: keeping the left mouse button pressed, you can pick and move a point on the screen
- Del: Removes all objects (or only one if the left button is pressed)
- Right Ctrl: slow motion (keep the button pressed)
- Return: enables/disables the display (for speed tests)
Note: Due to some optimizations (for the inverse square root and pointers) I'm not sure it works in 64 bits, and even less on Mac or Linux.
There are still a few things to finish, but it's already fun as it is, so I post it... : wink:
Include#1 (save it as "vector2.pbi")
Code: Select all
; Author: Kelebrindae
; Date: December, 01, 2010
; PB version: v4.51
; ---------------------------------------------------------------------------------------------------------------
; Description:
; ---------------------------------------------------------------------------------------------------------------
; Vector2 library
; Parts of this code is based on this page: http://www.blitzmax.com/codearcs/codearcs.php?code=2737
; Thanks, Sauer!
; ---------------------------------------------------------------------------------------------------------------
;- Structure and globals
Structure vector2_struct
x.f
y.f
EndStructure
Global VEC2_tempLength.f
Global VEC2_tempCondition.b
Global VEC2_tempVectorC.vector2_struct,VEC2_tempVectorD.vector2_struct,VEC2_tempVectorE.vector2_struct
Global VEC2_tempProjVector.vector2_struct,VEC2_tempZeroVector.vector2_struct
Global VEC2_sqrhalf.f,*VEC2_sqrptr,VEC2_sqrInt.i ; used in fast inverse square root macro
;************************************************************************************
; Name: VEC2_INVSQR
; Purpose: Fast inverse square root approximation (faster than 1/sqr(x) )
; Credits: http://www.purebasic.fr/french/viewtopic.php?f=6&t=4113&hilit=sqr
; http://www.purebasic.fr/french/viewtopic.php?f=6&t=9963
; Parameters:
; - input (float)
; - result (lloat)
;************************************************************************************
Macro VEC2_INVSQR(x,result)
result = x
VEC2_sqrhalf = 0.5 * result
*VEC2_sqrptr = @result
VEC2_sqrInt = PeekI(*VEC2_sqrptr)
; The magic number is different in 64 bits
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
PokeI(*VEC2_sqrptr,$5FE6EB50C7AA19F9 - ( VEC2_sqrInt >> 1))
CompilerElse ; all the others are 32 bits ?
PokeI(*VEC2_sqrptr,$5F375A86 - ( VEC2_sqrInt >> 1)) ; or $5f3759df
CompilerEndIf
result=result*(1.5 - VEC2_sqrhalf * result * result)
result=result*(1.5 - VEC2_sqrhalf * result * result) ; twice for greater precision
result=result*(1.5 - VEC2_sqrhalf * result * result) ; thrice is even better (but you can ditch it to squeeze a few extra cycles from your code)
EndMacro
;************************************************************************************
; Name: VEC2_add
; Purpose: Adds two vector
; Parameters:
; - vector #1 (vector2)
; - vector #2 (vector2)
; - result (vector2)
;************************************************************************************
Macro VEC2_add(vectorA,vectorB,vectorResult)
vectorResult\x = vectorA\x + vectorB\x
vectorResult\y = vectorA\y + vectorB\y
EndMacro
;************************************************************************************
; Name: VEC2_substract
; Purpose: Substracts two vector
; Parameters:
; - vector #1 (vector2)
; - vector #2 (vector2)
; - result (vector2)
;************************************************************************************
Macro VEC2_substract(vectorA,vectorB,vectorResult)
vectorResult\x = vectorA\x - vectorB\x
vectorResult\y = vectorA\y - vectorB\y
EndMacro
;************************************************************************************
; Name: VEC2_multiply
; Purpose: Multiply a vector by a number
; Parameters:
; - vector (vector2)
; - magnitude (float)
; - result (vector2)
;************************************************************************************
Macro VEC2_multiply(vectorA,magnitude,vectorResult)
vectorResult\x = vectorA\x * magnitude
vectorResult\y = vectorA\y * magnitude
EndMacro
;************************************************************************************
; Name: VEC2_squareLength
; Purpose: (distance between A and B)²
; Parameters:
; - coords of point A (vector2)
; - coords of point B (vector2)
;************************************************************************************
Macro VEC2_squareLength(vectorA,vectorB)
((vectorA\x - vectorB\x) * (vectorA\x - vectorB\x) + (vectorA\y - vectorB\y) * (vectorA\y - vectorB\y))
EndMacro
;************************************************************************************
; Name: VEC2_length
; Purpose: Distance between A and B
; Parameters:
; - coords of point A (vector2)
; - coords of point B (vector2)
;************************************************************************************
Macro VEC2_length(vectorA)
Sqr( vectorA\x*vectorA\x + vectorA\y*vectorA\y )
EndMacro
;************************************************************************************
; Name: VEC2_normalize
; Purpose: Normalizes a vector
; Parameters:
; - vector A (vector2)
; - result (vector2)
;************************************************************************************
Macro VEC2_normalize(vectorA,vectorResult)
; Standard method
VEC2_tempLength = VEC2_length(vectorA)
vectorResult\x = vectorA\x / VEC2_tempLength
vectorResult\y = vectorA\y / VEC2_tempLength
; Faster
;VEC2_INVSQR(vectorA\x*vectorA\x + vectorA\y*vectorA\y,VEC2_tempLength)
;vectorResult\x = vectorA\x * VEC2_tempLength
;vectorResult\y = vectorA\y * VEC2_tempLength
EndMacro
;************************************************************************************
; Name: VEC2_dotproduct
; Purpose: Dot product of two 2D vector
; Parameters:
; - vector #1
; - vector #2
;************************************************************************************
Macro VEC2_dotProduct(vectorA,vectorB)
(vectorA\x * vectorB\x + vectorA\y * vectorB\y)
EndMacro
;************************************************************************************
; Name: VEC2_crossproduct
; Purpose: Cross product of two 2D vector
; Parameters:
; - vector #1
; - vector #2
;************************************************************************************
Macro VEC2_crossProduct(vectorA,vectorB)
(vectorA\x * vectorB\y - vectorA\y * vectorB\x)
EndMacro
;************************************************************************************
; Name: VEC2_crossVector
; Purpose: Gives the perpendicular vector
; Parameters:
; - input (vector2)
; - result (vector2)
;************************************************************************************
Macro VEC2_crossVector(vectorA,vectorResult)
;returns a vector perpendicular to v
vectorResult\x = vectorA\y
vectorResult\y = -vectorA\x
EndMacro
;************************************************************************************
; Name: VEC2_angleBetween
; Purpose: Angle from A to B
; Parameters:
; - coords of point A (vector2)
; - coords of point B (vector2)
;************************************************************************************
Macro VEC2_angleBetween(vectorA,vectorB)
ACos(VEC2_dotProduct(normalize(vectorA),normalize(vectorB)))
EndMacro
;************************************************************************************
; Name: VEC2_rotate
; Purpose: Rotates a vector
; Parameters:
; - vector (vector2)
; - angle in radians (float)
; - result (vector2)
;************************************************************************************
Macro VEC2_rotate(vectorA,rad,vectorResult)
; Counter clockwise rotation, in radians
vectorResult\x=(Cos(rad)*vectorA\x)-(Sin(rad)*vectorA\y)
vectorResult\y=(Sin(rad)*vectorA\x)+(Cos(rad)*vectorA\y)
EndMacro
;************************************************************************************
; Name: VEC2_reflection
; Purpose: Computes a reflection vector, vectorA being the direction and vectorB being
; the surface.on which to reflect ("Through" means "through wall" or "bounce
; off wall")
; Parameters:
; - vector #1 (vector2)
; - vector #2 (vector2)
; - result (vector2)
;************************************************************************************
Macro VEC2_Reflection(vectorA,vectorB,through,vectorResult)
If through=#False
VEC2_tempVectorC\x = vectorB\x
VEC2_tempVectorC\y = vectorB\y
Else
VEC2_tempVectorC = VEC2_crossVector(vectorB)
EndIf
VEC2_tempVectorD = VEC2_normalize(vectorA)
VEC2_tempVectorC = VEC2_normalize(VEC2_tempVectorC)
VEC2_tempVectorE = VEC2_multiply(VEC2_tempVectorC,VEC2_dotProduct(VEC2_tempVectorD,VEC2_tempVectorC))
vectorResult = VEC2_substract(VEC2_multiply(VEC2_tempVectorE,2),VEC2_tempVectorD)
vectorResult = VEC2_normalize(vectorResult)
EndMacro
;************************************************************************************
; Name: VEC2_collCircleToCircle
; Purpose: Indicates if two circles collide
; Parameters:
; - center of circle #1 (vector2)
; - center of circle #2 (vector2)
; - radius of circle #1 (float)
; - radius of circle #2 (float)
; - result (boolean)
;************************************************************************************
Macro VEC2_collCircleToCircle(vectorA,vectorB,radiusA,radiusB,result)
;simple circle to circle collision using vectors; both circles has the same radius
If VEC2_squareLength(vectorA,vectorB) < (radius) * (radius)
result = #True
Else
result = #False
EndIf
EndMacro
;************************************************************************************
; Name: VEC2_collCircleToVector
; Purpose: Indicates if a circle (with center vectorA and radius) and a vector (with
; origin vectorB and direction/magnitude.vectorC) are colliding,
; Parameters:
; - center of circle (vector2)
; - radius of circle (float)
; - vector origin (vector2)
; - vector direction/magnitude (vector2)
; - result (boolean)
;************************************************************************************
Macro VEC2_collCircleToVector(vectorA,radius,vectorB,vectorC,result)
VEC2_tempVectorD = VEC2_substract(vectorA,vectorB)
VEC2_tempVectorE = normalize(vectorC)
VEC2_tempProjVector = VEC2_multiply(VEC2_tempVectorE,VEC2_dotProduct(VEC2_tempVectorE,VEC2_tempVectorD))
VEC2_collCircleToCircle(VEC2_tempVectorD,VEC2_tempProjVector,radius,radius,VEC2_tempCondition)
VEC2_tempLength = VEC2_length(vectorC) + radius
VEC2_tempLength = (VEC2_tempLength * VEC2_tempLength)
If VEC2_tempCondition = #True And VEC2_squareLength(VEC2_tempProjVector,VEC2_tempZeroVector) <= tempVEC2_Length + radius And VEC2_squareLength(VEC2_tempProjVector,vectorC) <= VEC2_tempLength + radius
result = #True
Else
result = #False
EndIf
EndMacro