Générateur de circuit (pour jeu de course?)
Publié : sam. 10/déc./2011 20:09
Bonjour,
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...
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)