Page 1 sur 1

Générateur de circuit (pour jeu de course?)

Publié : sam. 10/déc./2011 20:09
par kelebrindae
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é :wink: )
[edit] correction d'un petit bug dans la suppression des balles qui tombent trop loin... :oops:

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)


Re: Générateur de circuit (pour jeu de course?)

Publié : dim. 11/déc./2011 0:03
par Kwai chang caine
Superbe 8O
Merci 8)

Re: Générateur de circuit (pour jeu de course?)

Publié : dim. 11/déc./2011 4:48
par Huitbit
Joli !

On dirait un carton de loto des campagnes
Boulègue, boulègue...
Quine, quine, carton plein
:lol: :lol:

Hasta la vista !

Re: Générateur de circuit (pour jeu de course?)

Publié : dim. 11/déc./2011 10:38
par comtois
Huitbit a écrit :On dirait un carton de loto des campagnes
Boulègue, boulègue...
Quine, quine, carton plein
ça me fait penser à la même chose :P

Je vois que les textes sont à l'endroit , tu as inversés les coordonnées des textures uv pour ça ? C'est l'avantage quand on fait tout à la main :)

Re: Générateur de circuit (pour jeu de course?)

Publié : dim. 11/déc./2011 12:08
par djes
Chouette exemple, merci!

Re: Générateur de circuit (pour jeu de course?)

Publié : dim. 11/déc./2011 12:41
par Cool Dji
Hello kelebrindae,

Je te dis bravo pour ce code. Associé à celui du CreateTerrain, il y a moyen de faire un truc sympa.
Je réfléchissais à un générateur de route qui s'inscrit dans le terrain en le modifiant à la marge (remblais, devers, pente, intersection...)
J'ai trouvé un utilitaire permettant cela et qui tourne sur Unity (sauf que la version pro d'Unity est à 1500 €)
http://www.youtube.com/watch?v=NAxo7g7sTgk

Je débute en 3D et j'ai quelques limites (mais d'autres forces) : penses-tu que l'on peut essayer d'avancer ensemble et avec d'autres membres sur un tool du genre ?

Re: Générateur de circuit (pour jeu de course?)

Publié : lun. 12/déc./2011 10:09
par kelebrindae
Merci à tous pour les retours positifs! :D

@Cool Dji:
La vidéo est effectivement très intéressante; ça donne des idées.
Par contre, je ne peux guère m'investir dans un quelconque projet en ce moment. :( Je vais être pas mal pris professionnellement cette année; D'ailleurs, au moment où j'écris ces lignes, je suis en pleine formation JEE / Struts (une partie du code ci-dessus a été écrit durant la formation, quand je saturais trop sur Java, ce qui explique en partie son aspect bordélique... :mrgreen:).
Mais bon, si j'ai le temps de faire évoluer le code, je ne manquerai pas de le poster ici bien sûr.

(allez, 'faut que j'y retourne, on aborde les eventListeners et je dois suivre un minimum quand même...)

Re: Générateur de circuit (pour jeu de course?)

Publié : lun. 12/déc./2011 11:36
par Cool Dji
Ok, bon courage à toi !

Je vais me lancer dans cette aventure.
Il y a déjà un important travail de définition des fonctions pour commencer :D

Je me permettrai d'emprunter quelques uns de tes algo : pour rappel c'est ton code CarPhysics qui a été le déclencheur pour me mettre à la 3D :wink:

A++

Re: Générateur de circuit (pour jeu de course?)

Publié : ven. 30/déc./2011 15:51
par Cool Dji
Hello,

Kelebrindae, merci encore à toi pour ce petit bout de code enchanté :D

J'entreprends le façonnage d'un petit Mario Kart, je posterai un topic quand yaura un truc de sympa à voir !

Re: Générateur de circuit (pour jeu de course?)

Publié : sam. 31/déc./2011 8:41
par SPH
waouw