Voici un petit moteur physique 2D basé sur la méthode de "l'intégration de Verlet".
Je suis tombé par hasard sur l'article suivant: http://www.gamasutra.com/resource_guide ... n_01.shtml et comme ça me paraissait accessible malgré mes faibles connaissances en maths, j'ai tenté le coup.
Le but n'est pas d'avoir une simulation hyper-précise, mais plutôt un petit truc pas trop lourd utilisable dans un jeu de plateformes (ou autre).
Le code est en trois parties:
- un include contenant des macros pour gérer les vecteurs 2;
- un include contenant le moteur physique lui-même (qui fait appel à l'include précédent);
- un petit programme de démo qui utilise l'include ci-dessus.
Contrôles:
- F1 à F9 : créer des objets
- Souris: en laissant le bouton gauche appuyé, on peut déplacer un point à l'écran
- Suppr: supprime tous les objets (ou seulement un seul si le bouton gauche est appuyé)
- Ctrl droit: ralenti (il faut laisser la touche enfoncée)
- Entrée: active/désactive l'affichage (pour les tests de vitesse)
Remarque: à cause de certaines optimisations (pour l'inverse de racine carrée et les pointeurs) je ne suis pas sûr que ça marche en 64 bits, et encore moins sur Mac ou Linux.
Il reste encore deux-trois trucs à terminer, mais comme c'est déjà marrant comme ça, je le poste...

Allez, je vous laisse tester:
Include 1 (à sauver sous le nom: "vector2.pbi"):
Code : Tout sélectionner
; 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