Un peu dans la lignée de mon aéroglisseur (cf. post précédent), je me suis créé une procédure qui génère un circuit rudimentaire (une piste + une barrière de chaque côté) à partir d'une liste de points.
=> Une portion de circuit est définie par un point(x,y,z)+largeur. On passe à la procédure la liste de ces portions, et ça génère les entities et les physiques bodies correspondants.
Dans l'exemple ci-dessous, j'ai généré la liste de points à coups de sinus/cosinus, mais il est facile d'imaginer un éditeur où on dessinerait une ligne à la souris pour générer la liste de points...
(Note: le code de la procédure est un peu bordélique, désolé )
[edit] correction d'un petit bug dans la suppression des balles qui tombent trop loin...
Code : Tout sélectionner
; Author: Kelebrindae
; Date: december, 9, 2011
; PB version: v4.60
; -----------------------------------------------------------------------------------------------
; Description:
; -----------------------------------------------------------------------------------------------
; Builds a track from a list of 3D points (x,y,z) + width. Physics included!
; Use mouse and arrows to move around
; 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
Debug "----------------------"
Debug "Segment " + Str(numPart)
Debug "Angle avec le précédent = " + StrF(angleToPrev,2)
Debug "Angle avec le suivant =" + StrF(angleToNext,2)
Debug "Résultat précédent =" + StrF(oldangle,2)
Debug "Résultat =" + StrF(angle,2)
Debug "angle next<->prev = " + StrF(angleToNext - angleToPrev,2)
; 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
Debug "(v1 v2 swappés)"
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)
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,100,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])
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])
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)
;- Track
; Generate a list of points
NewList track.trackpoint_struct()
radius=30
For i=0 To 720 Step 15
AddElement(track())
track()\point\y = i / 10
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 = 5
Next i
; Pass it to the "createTrack" procedure to generate the meshes and the entities
createTrack(track(),1,2)
; Create balls
NewList ball.i()
ballMesh = CreateSphere(#PB_Any,1)
For i=1 To 20
AddElement(ball())
ball() = CreateEntity(#PB_Any,MeshID(ballMesh),#PB_Material_None,1000,i*10,0)
EntityPhysicBody(ball(),#PB_Entity_SphereBody)
Next i
;- 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)
#CameraSpeed = 1
;- Main loop
Repeat
While WindowEvent()
Delay(1)
Wend
; Camera movements
If ExamineMouse()
MouseX = -(MouseDeltaX()/10)*#CameraSpeed
MouseY = -(MouseDeltaY()/10)*#CameraSpeed
EndIf
RotateCamera(0, MouseY, MouseX, RollZ, #PB_Relative)
If ExamineKeyboard()
If KeyboardPushed(#PB_Key_Up)
MoveCamera (0, 0, 0, -#CameraSpeed)
EndIf
If KeyboardPushed(#PB_Key_Down)
MoveCamera (0, 0, 0, #CameraSpeed)
EndIf
EndIf
; When a ball falls out of sight, reposition it at the start of the track
ForEach ball()
If EntityY(ball()) < -30
FreeEntity(ball())
ball() = CreateEntity(#PB_Any,MeshID(ballMesh),#PB_Material_None,track()\point\x+1,track()\point\y,track()\point\z)
EntityPhysicBody(ball(),#PB_Entity_SphereBody,1,0.7,0)
EndIf
Next ball()
; Render scene
RenderWorld()
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)