Page 1 sur 1

Hover Racers

Publié : lun. 17/déc./2012 17:50
par kelebrindae
Voici une version un peu plus aboutie de ma course d'hovercrafts avec un joli menu, du multiplayer en split-screen, des bonus, et deux trois autres trucs:
http://keleb.free.fr/codecorner/downloa ... Racers.zip (8 Mo)

Notes:
--------------------
- Il y a le source du programme principal, mais l'exe inclut en plus un accès à internet pour voir s'il existe une version plus récente et la télécharger pour mettre le programme et les ressources à jour. Je ne l'ai pas mis dans le source pour ne pas trop embrouiller, mais si ça vous intéresse, je l'ajouterai.
- La navigation dans le menu se fait avec les touches du curseur et la barre espace. Les flèches gauche droite servent à augmenter/diminuer (le nombre d'arbres, la résolution, etc..). De plus, pour la constitution des équipes, servez-vous des touches 1 2 3 4 pour affecter les joueurs aux différentes équipes.
- Il n'y a pas de son, peu de bonus, bref: encore beaucoup à faire. J'espère pouvoir l'ajouter au fur et à mesure; ça passera par la mise à jour automatique.
- J'ai inclus Engine3D.dll (renommée en "HoverRacers.dll") pour pouvoir dézipper tout ça dans un coin et que ça marche tout de suite.

Bugs:
------------------
- Le changement de résolution plante. Le CloseScreen / OpenScreen met visiblement le bazar: selon les machines, soit ça crashe instantanément, soit les Particle Emitters ne sont plus définis... :cry:
- Quelquefois, sous certaines conditions que je cerne mal (et que je n'ai pas réussi à isoler dans un code court), la fonction NodeX() renvoie Nan. J'ai contourné le problème en utilisant EntityX() à la place, mais si Comtois est intéressé je peux lui indiquer l'endroit du code où se produit le problème.
- Le code n'est pas du tout optimisé, ça fait peine à voir. Dans les prochaines versions, peut-être... :wink:

Joyeuses fêtes à tous!
Image

Re: Hover Racers

Publié : lun. 17/déc./2012 17:57
par kelebrindae
Je vous mets le code, pour rire (mais sans les ressources contenues dans le zip ci-dessus, ça ne sert pas à grand-chose) :

Code : Tout sélectionner

;************************************************************************************
;  Hovercraft race (inspired by the Binary Moon tutorials for DarkBasic)
;  PB version: 5.00
;  Date: December, 12, 2012
;
;- In game:
;- F1  -> Change camera view
;- F5  -> Display physic bodies
;- F12 -> Display FPS
;
;- Menus:
;- up / down / space -> Select menu item
;- left / right -> Less / more (trees, resolution, ai opponents...)
;- 1 / 2 / 3 / 4 -> Assign player to a team
;************************************************************************************


;************************************************************************************
;-                          ---- Constants and structure ----
;************************************************************************************

#CURRENTVERSION = "0.77"

#NUMTERRAIN = 0
#TerrainMiniX = 0
#TerrainMiniY = 0
#TerrainMaxiX = 0
#TerrainMaxiY = 0

#NB_TEAMS = 4  ; Nb teams ( starts from 0 )
#NB_BONUS = 3
#NB_CRATESMAX = 60

#NEWCAMERACONFIG = 999
#END_DATA = -999999

; Menu pages
Enumeration
  #MENUPAGE_MAIN
  #MENUPAGE_TEAMS
  #MENUPAGE_CONTROLS
  #MENUPAGE_GFX
EndEnumeration

; Menu items
Enumeration
  #MENU_START
  #MENU_NBPLAYERS
  #MENU_TEAMS
  #MENU_CONTROLS
  #MENU_GFX
  
  #MENU_TEAM1
  #MENU_TEAM2
  #MENU_TEAM3
  #MENU_TEAM4
  #MENU_TEAM5
  
  #MENU_CTRL1
  #MENU_CTRL2
  #MENU_CTRL3
  #MENU_CTRL4
  
  #MENU_RESOLUTION
  #MENU_FULLSCREEN
  #MENU_TERRAINDETAIL
  #MENU_TREES
  
  #MENU_BACK  
  #MENU_QUIT
EndEnumeration

; Menu items interactions
Enumeration
  #GO_TO_PAGE
  #TRIGGER
EndEnumeration
#MENU_CLICKED = %001
#MENU_LEFTPRESSED  = %010
#MENU_RIGHTPRESSED = %100

; Cameras (one for each player)
Enumeration
  #CAMERA1
  #CAMERA2
  #CAMERA3
  #CAMERA4
EndEnumeration

Enumeration
  #RearView
  #SideView
  #FrontView
  #TopView
  
  #END_VIEWLIST
  
  #WinnerView
EndEnumeration

; Player type
Enumeration
  #PLAYER_NONE
  #PLAYER_HUMAN
  #PLAYER_CPU
EndEnumeration

; Bonus type
Enumeration -1
  #NO_BONUS
  #BONUS_TURBO
  #BONUS_CRATE
  #BONUS_EXPLO
  #BONUS_FLASH
  #BONUS_MISSILE
  
  #END_BONUSLIST
EndEnumeration


; Menus
Structure menuItem_struct
  numItem.i
  
  numSprite.i
  action.i
  param.i
EndStructure

Structure menuPage_struct
  numPage.i
  
  nbItems.i
  itemList.menuItem_struct[10]
EndStructure

Structure resolution_struct
  width.i
  height.i
  numSprite.i ; sprite used to display resolution infos in the menu
EndStructure

Structure key_struct
  value.i
  name.s
EndStructure
Global NewMap key.key_struct()


; Team infos
Structure teamConf_struct
  players.i
  nbAi.i
EndStructure
Global Dim teamConf.teamConf_struct(5,5) ; one config per team and per nb. players

; Keyboard configuration for each player
Structure controls_struct
  key_up.i
  key_down.i
  key_left.i
  key_right.i
  key_fire.i
  
  key_changeCamView.i
EndStructure
Global Dim controls.controls_struct(4)

; Hovercraft infos
Structure hover_struct
  x.f
  y.f
  z.f
  
  controlMode.i   ; Human or CPU
  numTeam.i
    
  node.i
  frontNode.i
  backNode.i
  leftNode.i
  rightNode.i
  cameraNode.i
  
  hovercraftMesh.i
  hovercraftEntity.i
  physicsEntity.i
  physicsMesh.i
  
  mass.f
  restitution.f
  friction.f
  radius.f
  centerHeight.f   
  thrust.f
  
  *ptrTarget.checkpoint_struct ; can be anything, as long as it has x.f, y.f and z.f in first pos in its structure
  
  bonus.i
  bonustimeLeft.i
  bonusEffect.i
  bonusEffect2.i
  
  paralysed.i
  malusEffect.i
  malusEffect2.i
  
EndStructure
Global Dim hovercraft.hover_struct(60)

; Camera infos
Structure playerCam_struct
  cameraMode.i
  cameraAngle.f
  
  numTargetHovercraft.i
  arrowEntity.i
  
  cameraXpos.i
  cameraYpos.i
  cameraWidthPixel.i
  cameraHeightPixel.i
EndStructure
Global Dim playerCam.playerCam_struct(4)

; Checkpoint infos
Structure checkpoint_struct
  x.f
  y.f
  z.f
  
  node.i
  particle.i
  
  radius.f
EndStructure
Global currentCheckpoint.checkpoint_struct

; Bonus
Structure bonus_struct
  x.f
  y.f
  z.f
  
  bonusEntity.i
  glow.i
  emitter.i
  
  node.i
  hidden.b
EndStructure
Global NewList bonus.bonus_struct()

; Lists of trees and crates currently on track
Global NewList treeEntity.i()
Global NewList crateEntity.i()
Global NewList effectBoard.i()

; Sprites on screen during game
Global Dim scoreSprite.i(5)
Global Dim score.i(5)
Global Dim bonusIcon.i(#END_BONUSLIST)

Global Dim teamColor.i(5)
Global Dim teamMaterial.s(5)


Global cubeMesh.i, crateTexture.i, crateMat.i, cupMat.i

Global screenWidth.i, screenHeight.i, fullscreen.i
Global nbPlayers.i   ; 4 players maxi !
Global nbHovercrafts ; Nb hovercrafts ( starts from 0 )
Global terrainDetail.i = 10 ; Terrain definition (n^2 +1)
Global nbTrees.i
Global scoreLimit.i = 50 ; how much points you need to win
Global victorySprite.i

EnableExplicit

;************************************************************************************
;-                                 ---- Macros ----
;************************************************************************************

; Those two macros are from Comtois. Merci Comtois !
Macro NEWXVALUE(x, Angle, Distance)
  ((x) + Cos(Radian(Angle+90)) * (Distance))
EndMacro

Macro NEWZVALUE(z, Angle, Distance)
  ((z) - Sin(Radian(Angle+90)) * (Distance))
EndMacro

Macro ANGLE2CHECKPOINT(idHovercraft)
  Degree(ATan2(hovercraft(idHovercraft)\z - hovercraft(idHovercraft)\ptrTarget\z , hovercraft(idHovercraft)\x -  hovercraft(idHovercraft)\ptrTarget\x ))
EndMacro

Macro DRAWSCORESPRITE(numTeam)
  StartDrawing(SpriteOutput(scoreSprite(numTeam)))
  Box(0,0,20,20,teamColor(numTeam))
  DrawText(32,2,RSet(Str(score(numTeam)),3,"0"))
  DrawingMode(#PB_2DDrawing_Outlined)
  Box(0,0,64,20,teamColor(numTeam))  
  StopDrawing()
EndMacro

Global DIST_X.f,DIST_Y.f,DIST_Z.f
Macro DISTANCE2(x1,y1,z1,x2,y2,z2,result)
  DIST_X = (x1)-(x2)
  DIST_Y = (y1)-(y2)
  DIST_Z = (z1)-(z2)
  result = DIST_X*DIST_X + DIST_Y*DIST_Y + DIST_Z*DIST_Z ; no sqr, it's faster
EndMacro


;- --- Menu macros ---
; Create a sprite from an image, resized to fit the current resolution
Global TMP_SPR_IMAGE.i
Macro CREATERESIZEDSPRITE(imageFileName, ratio, targetSprite)
  TMP_SPR_IMAGE = LoadImage(#PB_Any,imageFileName)
  targetSprite = CreateSprite(#PB_Any,ImageWidth(TMP_SPR_IMAGE)*(ratio),ImageHeight(TMP_SPR_IMAGE)*(ratio))
  ResizeImage(TMP_SPR_IMAGE,SpriteWidth(targetSprite),SpriteHeight(targetSprite))
  StartDrawing(SpriteOutput(targetSprite))
  DrawImage(ImageID(TMP_SPR_IMAGE),0,0)
  StopDrawing()
  FreeImage(TMP_SPR_IMAGE)
EndMacro

; Create a sprite from a string
Macro CREATESTRINGSPRITE(tmpStr,sprWidth,sprHeight,ratio,targetSprite)
    TMP_SPR_IMAGE = CreateImage(#PB_Any,sprWidth,sprHeight)
    StartDrawing(ImageOutput(TMP_SPR_IMAGE))
    DrawingMode(#PB_2DDrawing_Transparent)
    DrawText(0,0,tmpStr,$666666)
    DrawText(2,2,tmpStr,$666666)
    DrawText(0,2,tmpStr,$666666)
    DrawText(2,0,tmpStr,$666666)
    DrawText(1,1,tmpStr,$EEEEEE)
    StopDrawing()
    
    targetSprite = CreateSprite(#PB_Any,ImageWidth(TMP_SPR_IMAGE)*(ratio)*(64/(sprHeight)),ImageHeight(TMP_SPR_IMAGE)*(ratio)*(64/(sprHeight)) )
    ResizeImage(TMP_SPR_IMAGE,ImageWidth(TMP_SPR_IMAGE)*4,ImageHeight(TMP_SPR_IMAGE)*4,#PB_Image_Smooth)
    ResizeImage(TMP_SPR_IMAGE,SpriteWidth(targetSprite),SpriteHeight(targetSprite),#PB_Image_Smooth)
    StartDrawing(SpriteOutput(targetSprite))
    DrawImage(ImageID(TMP_SPR_IMAGE),0,0)
    StopDrawing()
    FreeImage(TMP_SPR_IMAGE)
  
EndMacro

; Create a sprite displaying the keyboard config for a player
Macro CREATECTRLSPRITE(numPlayer,ratio,targetSprite)
    tmpStr = key(Str(controls(numPlayer)\key_left))\name + " | " + key(Str(controls(numPlayer)\key_right))\name + " | " + key(Str(controls(numPlayer)\key_up))\name + " | " + key(Str(controls(numPlayer)\key_fire))\name   
    CREATESTRINGSPRITE(tmpStr,256,20,ratio,targetSprite)
EndMacro

; Initialize 3D menu elements
Macro INIT3DMENUELEMENTS()
  ; Title background
  bgMesh = CreatePlane(#PB_Any,35,20,1,1,3.5,2)
  bgMaterial = GetScriptMaterial(#PB_Any,"menuBackground")
  bgEntity = CreateEntity(#PB_Any,MeshID(bgMesh),MaterialID(bgMaterial),0,11,-55)
  RotateEntity(bgEntity,90,0,0)
  
  ; Title
  titleMesh = CreatePlane(#PB_Any,7.36,1.62,1,1,1,1)
  titleMaterial = GetScriptMaterial(#PB_Any,"menuTitle")
  titleEntity = CreateEntity(#PB_Any,MeshID(titleMesh),MaterialID(titleMaterial),0,2.5,-12)
  RotateEntity(titleEntity,90,0,180)
  
  CreateCamera(0,0,0,100,100)
  
EndMacro

; Destroy 3D menu elements
Macro DESTROY3DMENUELEMENTS()
  FreeEntity(bgEntity)
  FreeMaterial(bgMaterial)
  FreeMesh(bgMesh)
  FreeEntity(titleEntity)
  FreeMaterial(titleMaterial)
  FreeMesh(titleMesh)
  
  FreeCamera(0)
EndMacro

; Initialize menu screen and sprites
Macro INITSCREENANDSPRITES()
  If fullscreen = #True
    OpenScreen(screenWidth,screenHeight,32,"HoverRacers",#PB_Screen_SmartSynchronization)
  Else
    OpenWindow(0,0,0,screenWidth,screenHeight,"HoverRacers")
    OpenWindowedScreen(WindowID(0),0,0, screenWidth,screenHeight,0,0,0,#PB_Screen_SmartSynchronization)
  EndIf
  SetFrameRate(60)
  
  ; 3D archives
  Add3DArchive("meshes/", #PB_3DArchive_FileSystem)
  Add3DArchive("materials/", #PB_3DArchive_FileSystem)
  Add3DArchive("textures/", #PB_3DArchive_FileSystem)
  Add3DArchive("medias/", #PB_3DArchive_FileSystem)
  Add3DArchive("particles/", #PB_3DArchive_FileSystem)
  Add3DArchive("skies/sky.zip", #PB_3DArchive_Zip)
  Parse3DScripts()  
  
  ; Title background
  INIT3DMENUELEMENTS()
  
  ; Initialize menus
  ratio = screenHeight / 1200
  interleave = 64 * ratio
  CREATERESIZEDSPRITE("medias/menuarrow64.png",ratio,selectSprite)
  CREATERESIZEDSPRITE("medias/menuNewKey.png",ratio,boxSprite)
  CREATERESIZEDSPRITE("medias/menuKo.png",ratio,okSprite(0))
  CREATERESIZEDSPRITE("medias/menuOk.png",ratio,okSprite(1))
  CREATERESIZEDSPRITE("medias/menuLow.png",ratio,detailSprite(0))
  CREATERESIZEDSPRITE("medias/menuHigh.png",ratio,detailSprite(1))
  CREATERESIZEDSPRITE("medias/50trees.png",ratio,nbTreeSprite)
  CREATERESIZEDSPRITE("medias/menuWait.png",ratio,waitSprite)
  CREATERESIZEDSPRITE("medias/left.png",ratio*2,keySpr(0))
  CREATERESIZEDSPRITE("medias/right.png",ratio*2,keySpr(1))
  CREATERESIZEDSPRITE("medias/up.png",ratio*2,keySpr(2))
  CREATERESIZEDSPRITE("medias/button.png",ratio*2,keySpr(3))

  ; Initialize "specific" sprites: Nb.players, Ctrl...
  For i=1 To 4
    ; Nb. Players
    CREATERESIZEDSPRITE("medias/" + Str(i) + "pGame.png",ratio,nbPlSprite(i))
    ; players
    CREATERESIZEDSPRITE("medias/" + Str(i) + "up.png",ratio,playerSprite(i-1))
    ; Controls
    CREATECTRLSPRITE(i-1 , ratio, playerCtrlSprite(i-1) )
  Next i
  CREATERESIZEDSPRITE("medias/aiUp.png",ratio,playerSprite(4))
  
  ; Available resolutions
  ClearList(resolution())
  ExamineScreenModes()
  While NextScreenMode()
    ; We only keep 32bits, 60Hz, wider-than-high screen modes
    If ScreenModeDepth() = 32 And ScreenModeRefreshRate() = 60 And ScreenModeWidth() > ScreenModeHeight()
      AddElement(resolution())
      resolution()\width = ScreenModeWidth()
      resolution()\height = ScreenModeHeight()
      tmpStr = Str(ScreenModeWidth()) + "x" + Str(ScreenModeHeight())
      CREATESTRINGSPRITE(tmpStr,256,20,ratio,resolution()\numSprite)
    EndIf
  Wend
  
  ; Version
  tmpStr = "v" + #CURRENTVERSION
  CREATESTRINGSPRITE(tmpStr,64,20,ratio/2,versionSprite)
   
  ; Read menu infos
  Restore startMenu
  Read.i j
  While j <> #END_DATA
    Read.i menuPage(j)\nbItems
    
    For i = 0 To menuPage(j)\nbItems - 1
      Read.i menuPage(j)\itemList[i]\numItem
      Read.i menuPage(j)\itemList[i]\action
      Read.i menuPage(j)\itemList[i]\param
      Read.s nomSprite
      CREATERESIZEDSPRITE(nomSprite,ratio,menuPage(j)\itemList[i]\numSprite)
    Next i
    
    Read.i j
  Wend
  
  hOri = screenWidth/2 - 300*ratio
  vOri = screenHeight - 480*ratio
  
EndMacro

; Close menu screen
Macro DESTROYSCREEN()
  DESTROY3DMENUELEMENTS()
  CloseScreen()
  If fullscreen = #False
    CloseWindow(0)
  EndIf  
EndMacro

; Redefine controls (keyboard)
Macro GETNEWCONTROLS(numPlayer)  
  numKey=0
  Repeat
    RenderWorld()
    
    DisplayTransparentSprite(boxSprite,screenWidth/2 - SpriteWidth(boxSprite)/2,vOri)
    DisplayTransparentSprite(keySpr(numKey),screenWidth/2 - SpriteWidth(keySpr(numKey))/2,vOri+interleave*2)   
    
    ExamineKeyboard()
    ForEach key()
      If KeyboardReleased(key()\value)
        Select numKey
          Case 0
            controls(numPlayer)\key_left = key()\value
          Case 1
            controls(numPlayer)\key_right = key()\value
          Case 2
            controls(numPlayer)\key_up = key()\value
          Case 3
            controls(numPlayer)\key_fire = key()\value
        EndSelect 
        numKey+1
        Break
      EndIf
    Next key()
    
    FlipBuffers()
    If fullscreen = #False
      While WindowEvent(): Wend
    EndIf
    
  Until numKey=4
  CREATECTRLSPRITE(numPlayer, ratio, playerCtrlSprite(numPlayer) )
EndMacro


;************************************************************************************
;-                                 ---- Procedures ----
;************************************************************************************

; Terrain blendmaps management, from Comtois 
Procedure Clamp(*var.float, min.f, max.f)
  If *var\f < min
    *var\f = min
  ElseIf *var\f > max
    *var\f = max
  EndIf
EndProcedure

Procedure InitBlendMaps()
  Protected minHeight1.f,fadeDist1.f,minHeight2.f,fadeDist2.f
  Protected x.i,y.i,tx.i,ty.i,size.i
  Protected height.f, val.f
  
  minHeight1 = 0
  fadeDist1 = 15
  minHeight2 = 25
  fadeDist2 = 15
  
  For ty = #TerrainMiniY To #TerrainMaxiY
    For tx = #TerrainMiniX To #TerrainMaxiX
      Size = TerrainTileLayerMapSize(#NUMTERRAIN, tx, ty)
      For y = 0 To Size-1
        For x = 0 To Size-1
          Height = TerrainTileHeightAtPosition(#NUMTERRAIN, tx, ty, 1, x, y)
          
          val = (Height - minHeight1) / fadeDist1
          Clamp(@val, 0, 1)
          SetTerrainTileLayerBlend(#NUMTERRAIN, tx, ty, 1, x, y, val)
          
          val = (Height - minHeight2) / fadeDist2
          Clamp(@val, 0, 1)
          SetTerrainTileLayerBlend(#NUMTERRAIN, tx, ty, 2, x, y, val)
        Next
      Next
      UpdateTerrainTileLayerBlend(#NUMTERRAIN, tx, ty, 1)
      UpdateTerrainTileLayerBlend(#NUMTERRAIN, tx, ty, 2)
    Next
  Next  
EndProcedure  

; ************** end of terrain procs *************


; Keep an angle in the 0-360 range
Procedure.f wrapValue(angle.f)
  If angle < 0
    angle + 360
  ElseIf angle >=360
    angle-360
  EndIf

  ProcedureReturn angle
EndProcedure

; This procedure is from Comtois. Merci Comtois !
; Calcule une valeur progressive allant de la valeur actuelle à la valeur cible
Procedure.f curveValue(actuelle.f, Cible.f, P.f)
  If P > 1000.0
    P = 1000.0
  EndIf
  ProcedureReturn (actuelle + ( (Cible - actuelle) * P / 1000.0))
EndProcedure

; Create a camera for each player and split the screen accordingly
Procedure createPlayerCameras(nbPlayers.i)
  Protected i.i,value.i,numConfig.i, arrowMesh.i
  Protected numCam.i,x.i,y.i,width.i,height.i,visMask.i
  
  arrowMesh = LoadMesh(#PB_Any,"arrow.mesh")
  
  ; Find the correct camera configuration
  Restore cameraConfigs
  Repeat
    Read.i value
    If value = #NEWCAMERACONFIG
      Read.i numConfig
      If numConfig = nbPlayers
        ; Create a camera for each player
        For  i = 1 To nbPlayers
          Read.i numCam
          Read.i x
          Read.i y
          Read.i width
          Read.i height
          Read.i visMask
          
          playerCam(numCam)\cameraXpos = screenWidth * x / 100
          playerCam(numCam)\cameraYpos = screenHeight * y / 100
          playerCam(numCam)\cameraWidthPixel = screenWidth * width / 100
          playerCam(numCam)\cameraHeightPixel = screenHeight * height / 100
                    
          CreateCamera(numCam, x, y, width, height,visMask)
          CameraBackColor(numCam,$FF7755)
          CameraLocate(numCam,hovercraft(i-1)\x,hovercraft(i-1)\y + 50,hovercraft(i-1)\z)  
          playerCam(numCam)\cameraMode = #RearView
          playerCam(numCam)\numTargetHovercraft = i-1
          playerCam(numCam)\arrowEntity = CreateEntity(#PB_Any,MeshID(arrowMesh),#PB_Material_None,0,0,0,0,visMask)
          ScaleEntity(playerCam(numCam)\arrowEntity,0.5,0.5,0.5)          
        Next i
      EndIf
    EndIf
  Until numConfig = nbPlayers  
  
  FreeMesh(arrowMesh)
  
EndProcedure

; Create a given number of random trees
; (The tree mesh is chosen according to altitude)
Procedure createTrees(nbTrees.i)
  Protected i.i,numMesh.i
  Protected angle.f, scale1.f,scale2.f,scale3.f, tempEnt.i
  Protected posX.f,posY.f,posZ.f
  Protected Dim treeMesh.i(4)
  
  treeMesh(0) = LoadMesh(#PB_Any,"arbol_mort.mesh") ; Dead tree (in the desert areas)
  treeMesh(1) = LoadMesh(#PB_Any,"arbol_sec.mesh")  ; Dried up tree (low areas)
  treeMesh(2) = LoadMesh(#PB_Any,"arbol.mesh")      ; Standard tree (medium height)
  treeMesh(3) = LoadMesh(#PB_Any,"sapin.mesh")      ; Pine tree (high areas)
  
  For i= 1 To nbTrees
    posX = Random(900) - 450
    posZ = Random(900) - 450
    posY = TerrainHeight(#NUMTERRAIN,posX,posZ)-0.2
    numMesh = Round(posY / 10, #PB_Round_Down)
    If numMesh < 0
      numMesh = 0
    ElseIf numMesh > 3
      numMesh = 3
    EndIf
    
    ; Create the entity, rotate and scale it randomly so all trees don't look the same
    AddElement(treeEntity())
    treeEntity() = CreateEntity(#PB_Any,MeshID(treeMesh(numMesh)),#PB_Material_None,posX,posY,posZ)
    angle = Random(360)
    scale1 = (70 + Random(60))/100.0
    scale2 = (70 + Random(60))/100.0
    scale3 = (70 + Random(60))/100.0    
    RotateEntity(treeEntity(),-90,angle,0)
    ScaleEntity(treeEntity(),scale1,scale2,scale3)
    
    EntityPhysicBody(treeEntity(),#PB_Entity_StaticBody,99,1.0,1.0)  
  Next i
  
  FreeMesh(treeMesh(0))
  FreeMesh(treeMesh(1))
  FreeMesh(treeMesh(2))
  FreeMesh(treeMesh(3))
  
EndProcedure

; Create the bonus objects
Procedure createBonus()
  Protected i.i
  Protected planeMesh.i, bonusMat.i, bonusGlowMat.i
  
  planeMesh = CreatePlane(#PB_Any,2,2,1,1,1,1)
  bonusMat = GetScriptMaterial(#PB_Any,"bonus")
  bonusGlowMat = GetScriptMaterial(#PB_Any,"bonusGlow")
  
  For i = 0 To #NB_BONUS
    AddElement(bonus())
    bonus()\node = CreateNode(#PB_Any)
    bonus()\bonusEntity = CreateEntity(#PB_Any,MeshID(planeMesh),MaterialID(bonusMat))
    RotateEntity(bonus()\bonusEntity,-90,0,0)
    AttachNodeObject(bonus()\node,EntityID(bonus()\bonusEntity))
  
    bonus()\glow = CreateBillboardGroup(#PB_Any,MaterialID(bonusGlowMat),3,3)
    AddBillboard(#PB_Any,bonus()\glow,EntityX(bonus()\bonusEntity),EntityY(bonus()\bonusEntity),EntityZ(bonus()\bonusEntity))
    AttachNodeObject(bonus()\node,BillboardGroupID(bonus()\glow))
  
    bonus()\emitter = GetScriptParticleEmitter(#PB_Any,"bonusParticles")
    MoveParticleEmitter(bonus()\emitter,EntityX(bonus()\bonusEntity),EntityY(bonus()\bonusEntity),EntityZ(bonus()\bonusEntity))
    AttachNodeObject(bonus()\node,ParticleEmitterID(bonus()\emitter))
  Next i
  FreeMesh(planeMesh)
  
EndProcedure


; Create an hovercraft and initialize its position, friction, max thrust, etc. + entity and physics.
; (Hovercraft #0 is the player's one)
Procedure createHovercraft(id.i,team.i,playerType.i,nomMesh.s,posX.f, posZ.f, mass.f, restitution.f, friction.f, thrust.f, centerHeight.f)
  Protected numMat.i
  
  ; Hovercraft entity
  hovercraft(id)\numTeam = team
  numMat = GetScriptMaterial(#PB_Any,teamMaterial(hovercraft(id)\numTeam))
  hovercraft(id)\hovercraftMesh = LoadMesh(#PB_Any,"hovercraft.mesh")
  hovercraft(id)\hovercraftEntity = CreateEntity(#PB_Any,MeshID(hovercraft(id)\hovercraftMesh),MaterialID(numMat))
  EntityRenderMode(hovercraft(id)\hovercraftEntity,#PB_Entity_CastShadow)
  EntityPhysicBody(hovercraft(id)\hovercraftEntity,#PB_Entity_None)
  
  ; Hovercraft parameters
  hovercraft(id)\controlMode = playerType
  hovercraft(id)\thrust = thrust
  hovercraft(id)\radius = MeshRadius(hovercraft(id)\hovercraftMesh)*1.33
  hovercraft(id)\centerHeight = centerHeight
  hovercraft(id)\mass = mass
  hovercraft(id)\restitution = restitution
  hovercraft(id)\friction = friction
  hovercraft(id)\bonus = -1
  hovercraft(id)\x = posX
  hovercraft(id)\y = TerrainHeight(#NUMTERRAIN,posX,posZ)+1
  hovercraft(id)\z = posZ
  
  ; Main node
  hovercraft(id)\node = CreateNode(#PB_Any)
  AttachNodeObject(hovercraft(id)\node,EntityID(hovercraft(id)\hovercraftEntity))
  
  ; These nodes are used to get terrain height at different points of the hovercraft, according to its rotation
  hovercraft(id)\frontNode = CreateNode(#PB_Any,0,0,-hovercraft(id)\radius)
  hovercraft(id)\backNode = CreateNode(#PB_Any,0,0,hovercraft(id)\radius)
  hovercraft(id)\leftNode = CreateNode(#PB_Any,-hovercraft(id)\radius,0,0)
  hovercraft(id)\rightNode = CreateNode(#PB_Any,hovercraft(id)\radius,0,0)
  
  AttachNodeObject(hovercraft(id)\node,NodeID(hovercraft(id)\frontNode))
  AttachNodeObject(hovercraft(id)\node,NodeID(hovercraft(id)\backNode))
  AttachNodeObject(hovercraft(id)\node,NodeID(hovercraft(id)\leftNode))
  AttachNodeObject(hovercraft(id)\node,NodeID(hovercraft(id)\rightNode))
  
  ; Camera Node
  hovercraft(id)\cameraNode = CreateNode(#PB_Any,0,1,5)
  AttachNodeObject(hovercraft(id)\node,NodeID(hovercraft(id)\cameraNode))
  
  ; Physics entity for the hovercraft
  hovercraft(id)\physicsMesh = CreateSphere(#PB_Any,hovercraft(id)\radius * 0.8)
  hovercraft(id)\physicsEntity = CreateEntity(#PB_Any,MeshID(hovercraft(id)\physicsMesh),#PB_Material_None,posX,TerrainHeight(#NUMTERRAIN,posX,posZ)+1,posZ)
  EntityRenderMode(hovercraft(id)\physicsEntity,0)
  EntityPhysicBody(hovercraft(id)\physicsEntity,#PB_Entity_SphereBody,hovercraft(id)\mass,hovercraft(id)\restitution,hovercraft(id)\friction)
  HideEntity(hovercraft(id)\physicsEntity,#True)
  
EndProcedure


; Apply thrust and steering, and reposition an hovercraft
Procedure moveHovercraft(id.i ,forward.i, backward.i, left.i, right.i,fire.i)
  Protected xPos.f, yPos.f, zPos.f
  Protected frontHeight.f,backHeight.f,leftHeight.f,rightHeight.f
  Protected xAng.f,yAng.f, zAng.f
  Protected xSlide.f,zSlide.f
  Protected thrustAngle.f, thrust.f, thrustCorrection.f
  Protected i.i,j.i,temp.i
  
  ; Position the hovercraft and get its yaw
  xPos = EntityX(hovercraft(id)\physicsEntity)
  yPos = EntityY(hovercraft(id)\physicsEntity) - hovercraft(id)\radius
  zPos = EntityZ(hovercraft(id)\physicsEntity)
  yAng = NodeYaw(hovercraft(id)\node)
  
  ; The hovercraft can rotate left/right, even in the air
  If left = #True
    RotateNode(hovercraft(id)\node,0,wrapvalue(yAng+4),0)
  ElseIf right = #True
    RotateNode(hovercraft(id)\node,0,wrapvalue(yAng-4),0)
  EndIf
  
  ; If the player is on ground:
  ;   - its pitch/roll must change according to terrain slope;
  ;   - it can accelerate / deccelerate;
  If yPos < TerrainHeight(#NUMTERRAIN,xPos,zPos)
     
    ; Put the hovercraft on the ground
    yPos = TerrainHeight(#NUMTERRAIN,xPos,zPos)
  
    ; Positions of the front, back, left and right nodes
    frontHeight = TerrainHeight(#NUMTERRAIN,NodeX(hovercraft(id)\frontNode),NodeZ(hovercraft(id)\frontNode))
    backHeight  = TerrainHeight(#NUMTERRAIN,NodeX(hovercraft(id)\backNode),NodeZ(hovercraft(id)\backNode))
    leftHeight  = TerrainHeight(#NUMTERRAIN,NodeX(hovercraft(id)\leftNode),NodeZ(hovercraft(id)\leftNode))
    rightHeight = TerrainHeight(#NUMTERRAIN,NodeX(hovercraft(id)\rightNode),NodeZ(hovercraft(id)\rightNode))
    
    ; Quick hack to estimate hovercraft's angle
    xAng = (frontHeight - backHeight) * 30
    zAng = (rightHeight - leftHeight) * 30
    
    ; Update the vehicle's pitch & roll
    RotateEntity(hovercraft(id)\hovercraftEntity,xAng,0,0,#PB_Absolute)
    RotateEntity(hovercraft(id)\hovercraftEntity,0,0,zAng,#PB_Relative)
  
    ; Apply forward/backward movement
    If forward = #True
      thrustAngle = 270 - NodeYaw(hovercraft(id)\node)
      thrust = hovercraft(id)\thrust
    ElseIf backward = #True
      thrustAngle = 270 - NodeYaw(hovercraft(id)\node)
      thrust = -hovercraft(id)\thrust
    EndIf
    
    ; Adjust thrust according to pitch
    thrustCorrection = (1 - (xAng/30))
    If thrustCorrection < 0.0
      thrustCorrection = 0.0
    EndIf
    thrust * thrustCorrection
    ;Debug StrF(xpos,2)+" , "+StrF(zpos,2)
    ;Debug "Angle = " + StrF(xAng,2) + "° | Thrust factor = " + StrF((1 - (xAng/30)),2)
        
    ; Move the hovercraft
    DisableEntityBody(hovercraft(id)\physicsEntity,#False)
    ApplyEntityForce(hovercraft(id)\physicsEntity,thrust * Cos(Radian(thrustAngle)),0,thrust * Sin(Radian(thrustAngle)) )
    SetEntityAttribute(hovercraft(id)\physicsEntity, #PB_Entity_MaxVelocity, hovercraft(id)\thrust)
  EndIf
  
  ; Reposition the player object
  NodeLocate(hovercraft(id)\node,xPos,yPos + hovercraft(id)\centerHeight,zPos)
  hovercraft(id)\x = EntityX(hovercraft(id)\hovercraftEntity)
  hovercraft(id)\y = EntityY(hovercraft(id)\hovercraftEntity)
  hovercraft(id)\z = EntityZ(hovercraft(id)\hovercraftEntity)
  
  ; If the player has got an item
  If hovercraft(id)\bonus <> #NO_BONUS
    ; if the item is currently activated
    If hovercraft(id)\bonusTimeLeft > 0
      hovercraft(id)\bonusTimeLeft -1
      ; if the item's effect ran out
      If hovercraft(id)\bonusTimeLeft = 0
        Select hovercraft(id)\bonus
          Case #BONUS_TURBO
            hovercraft(id)\thrust - 5
            DetachNodeObject(hovercraft(id)\backNode,ParticleEmitterID(hovercraft(id)\bonusEffect))
            If IsParticleEmitter(hovercraft(id)\bonusEffect)
              FreeParticleEmitter(hovercraft(id)\bonusEffect)
            EndIf
            
          Case #BONUS_EXPLO  
            If IsParticleEmitter(hovercraft(id)\bonusEffect)
              FreeParticleEmitter(hovercraft(id)\bonusEffect)
            EndIf
            
        EndSelect
        hovercraft(id)\bonus = #NO_BONUS
      EndIf
    Else
      ; if the player activates the item
      If fire = #True
        Select hovercraft(id)\bonus
          Case #BONUS_TURBO
            hovercraft(id)\bonusTimeLeft = 1000
            hovercraft(id)\thrust + 5
            hovercraft(id)\bonusEffect = GetScriptParticleEmitter(#PB_Any,"turbo")
            AttachNodeObject(hovercraft(id)\backNode,ParticleEmitterID(hovercraft(id)\bonusEffect))
            
          Case #BONUS_CRATE
            For i = -3 To 3 Step 2
              AddElement(crateEntity())
              crateEntity() = CreateEntity(#PB_Any, MeshID(cubeMesh), MaterialID(crateMat))
              xPos = NEWXVALUE(hovercraft(id)\x,EntityYaw(hovercraft(id)\hovercraftEntity)+90,i)
              yPos = hovercraft(id)\y + 1
              zPos = NEWZVALUE(hovercraft(id)\z,EntityYaw(hovercraft(id)\hovercraftEntity)+90,i)
              Debug xPos
              Debug yPos
              Debug zPos
              EntityLocate(crateEntity(),xPos,yPos,zPos)
              EntityPhysicBody(crateEntity(), #PB_Entity_BoxBody, 0.5)
            Next i
            ; If there's too much crates, delete the 4 oldest ones
            If ListSize(crateEntity()) > #NB_CRATESMAX
              FirstElement(crateEntity())
              FreeEntity(crateEntity()):DeleteElement(crateEntity())
              FirstElement(crateEntity())
              FreeEntity(crateEntity()):DeleteElement(crateEntity())
              FirstElement(crateEntity())
              FreeEntity(crateEntity()):DeleteElement(crateEntity())
              FirstElement(crateEntity())
              FreeEntity(crateEntity()):DeleteElement(crateEntity())
              LastElement(crateEntity())
            EndIf
            hovercraft(id)\bonusTimeLeft = 1
            
          Case #BONUS_EXPLO
            thrustAngle = 270 - NodeYaw(hovercraft(id)\node)
            SetEntityAttribute(hovercraft(id)\physicsEntity, #PB_Entity_MaxVelocity, 999999)
            ApplyEntityImpulse(hovercraft(id)\physicsEntity,10 * Cos(Radian(thrustAngle)),20,10 * Sin(Radian(thrustAngle)) )
            
            ; Push nearby opponents
            For j = 0 To nbHovercrafts
              If j = id
                Continue
              EndIf
              
              DISTANCE2(hovercraft(j)\x,hovercraft(j)\y,hovercraft(j)\z,xPos,yPos,Zpos,thrust)
              If thrust < 50
                thrustAngle = ATan2(xPos , zPos)
                SetEntityAttribute(hovercraft(j)\physicsEntity, #PB_Entity_MaxVelocity, 999999)
                ApplyEntityImpulse(hovercraft(j)\physicsEntity,(-50/thrust) * Cos(thrustAngle),2,(-50/thrust) * Sin(thrustAngle) )
                
              EndIf
            Next j
            
            hovercraft(id)\bonusEffect = GetScriptParticleEmitter(#PB_Any,"explosion")
            MoveParticleEmitter(hovercraft(id)\bonusEffect,hovercraft(id)\x,hovercraft(id)\y,hovercraft(id)\z)
            hovercraft(id)\bonusTimeLeft = 200
            
          Case #BONUS_FLASH
            ; Paralyse nearby opponents 
            For j = 0 To nbHovercrafts
              If j = id
                Continue
              EndIf
              
              DISTANCE2(hovercraft(j)\x,hovercraft(j)\y,hovercraft(j)\z,xPos,yPos,Zpos,thrust)
              If thrust < 50
                hovercraft(j)\paralysed = 1000
                hovercraft(j)\malusEffect = GetScriptParticleEmitter(#PB_Any,"shortSmoke")
                AttachNodeObject(hovercraft(j)\node,ParticleEmitterID(hovercraft(j)\malusEffect))
                hovercraft(j)\malusEffect2 = GetScriptParticleEmitter(#PB_Any,"sparkle")
                AttachNodeObject(hovercraft(j)\node,ParticleEmitterID(hovercraft(j)\malusEffect2))
              EndIf
            Next j
            hovercraft(id)\bonusTimeLeft = 1
            

        EndSelect
      EndIf ; if keyboardPushed...
    EndIf ; else...
  EndIf ; if bonus <> #NO_BONUS
  
EndProcedure


Procedure controlHovercrafts()
  Protected id.i, i.i
  Protected forward.b, backward.b, left.b, right.b,fire.b
  Protected targetHeading.i,result.i
  
  For id = 0 To nbHovercrafts
    forward = #False:backward=#False:left=#False:right=#False:fire=#False
    
    ; Paralysed
    If hovercraft(id)\paralysed > 0
      hovercraft(id)\paralysed - 1
      If hovercraft(id)\paralysed = 0
        If IsParticleEmitter(hovercraft(id)\malusEffect)
          DetachNodeObject(hovercraft(id)\backNode,ParticleEmitterID(hovercraft(id)\malusEffect))
          FreeParticleEmitter(hovercraft(id)\malusEffect)        
        EndIf
        If IsParticleEmitter(hovercraft(id)\malusEffect2)
          DetachNodeObject(hovercraft(id)\backNode,ParticleEmitterID(hovercraft(id)\malusEffect2))
          FreeParticleEmitter(hovercraft(id)\malusEffect2)
        EndIf
      EndIf
    Else
      ; Human players
      If hovercraft(id)\controlMode = #PLAYER_HUMAN
        If KeyboardPushed(controls(id)\key_up)
          forward = #True
        ElseIf KeyboardPushed(controls(id)\key_down)
          backward=#True
        EndIf    
        If KeyboardPushed(controls(id)\key_left)
          left = #True
        ElseIf KeyboardPushed(controls(id)\key_right)
          right=#True
        EndIf
        
        ; Activate special item (turbo, etc.)
        If KeyboardPushed(controls(id)\key_fire)
          fire=#True
        EndIf
        
        ; Camera view
        If KeyboardReleased(controls(id)\key_changeCamView)
          playerCam(id)\cameraMode = (playerCam(id)\cameraMode + 1) % #END_VIEWLIST
        EndIf
        
      ElseIf hovercraft(id)\controlMode = #PLAYER_CPU
        ; Opponents AI (just steer towards the checkpoint And move forward)
        forward = #True
        targetHeading = wrapValue(ANGLE2CHECKPOINT(id) - NodeYaw(hovercraft(id)\node))
        If targetHeading < 180
          left=#True
          right=#False
        Else
          left=#False
          right=#True
        EndIf
        
        ; If the AI's got a bonus, choose what to do.
        If hovercraft(id)\bonus <> #NO_BONUS And Random(100) = 0
          Select hovercraft(id)\bonus
            Case #BONUS_TURBO
              fire=#True
              
            Case #BONUS_EXPLO
              If targetHeading =< 1 Or targetHeading => 359
                DISTANCE2(hovercraft(id)\ptrTarget\x,0,hovercraft(id)\ptrTarget\z,hovercraft(id)\x,0,hovercraft(id)\z,result)
                If result > 7000
                  fire = #True
                EndIf
              EndIf
              
            Case #BONUS_CRATE
              fire=#True
              
            Case #BONUS_FLASH
              i = Random(nbHovercrafts)
              If i<> id
                DISTANCE2(hovercraft(i)\x,hovercraft(i)\y,hovercraft(i)\z,hovercraft(id)\x,hovercraft(id)\y,hovercraft(id)\z,result)
                If result < 50
                  fire = #True
                EndIf
              EndIf
              
          EndSelect
        EndIf ; if bonus > -1...
        
      EndIf ; AI hovercrafts
    EndIf ; if paralysed...
    
    moveHovercraft(id,forward,backward,left,right,fire)
  Next id
  
EndProcedure

; Reposition the bonus Halfway between old and new position
Procedure repositionBonus(oldX.f, oldZ.f, newX.f, newZ.f)
  Protected i.i
  Protected posX.f = oldX + (newX - oldX) / 2.0
  Protected posZ.f = oldZ + (newZ - oldZ) / 2.0
  Protected angle.f = Degree(ATan2(newZ - oldZ,newX - oldX))
  
  ForEach bonus()
    bonus()\hidden = #False
    bonus()\x = NEWXVALUE(posX,angle+90,i*5)
    bonus()\z = NEWZVALUE(posZ,angle+90,i*5)
    bonus()\y = TerrainHeight(#NUMTERRAIN,bonus()\x,bonus()\z)+1.5
    NodeLocate(bonus()\node,bonus()\x,bonus()\y,bonus()\z)
    i+1
  Next bonus()
  
EndProcedure

; Check if an hovercraft touched a bonus
Procedure manageBonus()
  Protected i.i
  Protected dist.f
  
  ForEach bonus()
    RotateEntity(bonus()\bonusEntity,0,0,1.5,#PB_Relative)
      
    If bonus()\hidden = #True
      Continue
    EndIf  
    For i = 0 To nbHovercrafts
      If hovercraft(i)\bonus <> #NO_BONUS
        Continue
      EndIf
      
      DISTANCE2(bonus()\x,bonus()\y,bonus()\z,hovercraft(i)\x,hovercraft(i)\y,hovercraft(i)\z,dist)
      If dist < 2.5
        bonus()\hidden = #True
        NodeLocate(bonus()\node,-999,-999,-999) 
        hovercraft(i)\bonus = Random(3)
        
        Break
      EndIf

    Next i    
  Next bonus()
  
EndProcedure


; Animate the checkpoint and check if an hovercraft reached it.
Procedure manageCheckpoint(*ptrCheckPoint.checkpoint_struct)
  Protected i.i, j.i
  Protected posX.f = *ptrCheckPoint\x + *ptrCheckPoint\radius * Cos(Radian(ElapsedMilliseconds()*2))
  Protected posZ.f = *ptrCheckPoint\z + *ptrCheckPoint\radius * Sin(Radian(ElapsedMilliseconds()*2))
  Protected dist.f
  
  NodeLocate(*ptrCheckPoint\node,posX,TerrainHeight(#NUMTERRAIN,posX,posZ)+ *ptrCheckPoint\y,posZ)
  
  ; If an hovercraft reach the checkpoint, change its position
  For i=0 To nbHovercrafts
    DISTANCE2(*ptrCheckPoint\x,0,*ptrCheckPoint\z,hovercraft(i)\x,0,hovercraft(i)\z,dist)
    If dist < *ptrCheckPoint\radius * *ptrCheckPoint\radius
      
      ; Increase and redraw score
      score(hovercraft(i)\numTeam) + 10
      DRAWSCORESPRITE(hovercraft(i)\numTeam)
      If score(hovercraft(i)\numTeam) >= scoreLimit
        hovercraft(i)\controlMode = #PLAYER_CPU
        hovercraft(i)\bonus = #NO_BONUS
        HideParticleEmitter(*ptrCheckPoint\particle,#True)
        *ptrCheckPoint\radius = 0 ; no one can attain it
        For j=0 To nbPlayers-1
          If hovercraft(playerCam(j)\numTargetHovercraft)\numTeam <> hovercraft(i)\numTeam
            playerCam(j)\numTargetHovercraft = i
          EndIf
          If playerCam(j)\cameraMode <> #WinnerView
            playerCam(j)\cameraMode = #WinnerView
            playerCam(j)\cameraAngle = Random(360)
          EndIf
        Next j
        For j = 0 To nbHovercrafts
          If hovercraft(j)\numTeam <> hovercraft(i)\numTeam
            hovercraft(j)\controlMode = #PLAYER_NONE
          Else
            hovercraft(j)\controlMode = #PLAYER_CPU
            hovercraft(j)\bonus = #NO_BONUS
            
            AddElement(effectBoard())
            effectBoard() = CreateBillboardGroup(#PB_Any,MaterialID(cupMat),0.75,0.75)
            AddBillboard(#PB_Any,effectBoard(),0,1,0)
            AttachNodeObject(hovercraft(j)\node,BillboardGroupID(effectBoard()) )
            
          EndIf
        Next j
        ForEach bonus()
          bonus()\hidden = #True
          NodeLocate(bonus()\node,-999,-999,-999)
        Next bonus()
        CREATERESIZEDSPRITE("medias/winner"+Str(hovercraft(i)\numTeam)+".png",screenHeight / 1200.0,victorySprite)

      Else            
        ; New position
        *ptrCheckPoint\x = Random(900) - 450
        *ptrCheckPoint\z = Random(900) - 450

        ; Reposition bonus
        repositionBonus(hovercraft(i)\x,hovercraft(i)\z,*ptrCheckPoint\x,*ptrCheckPoint\z)
        
        ; All hovercrafts get their new target
        For j = 0 To nbHovercrafts
          hovercraft(j)\ptrTarget = *ptrCheckPoint
        Next j
        
      EndIf
      Break
    EndIf  
  Next i
  
EndProcedure


; Position the camera
Procedure manageCamera(numCamMax.i)
  Protected posX.f, posY.f, posZ.f
  Protected i.i
  
  For i = 0 To numCamMax - 1
    ; Compute camera position and angle
    Select playerCam(i)\cameraMode
  
      Case #FrontView
        playerCam(i)\cameraAngle = CurveValue(playerCam(i)\cameraAngle, NodeYaw(hovercraft(playerCam(i)\numTargetHovercraft)\node), 100)
        posX = CurveValue(CameraX(i), NEWXVALUE(NodeX(hovercraft(playerCam(i)\numTargetHovercraft)\node), playerCam(i)\cameraAngle, 6), 100)
        posY = CurveValue(CameraY(i), NodeY(hovercraft(playerCam(i)\numTargetHovercraft)\node) + 3, 100)
        posZ = CurveValue(CameraZ(i), NEWZVALUE(NodeZ(hovercraft(playerCam(i)\numTargetHovercraft)\node), playerCam(i)\cameraAngle, 6), 100)
  
      Case #TopView
        playerCam(i)\cameraAngle = CurveValue(playerCam(i)\cameraAngle, NodeYaw(hovercraft(playerCam(i)\numTargetHovercraft)\node) + 180, 100)
        posX = CurveValue(CameraX(i), NEWXVALUE(NodeX(hovercraft(playerCam(i)\numTargetHovercraft)\node), playerCam(i)\cameraAngle, 4), 30)
        posY = CurveValue(CameraY(i), NodeY(hovercraft(playerCam(i)\numTargetHovercraft)\node) + 30, 30)
        posZ = CurveValue(CameraZ(i), NEWZVALUE(NodeZ(hovercraft(playerCam(i)\numTargetHovercraft)\node), playerCam(i)\cameraAngle, 4), 30)
  
      Case #RearView
        playerCam(i)\cameraAngle = CurveValue(playerCam(i)\cameraAngle, NodeYaw(hovercraft(playerCam(i)\numTargetHovercraft)\node) + 180, 100)
        posX = CurveValue(CameraX(i), NodeX(hovercraft(playerCam(i)\numTargetHovercraft)\cameraNode), 100)
        posZ = CurveValue(CameraZ(i), NodeZ(hovercraft(playerCam(i)\numTargetHovercraft)\cameraNode), 100)
        posY = CurveValue(CameraY(i), NodeY(hovercraft(playerCam(i)\numTargetHovercraft)\node) + 1, 100)
        If posY < TerrainHeight(#NUMTERRAIN,posX,posZ) + 1
          posY = TerrainHeight(#NUMTERRAIN,posX,posZ) + 1
        EndIf
       
      Case #SideView
        playerCam(i)\cameraAngle = CurveValue(playerCam(i)\cameraAngle, NodeYaw(hovercraft(playerCam(i)\numTargetHovercraft)\node) + 90, 100)
        posX = CurveValue(CameraX(i), NEWXVALUE(NodeX(hovercraft(playerCam(i)\numTargetHovercraft)\node), playerCam(i)\cameraAngle, 8), 100)
        posY = CurveValue(CameraY(i), NodeY(hovercraft(playerCam(i)\numTargetHovercraft)\node) + 4, 100)
        posZ = CurveValue(CameraZ(i), NEWZVALUE(NodeZ(hovercraft(playerCam(i)\numTargetHovercraft)\node), playerCam(i)\cameraAngle, 8), 100)
  
      Case #WinnerView
        HideEntity(playerCam(i)\arrowEntity,#True)
        playerCam(i)\cameraAngle + 1
        posX = CurveValue(CameraX(i), NEWXVALUE(NodeX(hovercraft(playerCam(i)\numTargetHovercraft)\node), playerCam(i)\cameraAngle, 5), 100)
        posY = CurveValue(CameraY(i), NodeY(hovercraft(playerCam(i)\numTargetHovercraft)\node) + 3, 100)
        posZ = CurveValue(CameraZ(i), NEWZVALUE(NodeZ(hovercraft(playerCam(i)\numTargetHovercraft)\node), playerCam(i)\cameraAngle, 5), 100)
  
    EndSelect
    
    CameraLocate(i, posX, posY, posZ)
    CameraLookAt(i, NodeX(hovercraft(playerCam(i)\numTargetHovercraft)\node), NodeY(hovercraft(playerCam(i)\numTargetHovercraft)\node), NodeZ(hovercraft(playerCam(i)\numTargetHovercraft)\node))
    
    ; Display hud (3D)
    MoveCamera(i,0,1.60,-5)
    EntityLocate(playerCam(i)\arrowEntity,CameraX(i),CameraY(i),CameraZ(i))
    RotateEntity(playerCam(i)\arrowEntity,30,ANGLE2CHECKPOINT(playerCam(i)\numTargetHovercraft),0)
    MoveCamera(i,0,-1.60,5)    
  Next i
    
EndProcedure


;- --- Game procedure ---
Procedure playGame()
  Protected i.i,j.i
  Protected light.i, skymesh.i, skybox.i
  Protected tx.i, ty.i,imported.b
  Protected posX.f, posZ.f, radius.f
  Protected fpsSprite.i, fpsTimer.i
  Protected Dim countSprite.i(3)
  Protected showPhysicBody.b, showFps.b
  Protected x.i,y.i,w.f
  
  ;- Init environnement and objects
  ; Lighting
  light = CreateLight(#PB_Any ,$FFFFFF, 500, 1000, 500,#PB_Light_Directional)
  LightColor(light, $555555, #PB_Light_SpecularColor)
  LightDirection(light, 0.55, -0.5, -0.75)
  AmbientColor($222222)
  WorldShadows(#PB_Shadow_Modulative)
  Fog($C2AF80,20,10,1000) ; a little blueish fog increase the depth perception
  
  ; Skybox
  skymesh = LoadMesh(#PB_Any,"skybox.mesh")
  skybox = CreateEntity(#PB_Any,MeshID(skymesh),#PB_Material_None)
  RotateEntity(skybox,90,0,0)
  ScaleEntity(skybox,10000,10000,10000)
  FreeMesh(skymesh)
  
  ; Terrain definition
  SetupTerrains(LightID(light), 200, #PB_Terrain_NormalMapping)
  CreateTerrain(#NUMTERRAIN, Pow(2,terrainDetail)+1, 1000, 50, 3, "HoverRacers"+Str(terrainDetail), "dat")
  AddTerrainTexture(#NUMTERRAIN,  0, 10, "sand.jpg", "sand_n.jpg")
  AddTerrainTexture(#NUMTERRAIN,  1,  20, "grass.jpg", "grass_n.jpg")
  AddTerrainTexture(#NUMTERRAIN,  2, 30, "rock.jpg",  "rock_n.jpg")
  
  ; Build terrains
  For ty = #TerrainMiniY To #TerrainMaxiY
    For tx = #TerrainMiniX To #TerrainMaxiX
      imported = DefineTerrainTile(#NUMTERRAIN, tx, ty, "heightmap.png", ty % 2, tx % 2)  
    Next
  Next
  BuildTerrain(#NUMTERRAIN)
  
  If imported = #True
    InitBlendMaps() 
    UpdateTerrain(#NUMTERRAIN)
    SaveTerrain(#NUMTERRAIN, #False)
  EndIf  
  TerrainPhysicBody(#NUMTERRAIN,0.1,2.0)
  
  ; Hovercrafts
  For i = 0 To nbPlayers-1
    For j = 0 To #NB_TEAMS
      If teamConf(j,nbPlayers)\players & Int(Pow(2,i)) > 0
        createHovercraft(i,j,#PLAYER_HUMAN,"hovercraft.mesh",-3 + 2*i,150,1,0.1,2.0,15,0.4)
      EndIf
    Next j
  Next i
  
  radius = 5: nbHovercrafts = nbPlayers-1
  For j = 0 To #NB_TEAMS
    For i = 1 To teamConf(j,nbPlayers)\nbAi
      nbHovercrafts+1
      posX = radius * Cos(Radian(nbHovercrafts * 36))
      posZ = 150 + radius * Sin(Radian(nbHovercrafts * 36))
      radius + 0.5
      
      createHovercraft(nbHovercrafts,j,#PLAYER_CPU,"hovercraft.mesh",posX,posZ,1,0.1,2.0,14.5,0.4)  ; opponents (slightly slower)
    Next i
  Next j
    
  ; Cameras
  createPlayerCameras(nbPlayers)
  
  ; Crates
  cubeMesh = CreateCube(#PB_Any,1)
  crateTexture = LoadTexture(#PB_Any,"crate.png")
  crateMat = CreateMaterial(#PB_Any,TextureID(crateTexture))
  
  cupMat = GetScriptMaterial(#PB_Any,"cup")
  
  ; Trees
  createTrees(nbTrees)
  
  ; Checkpoint
  currentCheckpoint\particle = GetScriptParticleEmitter(#PB_Any,"flareFountain")
  currentCheckpoint\x = 0
  currentCheckpoint\z = -100
  currentCheckpoint\radius = 3
  currentCheckpoint\node = CreateNode(#PB_Any)
  AttachNodeObject(currentCheckpoint\node,ParticleEmitterID(currentCheckpoint\particle))
  For i = 0 To nbHovercrafts
    hovercraft(i)\ptrTarget = @currentCheckpoint
  Next i
  
  ; Bonus
  createBonus()
  repositionBonus(0,0,currentCheckpoint\x,currentCheckpoint\z)
  
  bonusIcon(#BONUS_TURBO) = LoadSprite(#PB_Any,"medias/item-turbo.png")
  bonusIcon(#BONUS_CRATE) = LoadSprite(#PB_Any,"medias/item-crate.png")
  bonusIcon(#BONUS_EXPLO) = LoadSprite(#PB_Any,"medias/item-bomb.png")
  bonusIcon(#BONUS_FLASH) = LoadSprite(#PB_Any,"medias/item-flash.png")
  bonusIcon(#BONUS_MISSILE) = LoadSprite(#PB_Any,"medias/item-missile.png")
  
  ; Score sprites
  For i = 0 To #NB_TEAMS
    score(i) = 0
    scoreSprite(i) = CreateSprite(#PB_Any,64,20)
    DRAWSCORESPRITE(i)
  Next i
  
  ; FPS sprite
  fpsSprite = CreateSprite(#PB_Any,64,16)
  
  ; Countdown sprites
  For i = 0 To 2
    CREATERESIZEDSPRITE("medias/count" + Str(i+1) + ".png",screenHeight / 1200.0,countSprite(i))
  Next i
    
  ; On your marks...
  EnableWorldPhysics(#False)
  For i=299 To 0 Step-1
    manageCheckpoint(@currentCheckpoint)
    controlHovercrafts()
    ManageCamera(nbPlayers)
    RenderWorld()
    
    j = Round(i/100, #PB_Round_Down)
    DisplayTransparentSprite(countSprite(j),screenWidth/2 - SpriteWidth(countSprite(j))/2, screenHeight/2 - SpriteHeight(countSprite(j))/2) 
    FlipBuffers()
    
    If fullscreen = #False
      While WindowEvent(): Wend
    EndIf    
  Next i
  For i = 0 To 2
    FreeSprite(countSprite(i))
  Next i  
  EnableWorldPhysics(#True)
  
  ;- - Main loop -
  showPhysicBody = #False
  Repeat
    
    ;- Controls
    ExamineKeyboard()
      
    ; Display physic body
    If KeyboardReleased(#PB_Key_F5)
      showPhysicBody = 1 - showPhysicBody
      If showPhysicBody = #True
        WorldDebug(#PB_World_DebugBody)
      Else
        WorldDebug(#PB_World_DebugNone)
      EndIf
    EndIf
  
    ;Change camera target
    If KeyboardReleased(#PB_Key_F6)
      playerCam(0)\numTargetHovercraft = (playerCam(0)\numTargetHovercraft + 1) % (nbHovercrafts + 1)
    EndIf
    
    ; Display FPS
    If KeyboardReleased(#PB_Key_F12)
      showFps = 1 - showFps
    EndIf
    
    ;- Checkpoint
    manageCheckpoint(@currentCheckpoint)
    
    ;- Move the hovercrafts
    controlHovercrafts()
    
    ;- Move the cameras
    ManageCamera(nbPlayers)
    
    ;- RenderWorld
    RenderWorld()
    
    ;- Bonus
    manageBonus()  
    
    ;- Display scores (2D)
    For i = 0 To #NB_TEAMS
      If teamConf(i,nbPlayers)\players <> 0 Or teamConf(i,nbPlayers)\nbAi <> 0
        DisplayTransparentSprite(scoreSprite(i),10+i*80,screenHeight - 30)
      EndIf
    Next i
    For i=1 To nbPlayers
      If hovercraft(i-1)\controlMode = #PLAYER_HUMAN And hovercraft(i-1)\bonus > -1
        DisplaySprite(bonusIcon(hovercraft(i-1)\bonus),playerCam(i-1)\cameraXpos + playerCam(i-1)\cameraWidthPixel - 100,playerCam(i-1)\cameraYpos + 10)
      EndIf
    Next i
    
    If IsSprite(victorySprite)
      DisplayTransparentSprite(victorySprite,ScreenWidth/2 - SpriteWidth(victorySprite)/2,screenHeight/2 - SpriteHeight(victorySprite)/2 )
    EndIf
    
    ; If we're in full screen, display FPS; if not, manage windows events
    If showFps = #True
      If ElapsedMilliseconds() - fpsTimer > 1000
        StartDrawing(SpriteOutput(fpsSprite))
        DrawText(0,0,Str(Engine3DFrameRate(#PB_Engine3D_Current))+ " FPS")
        StopDrawing()
        fpsTimer = ElapsedMilliseconds()
      EndIf
      DisplayTransparentSprite(fpsSprite,950,0) 
    EndIf
    If fullscreen = #False
      While WindowEvent(): Wend
    EndIf
    
    FlipBuffers()
  Until KeyboardReleased(#PB_Key_Escape)
  
  ;- Free resources before exiting
  FreeLight(light)
  Fog($000000,0,0,10000) ; no fog
  
  FreeEntity(skybox)
  FreeTerrain(#NUMTERRAIN)
  
  ForEach treeEntity()
    FreeEntity(treeEntity())
  Next treeEntity()
  ClearList(treeEntity())
  
  ForEach crateEntity()
    FreeEntity(crateEntity())
  Next crateEntity()
  ClearList(crateEntity())
  
  ForEach effectBoard()
    FreeBillboardGroup(effectBoard())
  Next effectBoard()
  ClearList(effectBoard())

  For i = 0 To nbHovercrafts 
    FreeEntity(hovercraft(i)\hovercraftEntity)
    FreeMesh(hovercraft(i)\hovercraftMesh)
    FreeEntity(hovercraft(i)\physicsEntity) 
    FreeMesh(hovercraft(i)\physicsMesh) 
    
    If IsParticleEmitter(hovercraft(i)\bonusEffect)
      FreeParticleEmitter(hovercraft(i)\bonusEffect)        
    EndIf
    If IsParticleEmitter(hovercraft(i)\bonusEffect2)
      FreeParticleEmitter(hovercraft(i)\bonusEffect2)
    EndIf
    If IsParticleEmitter(hovercraft(i)\malusEffect)
      FreeParticleEmitter(hovercraft(i)\malusEffect)        
    EndIf
    If IsParticleEmitter(hovercraft(i)\malusEffect2)
      FreeParticleEmitter(hovercraft(i)\malusEffect2)
    EndIf

    FreeNode(hovercraft(i)\cameraNode)
    FreeNode(hovercraft(i)\frontNode)
    FreeNode(hovercraft(i)\backNode)
    FreeNode(hovercraft(i)\leftNode)
    FreeNode(hovercraft(i)\rightNode)
    FreeNode(hovercraft(i)\node)    
  Next i
  
  FreeParticleEmitter(currentCheckpoint\particle)
  FreeNode(currentCheckpoint\node)
  
  ForEach bonus()
    FreeParticleEmitter(bonus()\emitter)
    FreeBillboardGroup(bonus()\glow)
    FreeEntity(bonus()\bonusEntity)
    FreeNode(bonus()\node)
  Next bonus()
  ClearList(bonus())
  
  For i=0 To nbPlayers-1
    FreeEntity(playerCam(i)\arrowEntity)
    FreeCamera(i)
  Next i
  
  For i=#BONUS_TURBO To #BONUS_MISSILE
    FreeSprite(bonusIcon(i))
  Next i   
  For i = 0 To #NB_TEAMS
    FreeSprite(scoreSprite(i))
  Next i
  FreeSprite(fpsSprite)
  If IsSprite(victorySprite)
    FreeSprite(victorySprite)
    victorySprite = 0
  EndIf
  
EndProcedure

Re: Hover Racers

Publié : lun. 17/déc./2012 17:58
par kelebrindae
Et la suite:

Code : Tout sélectionner

;- --- Menu procs ---
; Read preferences file
Procedure readInifile()
  Protected iniFileName.s = "gameSettings.ini"
  
  ; Read content
  OpenPreferences(iniFileName)
 
  screenWidth  = ReadPreferenceLong("ScreenWidth", 800)  
  screenHeight = ReadPreferenceLong("ScreenHeight", 600)
  fullscreen   = ReadPreferenceLong("FullScreen", 0)
  
  nbPlayers    = ReadPreferenceLong("NbPlayers", 1)
  terrainDetail= ReadPreferenceLong("TerrainDetail", 10)
  nbTrees      = ReadPreferenceLong("NbTrees", 100)
  
  ; Controls
  controls(0)\key_changeCamView = ReadPreferenceLong("Player1_cam", #PB_Key_F1)
  controls(0)\key_up = ReadPreferenceLong("Player1_up", #PB_Key_Up)
  controls(0)\key_left = ReadPreferenceLong("Player1_left", #PB_Key_Left)
  controls(0)\key_right = ReadPreferenceLong("Player1_right", #PB_Key_Right)
  controls(0)\key_fire = ReadPreferenceLong("Player1_fire", #PB_Key_Space)

  controls(1)\key_changeCamView = ReadPreferenceLong("Player2_cam", #PB_Key_F2)
  controls(1)\key_up = ReadPreferenceLong("Player2_up", #PB_Key_S)
  controls(1)\key_left = ReadPreferenceLong("Player2_left", #PB_Key_Z)
  controls(1)\key_right = ReadPreferenceLong("Player2_right", #PB_Key_C)
  controls(1)\key_fire = ReadPreferenceLong("Player2_fire", #PB_Key_LeftControl)

  controls(2)\key_changeCamView = ReadPreferenceLong("Player3_cam", #PB_Key_F3)
  controls(2)\key_up = ReadPreferenceLong("Player3_up", #PB_Key_O)
  controls(2)\key_left = ReadPreferenceLong("Player3_left", #PB_Key_K)
  controls(2)\key_right = ReadPreferenceLong("Player3_right", #PB_Key_SemiColon)
  controls(2)\key_fire = ReadPreferenceLong("Player3_fire", #PB_Key_RightControl)

  controls(3)\key_changeCamView = ReadPreferenceLong("Player4_cam", #PB_Key_F4)
  controls(3)\key_up = ReadPreferenceLong("Player4_up", #PB_Key_Pad8)
  controls(3)\key_left= ReadPreferenceLong("Player4_left", #PB_Key_Pad4)
  controls(3)\key_right = ReadPreferenceLong("Player4_right", #PB_Key_Pad6)
  controls(3)\key_fire = ReadPreferenceLong("Player4_fire", #PB_Key_PadEnter)

  ; Config for 1 player game
  teamConf(0,1)\players = ReadPreferenceLong("Team1_1players_humans",%0001)
  teamConf(0,1)\nbAi    = ReadPreferenceLong("Team1_1players_AI",0)
  teamConf(1,1)\players = ReadPreferenceLong("Team2_1players_humans",0)
  teamConf(1,1)\nbAi    = ReadPreferenceLong("Team2_1players_AI",1)
  teamConf(2,1)\players = ReadPreferenceLong("Team3_1players_humans",0)
  teamConf(2,1)\nbAi    = ReadPreferenceLong("Team3_1players_AI",1)
  teamConf(3,1)\players = ReadPreferenceLong("Team4_1players_humans",0)
  teamConf(3,1)\nbAi    = ReadPreferenceLong("Team4_1players_AI",1)
  teamConf(4,1)\players = ReadPreferenceLong("Team5_1players_humans",0)
  teamConf(4,1)\nbAi    = ReadPreferenceLong("Team5_1players_AI",1)
  ; Config for 2 players game
  teamConf(0,2)\players = ReadPreferenceLong("Team1_2players_humans",%0001)
  teamConf(0,2)\nbAi    = ReadPreferenceLong("Team1_2players_AI",0)
  teamConf(1,2)\players = ReadPreferenceLong("Team2_2players_humans",%0010)
  teamConf(1,2)\nbAi    = ReadPreferenceLong("Team2_2players_AI",0)
  teamConf(2,2)\players = ReadPreferenceLong("Team3_2players_humans",0)
  teamConf(2,2)\nbAi    = ReadPreferenceLong("Team3_2players_AI",1)
  teamConf(3,2)\players = ReadPreferenceLong("Team4_2players_humans",0)
  teamConf(3,2)\nbAi    = ReadPreferenceLong("Team4_2players_AI",1)
  teamConf(4,2)\players = ReadPreferenceLong("Team5_2players_humans",0)
  teamConf(4,2)\nbAi    = ReadPreferenceLong("Team5_2players_AI",1)
  ; Config for 3 players game
  teamConf(0,3)\players = ReadPreferenceLong("Team1_3players_humans",%0001)
  teamConf(0,3)\nbAi    = ReadPreferenceLong("Team1_3players_AI",0)
  teamConf(1,3)\players = ReadPreferenceLong("Team2_3players_humans",%0010)
  teamConf(1,3)\nbAi    = ReadPreferenceLong("Team2_3players_AI",0)
  teamConf(2,3)\players = ReadPreferenceLong("Team3_3players_humans",%0100)
  teamConf(2,3)\nbAi    = ReadPreferenceLong("Team3_3players_AI",0)
  teamConf(3,3)\players = ReadPreferenceLong("Team4_3players_humans",0)
  teamConf(3,3)\nbAi    = ReadPreferenceLong("Team4_3players_AI",1)
  teamConf(4,3)\players = ReadPreferenceLong("Team5_3players_humans",0)
  teamConf(4,3)\nbAi    = ReadPreferenceLong("Team5_3players_AI",1)
  ; Config for 4 players game
  teamConf(0,4)\players = ReadPreferenceLong("Team1_4players_humans",%0001)
  teamConf(0,4)\nbAi    = ReadPreferenceLong("Team1_4players_AI",0)
  teamConf(1,4)\players = ReadPreferenceLong("Team2_4players_humans",%0010)
  teamConf(1,4)\nbAi    = ReadPreferenceLong("Team2_4players_AI",0)
  teamConf(2,4)\players = ReadPreferenceLong("Team3_4players_humans",%0100)
  teamConf(2,4)\nbAi    = ReadPreferenceLong("Team3_4players_AI",0)
  teamConf(3,4)\players = ReadPreferenceLong("Team4_4players_humans",%1000)
  teamConf(3,4)\nbAi    = ReadPreferenceLong("Team4_4players_AI",0)
  teamConf(4,4)\players = ReadPreferenceLong("Team5_4players_humans",0)
  teamConf(4,4)\nbAi    = ReadPreferenceLong("Team5_4players_AI",1)
   
  ClosePreferences()
  
EndProcedure

; Save the user's settings in a preferences file
Procedure writeIniFile()
  Protected iniFileName.s = "gameSettings.ini"
  Protected player.i,numteam.i
  
  ; Read content
  CreatePreferences(iniFileName)
  
  PreferenceComment("General")
  WritePreferenceLong("ScreenWidth", screenWidth)  
  WritePreferenceLong("ScreenHeight", screenHeight)
  WritePreferenceLong("FullScreen", fullscreen)
  WritePreferenceLong("NbPlayers", nbPlayers)
  WritePreferenceLong("TerrainDetail", terrainDetail)
  WritePreferenceLong("NbTrees", nbTrees)
  
  PreferenceComment("---------------------------")
  PreferenceComment("Controls")
  For player = 0 To 3
    WritePreferenceLong("Player" + Str(player+1) + "_cam", controls(player)\key_changeCamView)
    WritePreferenceLong("Player" + Str(player+1) + "_up", controls(player)\key_up)
    WritePreferenceLong("Player" + Str(player+1) + "_left", controls(player)\key_left)
    WritePreferenceLong("Player" + Str(player+1) + "_right", controls(player)\key_right)
    WritePreferenceLong("Player" + Str(player+1) + "_fire", controls(player)\key_fire)
  Next player
  
  PreferenceComment("---------------------------")
  PreferenceComment("Teams")
  For player = 1 To 4
    PreferenceComment("Settings for a " + Str(player) + " players game")
    For numTeam = 0 To #NB_TEAMS
      WritePreferenceLong("Team" + Str(numTeam + 1) + "_" + Str(player) + "players_humans",teamConf(numTeam,player)\players)
      WritePreferenceLong("Team" + Str(numTeam + 1) + "_" + Str(player) + "players_AI",teamConf(numTeam,player)\nbAi)
    Next numTeam
  Next player
  
EndProcedure

; Start menu, access to options, etc..
Procedure startMenu()
  Protected i.i, j.i, x.i
  Protected hOri.i,vOri.i, numPage.i
  Protected quit.b, action.b
  Protected nomSprite.s, tmpStr.s
  Protected selected.i,selectSprite.i
  Protected ratio.f, interleave.f
  Protected titleSprite.i,boxSprite.i, numKey.i, nbTreeSprite.i
  Protected versionSprite.i, waitSprite.i
  Protected Dim menuPage.menuPage_struct(10)
  Protected NewList resolution.resolution_struct()
  Protected Dim nbPlSprite.i(5)
  Protected Dim playerSprite.i(5)
  Protected Dim playerCtrlSprite.i(5)
  Protected Dim keySpr.i(4)
  Protected Dim okSprite.i(2)
  Protected Dim detailSprite.i(2)
  Protected bgMesh.i,bgMaterial.i,bgEntity.i
  Protected titleMesh.i,titleMaterial.i,titleEntity.i
  
  ; Initialize menus & sprites
  INITSCREENANDSPRITES()
  
  ; Display menu
  Repeat
    ; Item selection
    ExamineKeyboard()
    
    action = 0
    If KeyboardReleased(#PB_Key_Up)
      selected-1
      If selected < 0
        selected = menuPage(numPage)\nbItems-1
      EndIf
    EndIf
    If KeyboardReleased(#PB_Key_Down)
      selected = (selected + 1) % menuPage(numPage)\nbItems
    EndIf
    If KeyboardReleased(#PB_Key_Left)
      action = #MENU_LEFTPRESSED
    EndIf
    If KeyboardReleased(#PB_Key_Right)
      action = #MENU_RIGHTPRESSED
    EndIf
    If KeyboardReleased(#PB_Key_Space) Or KeyboardReleased(#PB_Key_Return)
      action = #MENU_CLICKED
    EndIf
    If KeyboardReleased(#PB_Key_Escape)
      ; The last item is always "quit" or "return"
      selected = menuPage(numPage)\nbItems-1
      action = #MENU_CLICKED
    EndIf
    
    ; Other keys only on specific pages and items
    If numPage = #MENUPAGE_TEAMS
      If KeyboardReleased(#PB_Key_1) Or KeyboardReleased(#PB_Key_Pad1)
        For i=0 To #NB_TEAMS
          teamConf(i,nbPlayers)\players & %1110
        Next i
        teamConf(selected,nbPlayers)\players | %0001
      EndIf
      If (KeyboardReleased(#PB_Key_2) Or KeyboardReleased(#PB_Key_Pad2)) And nbPlayers >= 2
        For i=0 To #NB_TEAMS
          teamConf(i,nbPlayers)\players & %1101
        Next i
        teamConf(selected,nbPlayers)\players | %0010
      EndIf
      If (KeyboardReleased(#PB_Key_3) Or KeyboardReleased(#PB_Key_Pad3)) And nbPlayers >= 3
        For i=0 To #NB_TEAMS
          teamConf(i,nbPlayers)\players & %1011
        Next i
        teamConf(selected,nbPlayers)\players | %0100
      EndIf
      If (KeyboardReleased(#PB_Key_4) Or KeyboardReleased(#PB_Key_Pad4)) And nbPlayers >= 4
        For i=0 To #NB_TEAMS
          teamConf(i,nbPlayers)\players & %0111
        Next i
        teamConf(selected,nbPlayers)\players | %1000
      EndIf
    EndIf
    
    ; Click!
    If action <> 0
      If menuPage(numPage)\itemList[selected]\action = #GO_TO_PAGE
        ; Change menu page
        numPage = menuPage(numPage)\itemList[selected]\param
        selected = 0
        writeIniFile()

      ElseIf menuPage(numPage)\itemList[selected]\param & action > 0
        
        Select menuPage(numPage)\itemList[selected]\numItem
          Case #MENU_QUIT
            writeIniFile()
            quit = #True

          Case #MENU_START ; Start game            
            RenderWorld()
            DisplayTransparentSprite(waitSprite,screenWidth/2 - SpriteWidth(waitSprite)/2, vOri)
            FlipBuffers()
            
            DESTROY3DMENUELEMENTS()
            playGame()
            INIT3DMENUELEMENTS()
            ClearScreen(0)
  
          Case #MENU_NBPLAYERS ; Changed number of players
            If action = #MENU_LEFTPRESSED
              nbPlayers - 1
              If nbPlayers < 1
                nbPlayers = 4
              EndIf
            ElseIf action = #MENU_CLICKED Or action = #MENU_RIGHTPRESSED
              nbPlayers + 1
              If nbPlayers > 4
                nbPlayers = 1
              EndIf
            EndIf
            
          Case #MENU_TEAM1,#MENU_TEAM2,#MENU_TEAM3,#MENU_TEAM4,#MENU_TEAM5 ; Add an AI opponent to a team
            If action = #MENU_LEFTPRESSED And teamConf(selected,nbPlayers)\nbAi > 0
              teamConf(selected,nbPlayers)\nbAi - 1
            ElseIf action  = #MENU_RIGHTPRESSED And teamConf(selected,nbPlayers)\nbAi < 10
              teamConf(selected,nbPlayers)\nbAi + 1 
            EndIf
      
          Case #MENU_CTRL1,#MENU_CTRL2,#MENU_CTRL3,#MENU_CTRL4 ; Redefine keyboard
            GETNEWCONTROLS(menuPage(numPage)\itemList[selected]\numItem - #MENU_CTRL1)            
            
          Case #MENU_RESOLUTION ; Change screen resolution
            If action = #MENU_LEFTPRESSED And ListIndex(resolution()) > 0
              DESTROYSCREEN()
              PreviousElement(resolution())
              screenWidth = resolution()\width
              screenHeight = resolution()\height
              INITSCREENANDSPRITES()    
            ElseIf action = #MENU_RIGHTPRESSED And ListIndex(resolution()) < ListSize(resolution())-1
              DESTROYSCREEN()
              NextElement(resolution())
              screenWidth = resolution()\width
              screenHeight = resolution()\height
              INITSCREENANDSPRITES()    
            EndIf
            
          Case #MENU_FULLSCREEN ; Switch to windowed / fullscreen
            DESTROYSCREEN()
            fullscreen = 1-fullscreen
            INITSCREENANDSPRITES()
            
          Case #MENU_TERRAINDETAIL  ; Terrain definition
            If action = #MENU_LEFTPRESSED And terrainDetail > 9
              terrainDetail-1
              DeleteFile("meshes/HoverRacers10_00000000.dat")
            ElseIf action = #MENU_RIGHTPRESSED And terrainDetail < 10
              terrainDetail+1
              DeleteFile("meshes/HoverRacers9_00000000.dat")
            EndIf
            
          Case #MENU_TREES  ; Add trees
            If action = #MENU_LEFTPRESSED And nbTrees > 0
              nbTrees - 50
            ElseIf action = #MENU_RIGHTPRESSED And nbTrees < 500
              nbTrees + 50
            EndIf
            
        EndSelect
      EndIf
    EndIf

    ; Display
    RenderWorld()
    ; Menu items on this page
    For i=0 To menuPage(numPage)\nbItems-1
      DisplaySprite(menuPage(numPage)\itemList[i]\numSprite,hOri,vOri + i*interleave)
    Next i
    
    ; Selection
    DisplaySprite(selectSprite,hOri - 64*ratio,vOri + selected*interleave - 2*ratio)
    
    ; Specific sprites on specific pages
    Select numPage
      Case #MENUPAGE_MAIN
        DisplaySprite(nbPlSprite(nbPlayers), hOri + SpriteWidth(menuPage(#MENUPAGE_MAIN)\itemList[1]\numSprite),vOri + interleave - 8*ratio)

      Case #MENUPAGE_TEAMS
        For i=0 To #NB_TEAMS
          x=hOri + SpriteWidth(menuPage(#MENUPAGE_TEAMS)\itemList[i]\numSprite)
          For j=0 To 3
            If teamConf(i,nbPlayers)\players & Int(Pow(2,j)) > 0
              DisplaySprite(playerSprite(j),x,vOri + i*interleave)
              x+interleave
            EndIf
          Next j
          For j=1 To teamConf(i,nbPlayers)\nbAi
            DisplaySprite(playerSprite(4),x + (j-1)*interleave,vOri + i*interleave)
          Next j
        Next i

      Case #MENUPAGE_CONTROLS
        For i=0 To 3
          DisplaySprite(playerCtrlSprite(i), hOri + SpriteWidth(menuPage(#MENUPAGE_CONTROLS)\itemList[i]\numSprite),vOri + i*interleave)
        Next i
 
      Case #MENUPAGE_GFX
        ForEach resolution()
          If resolution()\width = screenWidth And resolution()\height = screenHeight
            DisplaySprite(resolution()\numSprite,hOri + SpriteWidth(menuPage(#MENUPAGE_GFX)\itemList[0]\numSprite),vOri)
            Break
          EndIf
        Next resolution()
        DisplaySprite(okSprite(fullscreen),hOri + SpriteWidth(menuPage(#MENUPAGE_GFX)\itemList[1]\numSprite),vOri + interleave)
        DisplaySprite(detailSprite(terrainDetail-9),hOri + SpriteWidth(menuPage(#MENUPAGE_GFX)\itemList[2]\numSprite),vOri + interleave*2)
        For i=1 To nbtrees Step 50
          DisplaySprite(nbTreeSprite,hOri + SpriteWidth(menuPage(#MENUPAGE_GFX)\itemList[3]\numSprite) + (i/50)*interleave,vOri + interleave*3)
        Next i
        
    EndSelect
    
    DisplaySprite(versionSprite,screenWidth - SpriteWidth(versionSprite),screenHeight - SpriteHeight(versionSprite))
    
    FlipBuffers()
    If fullscreen = #False
      While WindowEvent(): Wend
    EndIf
    
  Until quit=#True  
  
EndProcedure

DisableExplicit



;************************************************************************************
;-                                 ---- Main program ----
;************************************************************************************


; Engine initialization
If InitEngine3D(#PB_Engine3D_DebugLog) = 0
  MessageRequester( "Error" , "Can't initialize 3D, check if engine3D.dll is available")
End
ElseIf InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0
  MessageRequester( "Error" , "Can't initialize screen and/or controlers")
  End
EndIf
UsePNGImageDecoder()

;- Window & Screen
fullscreen = #False
screenWidth = 800 
screenHeight = 600

;- Teams initialization
Restore teamColors
For i = 0 To #NB_TEAMS
  Read.i teamColor(i)
Next i
Restore teamMaterials
For i = 0 To #NB_TEAMS
  Read.s teamMaterial(i)
Next i

; Keyboard configuration
Restore keyDatas
Read.i i
While i <> #END_DATA
  AddMapElement(key(),Str(i))
  key(Str(i))\value = i
  Read.s key(Str(i))\name
  
  Read.i i
Wend

;- Read configuration file
readInifile()

;- Call Start Menu
startMenu()


End

;- Datas
DataSection
  teamColors:
  Data.i $0000FF,$FF0000,$00FF00,$AA0077,$00FFFF
  
  teamNames:
  Data.s "Ichi","Kaks","Tatu","Maha","Fünf"
  
  teamMaterials:
  Data.s "hoverred","hoverblue","hovergreen","hoverpurple","hoveryellow"
  
  teamControls:
  Data.i #PB_Key_Up,#PB_Key_Left,#PB_Key_Right,#PB_Key_Space,#PB_Key_F1
  Data.i #PB_Key_S,#PB_Key_Z,#PB_Key_C,#PB_Key_LeftControl,#PB_Key_F2
  Data.i #PB_Key_O,#PB_Key_K,#PB_Key_SemiColon,#PB_Key_RightControl,#PB_Key_F3
  Data.i #PB_Key_Pad8,#PB_Key_Pad4,#PB_Key_Pad6,#PB_Key_PadEnter,#PB_Key_F4
  
  cameraConfigs:
  Data.i #NEWCAMERACONFIG,1
  Data.i #CAMERA1,0,0,100,100,$0001
  
  Data.i #NEWCAMERACONFIG,2
  Data.i #CAMERA1, 0,0,50,100,$0001
  Data.i #CAMERA2,50,0,50,100,$0010
  
  Data.i #NEWCAMERACONFIG,3
  Data.i #CAMERA1, 0, 0, 50,50,$0001
  Data.i #CAMERA2,50, 0, 50,50,$0010
  Data.i #CAMERA3, 0,50,100,50,$0100
  
  Data.i #NEWCAMERACONFIG,4
  Data.i #CAMERA1, 0, 0,50,50,$0001
  Data.i #CAMERA2,50, 0,50,50,$0010
  Data.i #CAMERA3, 0,50,50,50,$0100
  Data.i #CAMERA4,50,50,50,50,$1000
  
  
  startMenu:
  Data.i #MENUPAGE_MAIN,6
    Data.i #MENU_START, #TRIGGER, #MENU_CLICKED
    Data.s "medias/menuStart.png"
    Data.i #MENU_NBPLAYERS, #TRIGGER, #MENU_CLICKED | #MENU_LEFTPRESSED | #MENU_RIGHTPRESSED
    Data.s "medias/menuNbPlayers.png"
    Data.i #MENU_TEAMS, #GO_TO_PAGE, #MENUPAGE_TEAMS
    Data.s "medias/menuTeams.png"
    Data.i #MENU_CONTROLS, #GO_TO_PAGE, #MENUPAGE_CONTROLS
    Data.s "medias/menuControls.png"
    Data.i #MENU_GFX, #GO_TO_PAGE, #MENUPAGE_GFX
    Data.s "medias/menuGfx.png"
    Data.i #MENU_QUIT, #TRIGGER, #MENU_CLICKED
    Data.s "medias/menuQuit.png"
    
  Data.i #MENUPAGE_TEAMS,6
    Data.i #MENU_TEAM1, #TRIGGER, #MENU_LEFTPRESSED | #MENU_RIGHTPRESSED  
    Data.s "medias/menuTeam1.png"
    Data.i #MENU_TEAM2, #TRIGGER, #MENU_LEFTPRESSED | #MENU_RIGHTPRESSED    
    Data.s "medias/menuTeam2.png"
    Data.i #MENU_TEAM3, #TRIGGER, #MENU_LEFTPRESSED | #MENU_RIGHTPRESSED    
    Data.s "medias/menuTeam3.png"
    Data.i #MENU_TEAM4, #TRIGGER, #MENU_LEFTPRESSED | #MENU_RIGHTPRESSED    
    Data.s "medias/menuTeam4.png"
    Data.i #MENU_TEAM5, #TRIGGER, #MENU_LEFTPRESSED | #MENU_RIGHTPRESSED    
    Data.s "medias/menuTeam5.png"
    Data.i #MENU_BACK, #GO_TO_PAGE, #MENU_START
    Data.s "medias/menuBack.png"
    
  Data.i #MENUPAGE_CONTROLS,5
    Data.i #MENU_CTRL1, #TRIGGER, #MENU_CLICKED  
    Data.s "medias/menuCtrlPlayer1.png"
    Data.i #MENU_CTRL2, #TRIGGER, #MENU_CLICKED  
    Data.s "medias/menuCtrlPlayer2.png"
    Data.i #MENU_CTRL3, #TRIGGER, #MENU_CLICKED  
    Data.s "medias/menuCtrlPlayer3.png"
    Data.i #MENU_CTRL4, #TRIGGER, #MENU_CLICKED  
    Data.s "medias/menuCtrlPlayer4.png"
    Data.i #MENU_BACK, #GO_TO_PAGE, #MENU_START
    Data.s "medias/menuBack.png"
    
  Data.i #MENUPAGE_GFX,5
    Data.i #MENU_RESOLUTION, #TRIGGER, #MENU_LEFTPRESSED | #MENU_RIGHTPRESSED  
    Data.s "medias/menuResolution.png"
    Data.i #MENU_FULLSCREEN, #TRIGGER, #MENU_CLICKED   
    Data.s "medias/menuFullscreen.png"
    Data.i #MENU_TERRAINDETAIL, #TRIGGER, #MENU_LEFTPRESSED | #MENU_RIGHTPRESSED   
    Data.s "medias/menuTerrainDetail.png"
    Data.i #MENU_TREES, #TRIGGER, #MENU_LEFTPRESSED | #MENU_RIGHTPRESSED   
    Data.s "medias/menuTrees.png"
    Data.i #MENU_BACK, #GO_TO_PAGE, #MENU_START
    Data.s "medias/menuBack.png"
    
  Data.i #END_DATA
  
  keyDatas:
  Data.i #PB_Key_1	:Data.s "1"
  Data.i #PB_Key_2	:Data.s "2"
  Data.i #PB_Key_3	:Data.s "3"
  Data.i #PB_Key_4	:Data.s "4"
  Data.i #PB_Key_5	:Data.s "5"
  Data.i #PB_Key_6	:Data.s "6"
  Data.i #PB_Key_7	:Data.s "7"
  Data.i #PB_Key_8	:Data.s "8"
  Data.i #PB_Key_9	:Data.s "9"
  Data.i #PB_Key_0	:Data.s "0"
  Data.i #PB_Key_A	:Data.s "A"
  Data.i #PB_Key_B	:Data.s "B"
  Data.i #PB_Key_C	:Data.s "C"
  Data.i #PB_Key_D	:Data.s "D"
  Data.i #PB_Key_E	:Data.s "E"
  Data.i #PB_Key_F	:Data.s "F"
  Data.i #PB_Key_G	:Data.s "G"
  Data.i #PB_Key_H	:Data.s "H"
  Data.i #PB_Key_I	:Data.s "I"
  Data.i #PB_Key_J	:Data.s "J"
  Data.i #PB_Key_K	:Data.s "K"
  Data.i #PB_Key_L	:Data.s "L"
  Data.i #PB_Key_M	:Data.s "M"
  Data.i #PB_Key_N	:Data.s "N"
  Data.i #PB_Key_O	:Data.s "O"
  Data.i #PB_Key_P	:Data.s "P"
  Data.i #PB_Key_Q	:Data.s "Q"
  Data.i #PB_Key_R	:Data.s "R"
  Data.i #PB_Key_S	:Data.s "S"
  Data.i #PB_Key_T	:Data.s "T"
  Data.i #PB_Key_U	:Data.s "U"
  Data.i #PB_Key_V	:Data.s "V"
  Data.i #PB_Key_W	:Data.s "W"
  Data.i #PB_Key_X	:Data.s "X"
  Data.i #PB_Key_Y	:Data.s "Y"
  Data.i #PB_Key_Z	:Data.s "Z"
  Data.i #PB_Key_Minus	:Data.s "-"
  Data.i #PB_Key_Equals	:Data.s "="
  Data.i #PB_Key_Back	:Data.s "Back"
  Data.i #PB_Key_Tab	:Data.s "Tab"
  Data.i #PB_Key_LeftBracket	:Data.s "["
  Data.i #PB_Key_RightBracket	:Data.s "]"
  Data.i #PB_Key_Return	:Data.s "Return"
  Data.i #PB_Key_LeftControl	:Data.s "LeftCtrl"
  Data.i #PB_Key_SemiColon	:Data.s ";"
  Data.i #PB_Key_Apostrophe	:Data.s "'"
  Data.i #PB_Key_Grave	:Data.s "Grave"
  Data.i #PB_Key_LeftShift	:Data.s "LeftShift"
  Data.i #PB_Key_BackSlash	:Data.s "\"
  Data.i #PB_Key_Comma	:Data.s ","
  Data.i #PB_Key_Period	:Data.s "."
  Data.i #PB_Key_Slash	:Data.s "Slash"
  Data.i #PB_Key_RightShift	:Data.s "RightShift"
  Data.i #PB_Key_Multiply	:Data.s "*"
  Data.i #PB_Key_LeftAlt	:Data.s "LeftAlt"
  Data.i #PB_Key_Space	:Data.s "Space"
  Data.i #PB_Key_Capital	:Data.s "Caps"
  Data.i #PB_Key_NumLock	:Data.s "NumLock"
  Data.i #PB_Key_Scroll	:Data.s "Scroll"
  Data.i #PB_Key_Pad0	:Data.s "Pad0"
  Data.i #PB_Key_Pad1	:Data.s "Pad1"
  Data.i #PB_Key_Pad2	:Data.s "Pad2"
  Data.i #PB_Key_Pad3	:Data.s "Pad3"
  Data.i #PB_Key_Pad4	:Data.s "Pad4"
  Data.i #PB_Key_Pad5	:Data.s "Pad5"
  Data.i #PB_Key_Pad6	:Data.s "Pad6"
  Data.i #PB_Key_Pad7	:Data.s "Pad7"
  Data.i #PB_Key_Pad8	:Data.s "Pad8"
  Data.i #PB_Key_Pad9	:Data.s "Pad9"
  Data.i #PB_Key_Add	:Data.s "+"
  Data.i #PB_Key_Subtract	:Data.s "Pad-"
  Data.i #PB_Key_Decimal	:Data.s "Decimal"
  Data.i #PB_Key_PadEnter	:Data.s "PadEnter"
  Data.i #PB_Key_RightControl	:Data.s "RightCtrl"
  Data.i #PB_Key_PadComma	:Data.s "Pad."
  Data.i #PB_Key_Divide	:Data.s "Pad/"
  Data.i #PB_Key_RightAlt	:Data.s "RightAlt"
  Data.i #PB_Key_Pause	:Data.s "Pause"
  Data.i #PB_Key_Home	:Data.s "Home"
  Data.i #PB_Key_Up	:Data.s "Up"
  Data.i #PB_Key_Down	:Data.s "Down"
  Data.i #PB_Key_Left	:Data.s "Left"
  Data.i #PB_Key_Right	:Data.s "Right"
  Data.i #PB_Key_End	:Data.s "End"
  Data.i #PB_Key_PageUp	:Data.s "PageUp"
  Data.i #PB_Key_PageDown	:Data.s "PageDown"
  Data.i #PB_Key_Insert	:Data.s "Insert"
  Data.i #PB_Key_Delete	:Data.s "Del"  
  Data.i #END_DATA
  

Re: Hover Racers

Publié : lun. 17/déc./2012 19:12
par comtois
kelebrindae a écrit : Bugs:
------------------
- Quelquefois, sous certaines conditions que je cerne mal (et que je n'ai pas réussi à isoler dans un code court), la fonction NodeX() renvoie Nan. J'ai contourné le problème en utilisant EntityX() à la place, mais si Comtois est intéressé je peux lui indiquer l'endroit du code où se produit le problème.
Oui, si tu peux me donner un max d'infos pour pister un bug, faut pas hésiter.

Je vais déjà récupérer ton archive, je teste dès que je peux.

Re: Hover Racers

Publié : dim. 06/janv./2013 20:53
par comtois
je viens de réinstaller ton archive. J'ai lancé l'exécutable pour tester la mise à jour. J'ai bien récupéré des trucs, mais les fichiers sont enregistrés au même emplacement que l'exécutable, alors qu'il y a des répertoires meshes, materials, etc. pour ranger correctement tout ce petit monde. Ensuite j'ai joué quelques minutes et le prog a planté. C'est le plantage dont tu parles plus haut ? Et que je recolle ici :
Bugs:
------------------
- Quelquefois, sous certaines conditions que je cerne mal (et que je n'ai pas réussi à isoler dans un code court), la fonction NodeX() renvoie Nan. J'ai contourné le problème en utilisant EntityX() à la place, mais si Comtois est intéressé je peux lui indiquer l'endroit du code où se produit le problème.
Tu as essayé avec la 5.10 si ça le fait encore ?

La dll et l'exécutable de l'archive, c'est toujours en 5.00 ?

Re: Hover Racers

Publié : lun. 07/janv./2013 10:54
par kelebrindae
Zut! Apparemment, j'ai un souci avec mon "versionPacker". :x
C'est un petit bout de programme que je me suis fait pour construire les fichiers de mise à jour: il compare tous les fichiers de la version actuelle avec ceux de la version précédente et les "packe" dans un fichier avec des infos sur les noms de fichiers et les répertoires (infos perdues quand on compresse avec la librairie Pack de PB).
Et visiblement, je perds l'info sur le répertoire... Je vais essayer d'arranger ça très vite.

En attendant, il faut déplacer les fichiers:
- ".material" vers le répertoire "materials";
- ".mesh" vers le répertoire "meshes";
- ".png" vers le répertoire "textures".

Pour le bug que tu as constaté:
Je n'ai pas porté le programme en 5.10b2, parce que j'ai eu un plantage avec le CreateLight + flag "#PB_Light_Directional" => ça crashait direct en "invalid memory access". Et puis, quand j'ai voulu remplacer tous les "xxxLocate" par des "MoveXxx", j'ai dû me planter dans les paramètres car je ne voyais plus rien. Comme je manquais de temps, j'ai remis à plus tard et je suis revenu en 5.00...

En v0.78, j'ai revu le fonctionnement des explosions et ajouté des missiles à tête chercheuses, et je suis tombé sur un bug bizarre. Tentative d'explication:
Les missiles existant sont stockés dans une linkedList. J'en ajoute un quand le joueur prend un bonus "Missile", et je l'efface quand le missile explose. Entre les deux, au moment où le joueur tire le missile, je fais un "missile()\entity = CreateEntity(#PB_any..." pour créer l'entity du missile. Et quand il explose, je fais un "freeEntity(missile()\entity)" avant le "deleteElement(missile())".
Or, dans certains cas, le "CreateEntity" semble fonctionner, il renvoie un numéro d'entité, mais dès que l'on tente d'utiliser cette entité on obtient un crash "entité non-initialisée". En traçant un peu, j'ai remarqué que le n° d'entité fautif est identique à celui d'une entité qui vient d'être détruite (ce qui n'est pas forcément anormal: je ne sais pas comment PB attribue les n° d'entités).

Je pensais avoir contourné le problème en créant les missiles à l'initialisation, de façon à ne plus les "créer-détruire-créer...", et dans mes tests ça semblait marcher, mais si tu me dis que ça a planté au bout de quelques minutes, il faut que je regarde ça de plus près... :?

Merci du test, en tous cas!

Re: Hover Racers

Publié : lun. 07/janv./2013 11:04
par comtois
j'ai eu un plantage avec le CreateLight + flag "#PB_Light_Directional"

N'hésite pas à faire des rapports de bogues, avec un petit code si possible, ça peut aider pour corriger les problèmes. Idem pour ton problème d'entity.

Re: Hover Racers

Publié : lun. 07/janv./2013 11:39
par kelebrindae
Oui, pour la lumière, je le fais dès que possible. Pour l'autre, je ne sais pas si j'arriverai à le reproduire dans un code court...

Sinon, j'ai corrigé le problème des chemins lors de l'update de la v0.78 (c'est déjà ça...)

[EDIT]
Ah, bâh non en fait, le bug c'est que j'suis trop con: Dans mon "InitEngine3D", je pointais sur le "engine3D.dll" de la v5.00. Alors forcément, ça marchait beaucoup moins bien... :oops:

Toutes mes excuses: pour ce que j'en constate, la 5.10b2 fonctionne à merveille! :D

Re: Hover Racers

Publié : mar. 19/mars/2013 10:37
par kelebrindae
Mise à jour, pour ajouter un mode de jeu alternatif, quelques mises à jour graphiques, quelques options...

http://keleb.free.fr/codecorner/downloa ... est inclu)

NB: Si le jeu rame (F12 pendant le jeu affiche les FPS), mettez le niveau de détail des ombres au minimum dans les options graphiques => ça désactive les ombres des arbres, qui sont assez coûteuses (surtout que le paramètre "distance" n'a pas l'air de marcher dans "WorldShadow").

Amusez-vous bien! :wink:

Re: Hover Racers

Publié : mar. 19/mars/2013 11:14
par falsam
Je me suis bien défoulé. Merci pour le partage qui va me permettre d'approfondir un peu plus le monde de la 3D.

J'ai deux moniteurs sur mon pc. Quand je déplace le jeu d'un moniteur á l'autre, le Menu disparait.

Re: Hover Racers

Publié : mar. 19/mars/2013 19:14
par comtois
Chez moi ça ne rame pas, mais ça plante quand je change la résolution. Sinon bravo, les jeux amateurs complets et finis sont rares (avec menu, musique, son, effets, etc).
J'en sais quelque chose, je n'en ai jamais fini un seul :)

Re: Hover Racers

Publié : mer. 20/mars/2013 7:55
par kelebrindae
@Falsam:
Le menu est à base de sprites et les sprites sont liés au "Screen" courant; peut-être que le "Screen" est lié à un écran physique? (Pure spéculation...)

@Comtois:
Merci! Je ne considère pas vraiment le jeu comme "fini": j'aimerais bien rajouter un mode de jeu (Capture the flag) et le support des joysticks, plus deux ou trois petites choses. Mais je manque de temps libre...
(et pour ce qui est de finir les choses, je compatis: je suis atteint du même syndrome :wink: )