Pour tester les possibilités du moteur physique, j'ai créé un proto très primitif de jeu de course: un circuit, une voiture, et vogue la galère.
Mais voilà: galère, justement.

En effet, si le moteur physique pourrait éventuellement se prêter (au prix de quelques astuces) à la création d'un jeu de course, il présente un petit bug: toutes les arêtes des meshes sont traitées comme si elles ressortaient en relief du mesh.
=> du coup, dès qu'une roue passe sur la diagonale d'un carré ou sur le bord du mesh, elle tressaute comme si elle avait rencontré un obstacle, et ça rend la voiture incontrôlable.

Dommage, parce que les résultats étaient encourageants, au regard du peu de code qu'ils avaient demandé...
J'ai signalé le bug dans le forum anglais, alors... Wait and see.
Code : Tout sélectionner
; Author: Kelebrindae
; Date: december, 9, 2011
; PB version: v4.61
; -----------------------------------------------------------------------------------------------
; Description:
; -----------------------------------------------------------------------------------------------
; Racing game prototype using the physics engine.
; Struct for 3D points
Structure coord3D_struct
x.f
y.f
z.f
EndStructure
; Struct of input list to the "CreateTrack" procedure
Structure trackpoint_struct
point.coord3D_struct
width.f
EndStructure
; The "CreateTrack" procedure stores the generated meshes and entities in this list
Structure trackPart_struct
trackMesh.i
trackEntity.i
barrierMesh.i[2]
barrierEntity.i[2]
EndStructure
Global NewList trackPart.trackPart_struct()
EnableExplicit
;********************************************************
;- --- Procedures ---
;********************************************************
; For each track part, this proc generates a texture with the track part's number on it.
; (for demo purpose)
Procedure.i createDemoTexture(i)
Protected numTexture.i,color.i
Select i % 7
Case 0
color = $FFFF00
Case 1
color = $0000FF
Case 2
color = $00FF00
Case 3
color = $FF0000
Case 4
color = $00FFFF
Case 5
color = $0077FF
Case 6
color = $EE00CC
EndSelect
numTexture = CreateTexture(#PB_Any,32,32)
StartDrawing(TextureOutput(numTexture))
Box(0,0,32,32,color)
DrawText(8,8,Str(i),$000000,$FFFFFF)
StopDrawing()
ProcedureReturn numTexture
EndProcedure
; This proc takes a list of 3D points + width and creates the track from it.
Procedure createTrack(List track.trackpoint_struct(),barrierWidth.f = 1.0,barrierHeight.f = 1.0,restitution.f = 0.5,friction.f=0)
Protected *ptrPrev.trackpoint_struct
Protected *ptrCurrent.trackpoint_struct
Protected *ptrNext.trackpoint_struct
Protected *ptrLast.trackpoint_struct
Protected angle.f,oldangle.f
Protected angleToPrev.f,angleToNext.f
Protected vertex1.coord3D_struct,vertex2.coord3D_struct,prevVertex1.coord3D_struct,prevVertex2.coord3D_struct
Protected barV1.coord3D_struct,barV2.coord3D_struct,prevbarV1.coord3D_struct,prevbarV2.coord3D_struct
Protected numPart.i,numTexture.i,numMaterial.i
; Look for last element
*ptrLast = LastElement(track())
; Read start point of track
*ptrPrev = FirstElement(track())
; Read track's points
*ptrCurrent = NextElement(track())
While (*ptrPrev <> *ptrLast)
; Read next point
*ptrNext = NextElement(track())
; Interpolate angle between current and next track part
If *ptrCurrent <> *ptrLast
angleToPrev = Degree(ATan2(*ptrPrev\point\x - *ptrCurrent\point\x, *ptrPrev\point\z - *ptrCurrent\point\z))+90
angleToNext = Degree(ATan2(*ptrCurrent\point\x - *ptrNext\point\x, *ptrCurrent\point\z - *ptrNext\point\z))+90
angle = angleToPrev + (angleToNext - angleToPrev) / 2
Else
angleToPrev = Degree(ATan2(*ptrPrev\point\x - *ptrCurrent\point\x, *ptrPrev\point\z - *ptrCurrent\point\z))+90
angle = angleToPrev
EndIf
; Create mesh
AddElement(trackPart())
trackPart()\trackMesh = CreateMesh(#PB_Any)
; Create vertices
If numPart=0
prevVertex1\x = *ptrPrev\point\x - ( *ptrPrev\width * Cos(Radian(oldangle)))
prevVertex1\y = *ptrPrev\point\y
prevVertex1\z = *ptrPrev\point\z - ( *ptrPrev\width * Sin(Radian(oldangle)) )
prevVertex2\x = *ptrPrev\point\x + ( *ptrPrev\width * Cos(Radian(oldangle)))
prevVertex2\y = *ptrPrev\point\y
prevVertex2\z = *ptrPrev\point\z + ( *ptrPrev\width * Sin(Radian(oldangle)) )
prevbarV1\x = *ptrPrev\point\x - ( (*ptrPrev\width+barrierWidth) * Cos(Radian(oldangle)))
prevbarV1\y = *ptrPrev\point\y + barrierHeight
prevbarV1\z = *ptrPrev\point\z - ( (*ptrPrev\width+barrierWidth) * Sin(Radian(oldangle)) )
prevbarV2\x = *ptrPrev\point\x + ( (*ptrPrev\width+barrierWidth) * Cos(Radian(oldangle)))
prevbarV2\y = *ptrPrev\point\y + barrierHeight
prevbarV2\z = *ptrPrev\point\z + ( (*ptrPrev\width+barrierWidth) * Sin(Radian(oldangle)) )
EndIf
AddMeshVertex(prevVertex1\x,prevVertex1\y,prevVertex1\z)
MeshVertexTextureCoordinate(1,0)
AddMeshVertex(prevVertex2\x,prevVertex2\y,prevVertex2\z)
MeshVertexTextureCoordinate(0,0)
vertex1\x = *ptrCurrent\point\x - ( *ptrCurrent\width * Cos(Radian(angle)))
vertex1\y = *ptrCurrent\point\y
vertex1\z = *ptrCurrent\point\z - ( *ptrCurrent\width * Sin(Radian(angle)) )
vertex2\x = *ptrCurrent\point\x + ( *ptrCurrent\width * Cos(Radian(angle)))
vertex2\y = *ptrCurrent\point\y
vertex2\z = *ptrCurrent\point\z + ( *ptrCurrent\width * Sin(Radian(angle)) )
barV1\x = *ptrCurrent\point\x - ( (*ptrCurrent\width+barrierWidth) * Cos(Radian(angle)))
barV1\y = *ptrCurrent\point\y + barrierHeight
barV1\z = *ptrCurrent\point\z - ( (*ptrCurrent\width+barrierWidth) * Sin(Radian(angle)) )
barV2\x = *ptrCurrent\point\x + ( (*ptrCurrent\width+barrierWidth) * Cos(Radian(angle)))
barV2\y = *ptrCurrent\point\y + barrierHeight
barV2\z = *ptrCurrent\point\z + ( (*ptrCurrent\width+barrierWidth) * Sin(Radian(angle)) )
If Abs(angleToNext - angleToPrev) >= 180
Swap vertex1\x,vertex2\x
Swap vertex1\y,vertex2\y
Swap vertex1\z,vertex2\z
Swap barV1\x,barV2\x
Swap barV1\y,barV2\y
Swap barV1\z,barV2\z
EndIf
AddMeshVertex(vertex1\x,vertex1\y,vertex1\z)
MeshVertexTextureCoordinate(1,1)
AddMeshVertex(vertex2\x,vertex2\y,vertex2\z)
MeshVertexTextureCoordinate(0,1)
; Create faces
AddMeshFace(0, 2, 3)
AddMeshFace(0, 3, 1)
; Finih and compute the normals
FinishMesh()
NormalizeMesh(trackPart()\trackMesh)
BuildMeshShadowVolume(trackPart()\trackMesh)
UpdateMeshBoundingBox(trackPart()\trackMesh)
numTexture = createDemoTexture(numPart)
numMaterial = CreateMaterial(#PB_Any,TextureID(numTexture))
; Create entity
trackPart()\trackEntity = CreateEntity(#PB_Any,MeshID(trackPart()\trackMesh),MaterialID(numMaterial))
EntityPhysicBody(trackPart()\trackEntity,#PB_Entity_StaticBody,0,restitution,friction)
; Create barriers
; Right barrier
trackPart()\barrierMesh[0] = CreateMesh(#PB_Any)
AddMeshVertex(prevVertex2\x,prevVertex2\y + barrierHeight,prevVertex2\z)
MeshVertexTextureCoordinate(2/3,0)
AddMeshVertex(vertex2\x,vertex2\y + barrierHeight,vertex2\z)
MeshVertexTextureCoordinate(2/3,1)
AddMeshVertex(prevVertex2\x,prevVertex2\y,prevVertex2\z)
MeshVertexTextureCoordinate(1,0)
AddMeshVertex(vertex2\x,vertex2\y,vertex2\z)
MeshVertexTextureCoordinate(1,1)
AddMeshFace(0, 2, 3)
AddMeshFace(0, 3, 1)
AddMeshVertex(prevbarV2\x,prevbarV2\y,prevbarV2\z)
MeshVertexTextureCoordinate(1/3,0)
AddMeshVertex(barV2\x,barV2\y,barV2\z)
MeshVertexTextureCoordinate(1/3,1)
AddMeshVertex(prevVertex2\x,prevVertex2\y + barrierHeight,prevVertex2\z)
MeshVertexTextureCoordinate(2/3,0)
AddMeshVertex(vertex2\x,vertex2\y + barrierHeight,vertex2\z)
MeshVertexTextureCoordinate(2/3,1)
AddMeshFace(4, 6, 7)
AddMeshFace(4, 7, 5)
AddMeshVertex(prevbarV2\x,prevbarV2\y - barrierHeight,prevbarV2\z)
MeshVertexTextureCoordinate(0,0)
AddMeshVertex(barV2\x,barV2\y - barrierHeight,barV2\z)
MeshVertexTextureCoordinate(0,1)
AddMeshVertex(prevbarV2\x,prevbarV2\y,prevbarV2\z)
MeshVertexTextureCoordinate(1/3,0)
AddMeshVertex(barV2\x,barV2\y,barV2\z)
MeshVertexTextureCoordinate(1/3,1)
AddMeshFace(8, 10, 11)
AddMeshFace(8, 11, 9)
FinishMesh()
NormalizeMesh(trackPart()\barrierMesh[0])
BuildMeshShadowVolume(trackPart()\barrierMesh[0])
UpdateMeshBoundingBox(trackPart()\barrierMesh[0])
trackPart()\barrierEntity[0] = CreateEntity(#PB_Any,MeshID(trackPart()\barrierMesh[0]),MaterialID(numMaterial))
EntityPhysicBody(trackPart()\barrierEntity[0],#PB_Entity_StaticBody,100,restitution,friction)
; Left barrier
trackPart()\barrierMesh[1] = CreateMesh(#PB_Any)
AddMeshVertex(prevVertex1\x,prevVertex1\y + barrierHeight,prevVertex1\z)
MeshVertexTextureCoordinate(1/3,0)
AddMeshVertex(vertex1\x,vertex1\y + barrierHeight,vertex1\z)
MeshVertexTextureCoordinate(1/3,1)
AddMeshVertex(prevVertex1\x,prevVertex1\y,prevVertex1\z)
MeshVertexTextureCoordinate(0,0)
AddMeshVertex(vertex1\x,vertex1\y,vertex1\z)
MeshVertexTextureCoordinate(0,1)
AddMeshFace(3, 2, 0)
AddMeshFace(1, 3, 0)
AddMeshVertex(prevbarV1\x,prevbarV1\y,prevbarV1\z)
MeshVertexTextureCoordinate(2/3,0)
AddMeshVertex(barV1\x,barV1\y,barV1\z)
MeshVertexTextureCoordinate(2/3,1)
AddMeshVertex(prevVertex1\x,prevVertex1\y + barrierHeight,prevVertex1\z)
MeshVertexTextureCoordinate(1/3,0)
AddMeshVertex(vertex1\x,vertex1\y + barrierHeight,vertex1\z)
MeshVertexTextureCoordinate(1/3,1)
AddMeshFace(7, 6, 4)
AddMeshFace(5, 7, 4)
AddMeshVertex(prevbarV1\x,prevbarV1\y - barrierHeight,prevbarV1\z)
MeshVertexTextureCoordinate(1,0)
AddMeshVertex(barV1\x,barV1\y - barrierHeight,barV1\z)
MeshVertexTextureCoordinate(1,1)
AddMeshVertex(prevbarV1\x,prevbarV1\y,prevbarV1\z)
MeshVertexTextureCoordinate(2/3,0)
AddMeshVertex(barV1\x,barV1\y,barV1\z)
MeshVertexTextureCoordinate(2/3,1)
AddMeshFace(11, 10, 8)
AddMeshFace(9, 11, 8)
FinishMesh()
NormalizeMesh(trackPart()\barrierMesh[1])
BuildMeshShadowVolume(trackPart()\barrierMesh[1])
UpdateMeshBoundingBox(trackPart()\barrierMesh[1])
trackPart()\barrierEntity[1] = CreateEntity(#PB_Any,MeshID(trackPart()\barrierMesh[1]),MaterialID(numMaterial))
EntityPhysicBody(trackPart()\barrierEntity[1],#PB_Entity_StaticBody,100,restitution,friction)
; Prepare next iteration
numpart+1
*ptrPrev = *ptrCurrent
oldangle = angle
*ptrCurrent = *ptrNext
prevVertex1\x = vertex1\x
prevVertex1\y = vertex1\y
prevVertex1\z = vertex1\z
prevVertex2\x = vertex2\x
prevVertex2\y = vertex2\y
prevVertex2\z = vertex2\z
prevbarV1\x = barV1\x
prevbarV1\y = barV1\y
prevbarV1\z = barV1\z
prevbarV2\x = barV2\x
prevbarV2\y = barV2\y
prevbarV2\z = barV2\z
Wend
EndProcedure
DisableExplicit
;- Initialization
If InitEngine3D() = 0
MessageRequester( "Error" , "Can't initialize 3D, check if engine3D.dll is available" , 0 )
End
ElseIf InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0
MessageRequester( "Error" , "Can't find DirectX 7.0 or above" , 0 )
End
EndIf
OpenWindow(0,0, 0, 800 , 500 ,"Piste")
OpenWindowedScreen(WindowID(0),0,0, 800, 500,0,0,0,#PB_Screen_SmartSynchronization)
;- Textures
txtire = CreateTexture(#PB_Any,256, 256)
StartDrawing(TextureOutput(txTire))
Box(0, 0, 256, 256, $777777)
For i=0 To 255 Step 32
Line(i,0,1,256, $222222)
Next i
StopDrawing()
matTire = CreateMaterial(#PB_Any,TextureID(txtire))
;- Track
; Generate a list of points
NewList track.trackpoint_struct()
radius=100
For i=0 To 720 Step 15
AddElement(track())
If i >=22*15 And i <=27*15
If i = 22*15 Or i = 27*15
track()\point\y = 3
Else
track()\point\y = 7
EndIf
Else
track()\point\y = 0
EndIf
If i<360
track()\point\x = radius * Cos(Radian(i))
track()\point\z = radius * Sin(Radian(i))
Else
track()\point\x = radius * Cos(Radian(180-i)) + radius*2
track()\point\z = radius * Sin(Radian(180-i))
EndIf
track()\width = 20
Next i
; Pass it to the "createTrack" procedure to generate the meshes and the entities
createTrack(track(),1,1,0,0.3)
;- Vehicle
carWidth.f = 3
carHeight.f = 0.7
carLength.f = 3
wheelRadius.f = 0.4
wheelPosX.f = (carWidth / 2) - wheelRadius
wheelPosY.f = wheelRadius
wheelPosZ.f = (carLength / 2) - wheelRadius
FirstElement(track())
x = track()\point\x:y = track()\point\y + 3:z = track()\point\z
carMesh = CreateCube(#PB_Any,1)
car = CreateEntity(#PB_Any,MeshID(carMesh),#PB_Material_None)
ScaleEntity(car,1.5,1,2)
EntityLocate(car,x,y + (carHeight / 2) + (wheelRadius * 2),z)
EntityPhysicBody(car,#PB_Entity_BoxBody)
;wheelMesh = CreateSphere(#PB_Any,wheelRadius)
wheelMesh = CreateCylinder(#PB_Any,wheelRadius,0.4)
wheel_FL = CreateEntity(#PB_Any,MeshID(wheelMesh),MaterialID(matTire))
RotateEntity(wheel_FL,90,90,0)
EntityLocate(wheel_FL,x - wheelPosX,y + wheelPosY,z - wheelPosZ)
wheel_FR = CreateEntity(#PB_Any,MeshID(wheelMesh),MaterialID(matTire))
RotateEntity(wheel_FR,90,90,0)
EntityLocate(wheel_FR,x + wheelPosX,y + wheelPosY,z - wheelPosZ)
wheel_RL = CreateEntity(#PB_Any,MeshID(wheelMesh),MaterialID(matTire))
RotateEntity(wheel_RL,90,90,0)
EntityLocate(wheel_RL,x - wheelPosX,y + wheelPosY,z + wheelPosZ)
wheel_RR = CreateEntity(#PB_Any,MeshID(wheelMesh),MaterialID(matTire))
RotateEntity(wheel_RR,90,90,0)
EntityLocate(wheel_RR,x + wheelPosX,y + wheelPosY,z + wheelPosZ)
;- Vehicle bodies and joints
friction.f = 1
restitution.f = 0.1
mass.f = 1
typeBody = #PB_Entity_CylinderBody
EntityPhysicBody(wheel_FL,typeBody,mass,restitution,friction)
EntityPhysicBody(wheel_FR,typeBody,mass,restitution,friction)
EntityPhysicBody(wheel_RL,typeBody,mass,restitution,friction)
EntityPhysicBody(wheel_RR,typeBody,mass,restitution,friction)
x1=1:y1=0:z1=0
x2=0:y2=1:z2=0
carHeight / 4 : wheelPosY / 4
HingeJoint(car,-wheelPosX,-((carHeight / 2)+wheelPosY+0.1),-wheelPosZ,x1,y1,z1,wheel_FL,0,0,0,x2,y2,z2)
HingeJoint(car, wheelPosX,-((carHeight / 2)+wheelPosY+0.1),-wheelPosZ,x1,y1,z1,wheel_FR,0,0,0,x2,y2,z2)
HingeJoint(car,-wheelPosX,-((carHeight / 2)+wheelPosY+0.1),wheelPosZ,x1,y1,z1,wheel_RL,0,0,0,x2,y2,z2)
HingeJoint(car, wheelPosX,-((carHeight / 2)+wheelPosY+0.1),wheelPosZ,x1,y1,z1,wheel_RR,0,0,0,x2,y2,z2)
;- Light
AmbientColor($555555)
CreateLight(0,$BBBBBB, 100,500,100)
WorldShadows(#PB_Shadow_Modulative)
;- Camera
CreateCamera(0, 0, 0, 100, 100)
CameraBackColor(0,$FF7755)
LastElement(track())
CameraLocate(0,track()\point\x+50,track()\point\y+70,track()\point\z+30)
CameraLookAt(0,track()\point\x+30,track()\point\y,track()\point\z+10)
;- Main loop
angle.f = 0
impulse.f = 0.2
leftRightRatio.f = 0.5
trackCam = #True
KeyboardMode(#PB_Keyboard_International)
Repeat
Delay(1)
While WindowEvent() : Wend
;- F1, F2: Change view
;- W : toggle wireframe display
ExamineKeyboard()
If KeyboardReleased(#PB_Key_F1)
trackCam = #True
EndIf
If KeyboardReleased(#PB_Key_F2)
trackCam = #False
EndIf
If KeyboardReleased(#PB_Key_W)
wireframe = 1-wireframe
If wireframe = #True
CameraRenderMode(0,#PB_Camera_Wireframe)
Else
CameraRenderMode(0,#PB_Camera_Textured)
EndIf
EndIf
;- Cursor keys: Move
; Turning left / right = changing the amount of impulse applied to left/right wheels
; Apply impulse on each wheel
angle = 270-EntityYaw(car)
If KeyboardPushed(#PB_Key_Up)
leftRightRatio = 0.5
If KeyboardPushed(#PB_Key_Left)
leftRightRatio = 0.1
ElseIf KeyboardPushed(#PB_Key_Right)
leftRightRatio = 0.9
EndIf
ApplyEntityImpulse(wheel_FL,leftRightRatio * impulse * Cos(Radian(angle)),0,leftRightRatio * impulse * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_RL,leftRightRatio * impulse * Cos(Radian(angle)),0,leftRightRatio * impulse * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_FR,(1 - leftRightRatio) * impulse * Cos(Radian(angle)),0,(1 - leftRightRatio) * impulse * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_RR,(1 - leftRightRatio) * impulse * Cos(Radian(angle)),0,(1 - leftRightRatio) * impulse * Sin(Radian(angle)) )
ElseIf KeyboardPushed(#PB_Key_Down)
leftRightRatio = 0.5
If KeyboardPushed(#PB_Key_Left)
leftRightRatio = 0.1
ElseIf KeyboardPushed(#PB_Key_Right)
leftRightRatio = 0.9
EndIf
ApplyEntityImpulse(wheel_FL,leftRightRatio * -impulse * Cos(Radian(angle)),0,leftRightRatio * -impulse * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_RL,leftRightRatio * -impulse * Cos(Radian(angle)),0,leftRightRatio * -impulse * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_FR,(1 - leftRightRatio) * -impulse * Cos(Radian(angle)),0,(1 - leftRightRatio) * -impulse * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_RR,(1 - leftRightRatio) * -impulse * Cos(Radian(angle)),0,(1 - leftRightRatio) * -impulse * Sin(Radian(angle)) )
Else
If KeyboardPushed(#PB_Key_Right)
ApplyEntityImpulse(wheel_FL,impulse * 0.2 * Cos(Radian(angle)),0,impulse * 0.2 * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_RL,impulse * 0.2 * Cos(Radian(angle)),0,impulse * 0.2 * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_FR,-impulse * 0.2 * Cos(Radian(angle)),0,-impulse * 0.2 * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_RR,-impulse * 0.2 * Cos(Radian(angle)),0,-impulse * 0.2 * Sin(Radian(angle)) )
ElseIf KeyboardPushed(#PB_Key_Left)
ApplyEntityImpulse(wheel_FL,-impulse * 0.2 * Cos(Radian(angle)),0,-impulse * 0.2 * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_RL,-impulse * 0.2 * Cos(Radian(angle)),0,-impulse * 0.2 * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_FR,impulse * 0.2 * Cos(Radian(angle)),0,impulse * 0.2 * Sin(Radian(angle)) )
ApplyEntityImpulse(wheel_RR,impulse * 0.2 * Cos(Radian(angle)),0,impulse * 0.2 * Sin(Radian(angle)) )
EndIf
EndIf
; Turn camera toward vehicle
If trackCam = #True
CameraLocate(0,EntityX(car) + -5 * Cos(Radian(angle)),EntityY(car) + 2,EntityZ(car) + -5 * Sin(Radian(angle)))
EndIf
CameraLookAt(0,EntityX(car),EntityY(car),EntityZ(car))
; Render
RenderWorld()
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)