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

Généralités sur la programmation 3D
kelebrindae
Messages : 579
Inscription : ven. 11/mai/2007 15:21

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

Message 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)

Les idées sont le souvenir de choses qui ne se sont pas encore produites.
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

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

Message par Kwai chang caine »

Superbe 8O
Merci 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
Huitbit
Messages : 939
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

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

Message par Huitbit »

Joli !

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

Hasta la vista !
Elevé au MSX !
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

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

Message 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 :)
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

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

Message par djes »

Chouette exemple, merci!
Avatar de l’utilisateur
Cool Dji
Messages : 1126
Inscription : ven. 05/sept./2008 11:42
Localisation : Besançon
Contact :

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

Message 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 ?
Only PureBasic makes it possible
kelebrindae
Messages : 579
Inscription : ven. 11/mai/2007 15:21

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

Message 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...)
Les idées sont le souvenir de choses qui ne se sont pas encore produites.
Avatar de l’utilisateur
Cool Dji
Messages : 1126
Inscription : ven. 05/sept./2008 11:42
Localisation : Besançon
Contact :

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

Message 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++
Only PureBasic makes it possible
Avatar de l’utilisateur
Cool Dji
Messages : 1126
Inscription : ven. 05/sept./2008 11:42
Localisation : Besançon
Contact :

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

Message 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 !
Only PureBasic makes it possible
Avatar de l’utilisateur
SPH
Messages : 4726
Inscription : mer. 09/nov./2005 9:53

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

Message par SPH »

waouw
http://HexaScrabble.com/
!i!i!i!i!i!i!i!i!i!
!i!i!i!i!i!i!
!i!i!i!
//// Informations ////
Intel Core i7 4770 64 bits - GTX 650 Ti
Version de PB : 6.00 - 64 bits
Répondre