This is a little game (heavily) inspired by an old tutorial from a guy nicknamed Binary Moon. The hovercraft's mesh is from him, too.
(Find the tuto here: http://www.thegamecreators.com/?m=view_ ... rial_index)
My goal here was to test the new 3D functionnalities of PB5 and I must say it works real fine!

The rules are simple: you've got to get to the checkpoint before your opponents.
There's a few constants at the beginning of the code to set the number of opponents, the number of opponent teams (1-3), the trees, etc..
There's still a lot of flaws here and there (eg. the tree textures) and the game has no end, but it's playable; see it more as a proof of concept. A convincing one, I hope...

Grab the code & medias here (3. 6Mo):
http://keleb.free.fr/codecorner/downloa ... rcraft.zip
[UPDATE]: A PB 5.10 version, with more features, is available here:
http://keleb.free.fr/codecorner/downloa ... Racers.zip
(19.6 Mo, source included)
Screenshot:

Have fun!
Code: Select all
;************************************************************************************
; Hovercraft race (inspired by the Binary Moon tutorials for DarkBasic)
; PB version: 5.00 b6
; Date: October, 23, 2012
;- F1 -> Change camera view
;- F2 -> Change camera target
;- F5 : Display physic bodies
;- F6 : Wireframe mode
;************************************************************************************
;************************************************************************************
;- ---- Constants and structure ----
;************************************************************************************
#NUMTERRAIN = 0
#TerrainMiniX = 0
#TerrainMiniY = 0
#TerrainMaxiX = 0
#TerrainMaxiY = 0
#CAMERA = 0
#NB_HOVERCRAFTS = 6 ; Nb hovercrafts (except you)
#NB_TEAMS = 3 ; Nb teams (except yours)
#NB_CRATESTACKS = 20
#NB_TREES = 100
Enumeration
#RearView
#SideView
#FrontView
#TopView
#END_VIEWLIST
EndEnumeration
Structure hover_struct
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
EndStructure
Global Dim hovercraft.hover_struct(#NB_HOVERCRAFTS+1)
Structure checkpoint_struct
node.i
particle.i
x.f
y.f
z.f
radius.f
EndStructure
Global currentCheckpoint.checkpoint_struct
Global Dim treeMesh.i(4)
Global Dim scoreSprite.i(4)
Global Dim score.i(4)
Global Dim scoreColor.i(4)
scoreColor(0) = $0000FF
scoreColor(1) = $FF0000
scoreColor(2) = $00FF00
scoreColor(3) = $00FFFF
Global Dim nomMatAi.s(4)
nomMatAi(0) = "hoverblue"
nomMatAi(1) = "hovergreen"
nomMatAi(2) = "hoveryellow"
Global arrowMesh.i,arrowEntity.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(NodeZ(hovercraft(idHovercraft)\node) - currentCheckpoint\z , NodeX(hovercraft(idHovercraft)\node) - currentCheckpoint\x ))
EndMacro
Macro DRAWSCORESPRITE(numTeam)
StartDrawing(SpriteOutput(scoreSprite(numTeam)))
Box(0,0,20,20,scoreColor(numTeam))
DrawText(32,2,RSet(Str(score(numTeam)),3,"0"))
DrawingMode(#PB_2DDrawing_Outlined)
Box(0,0,64,20,scoreColor(numTeam))
StopDrawing()
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 given number of random trees
; (The tree mesh is chosen according to altitude)
Procedure createTrees(nbTrees.i)
Protected i.i,tree.i,numMesh.i
Protected posX.f,posY.f,posZ.f
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)
BuildMeshShadowVolume(treeMesh(0))
BuildMeshShadowVolume(treeMesh(1))
BuildMeshShadowVolume(treeMesh(2))
BuildMeshShadowVolume(treeMesh(3))
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
tree = CreateEntity(#PB_Any,MeshID(treeMesh(numMesh)),#PB_Material_None,posX,posY,posZ)
RotateEntity(tree,-90,Random(360),0)
ScaleEntity(tree,(70 + Random(60))/100.0,(70 + Random(60))/100.0,(70 + Random(60))/100.0)
EntityRenderMode(tree,#PB_Entity_CastShadow)
EntityPhysicBody(tree,#PB_Entity_StaticBody,99,1.0,1.0)
Next i
EndProcedure
; Create a given number of crates stacks, just so the hovercrafts can ram through them :)
Procedure createCrates(nbStacks.i)
Protected i.i,j.i,temp.i
Protected cubeMesh.i,crateTexture.i,crateMat.i
Protected oriX.f,oriZ.f,posX.f,posY,posZ.f
cubeMesh = CreateCube(#PB_Any,1)
crateTexture = LoadTexture(#PB_Any,"crate.png")
crateMat = CreateMaterial(#PB_Any,TextureID(crateTexture))
For j=1 To nbStacks
posX = Random(900) - 450
oriZ = Random(900) - 450
For i = 0 To 2
temp = CreateEntity(#PB_Any, MeshID(cubeMesh), MaterialID(crateMat))
posZ = oriZ + (i*1.1)
EntityLocate(temp,posX,TerrainHeight(#NUMTERRAIN,posX,posZ)+0.5,posZ)
EntityPhysicBody(temp, #PB_Entity_BoxBody, 0.25)
Next i
For i = 0 To 1
temp = CreateEntity(#PB_Any, MeshID(cubeMesh), MaterialID(crateMat))
posZ = oriZ + 0.5 + (i*1.1)
EntityLocate(temp,posX,TerrainHeight(#NUMTERRAIN,posX,posZ)+1.5,posZ)
EntityPhysicBody(temp, #PB_Entity_BoxBody, 0.25)
Next i
temp = CreateEntity(#PB_Any, MeshID(cubeMesh), MaterialID(crateMat))
posZ = oriZ + 1
EntityLocate(temp,posX,TerrainHeight(#NUMTERRAIN,posX,posZ)+2.5,posZ)
EntityPhysicBody(temp, #PB_Entity_BoxBody, 0.25)
Next j
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,nomMesh.s,posX.f, posZ.f, mass.f, restitution.f, friction.f, thrust.f, centerHeight.f)
Protected numMat.i
; Material
If id = 0
numMat = GetScriptMaterial(#PB_Any,"hoverred")
Else
numMat = GetScriptMaterial(#PB_Any,nomMatAi((id-1) % #NB_TEAMS))
EndIf
; Hovercraft entity
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)\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
; 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),MaterialID(999),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)
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
; 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;
ClearDebugOutput()
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
thrust * (1 - (xAng/30))
;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)
EndProcedure
; Opponents AI (just steer towards the checkpoint and move forward)
Procedure moveAiHovercraft()
Protected id.i
Protected forward.b = #True, backward.b, left.b, right.b
Protected angle.f
For id = 1 To #NB_HOVERCRAFTS
If wrapValue(ANGLE2CHECKPOINT(id) - NodeYaw(hovercraft(id)\node)) < 180
left=#True
right=#False
Else
left=#False
right=#True
EndIf
moveHovercraft(id,forward,backward,left,right)
Next id
EndProcedure
; Animate the checkpoint and check if an hovercraft reached it.
Procedure manageCheckpoint(*ptrCheckPoint.checkpoint_struct)
Protected i.i, team.i
Protected posX.f = *ptrCheckPoint\x + *ptrCheckPoint\radius * Cos(Radian(ElapsedMilliseconds()*2))
Protected posZ.f = *ptrCheckPoint\z + *ptrCheckPoint\radius * Sin(Radian(ElapsedMilliseconds()*2))
NodeLocate(*ptrCheckPoint\node,posX,TerrainHeight(#NUMTERRAIN,posX,posZ)+ *ptrCheckPoint\y,posZ)
; If an hovercraft reach the checkpoint, change its position
For i=0 To #NB_HOVERCRAFTS
If (*ptrCheckPoint\x - NodeX(hovercraft(i)\node)) * (*ptrCheckPoint\x - NodeX(hovercraft(i)\node)) + (*ptrCheckPoint\z - NodeZ(hovercraft(i)\node)) * (*ptrCheckPoint\z - NodeZ(hovercraft(i)\node)) < *ptrCheckPoint\radius * *ptrCheckPoint\radius
; New position
*ptrCheckPoint\x = Random(900) - 450
*ptrCheckPoint\z = Random(900) - 450
; Increase and redraw score
If i > 0
team = 1 + ((i-1) % #NB_TEAMS)
EndIf
score(team) + 10
DRAWSCORESPRITE(team)
EndIf
Next i
EndProcedure
; Position the camera
Procedure manageCamera(mode.i,id.i)
Protected posX.f, posY.f, posZ.f
Static cameraAngle.f
Select Mode
Case #FrontView
cameraAngle = CurveValue(cameraAngle, NodeYaw(hovercraft(id)\node), 100)
posX = CurveValue(CameraX(#CAMERA), NEWXVALUE(NodeX(hovercraft(id)\node), cameraAngle, 6), 100)
posY = CurveValue(CameraY(#CAMERA), NodeY(hovercraft(id)\node) + 3, 100)
posZ = CurveValue(CameraZ(#CAMERA), NEWZVALUE(NodeZ(hovercraft(id)\node), cameraAngle, 6), 100)
Case #TopView
cameraAngle = CurveValue(cameraAngle, NodeYaw(hovercraft(id)\node) + 180, 100)
posX = CurveValue(CameraX(#CAMERA), NEWXVALUE(NodeX(hovercraft(id)\node), cameraAngle, 4), 30)
posY = CurveValue(CameraY(#CAMERA), NodeY(hovercraft(id)\node) + 30, 30)
posZ = CurveValue(CameraZ(#CAMERA), NEWZVALUE(NodeZ(hovercraft(id)\node), cameraAngle, 4), 30)
Case #RearView
cameraAngle = CurveValue(cameraAngle, NodeYaw(hovercraft(id)\node) + 180, 100)
posX = CurveValue(CameraX(#CAMERA), NodeX(hovercraft(id)\cameraNode), 100)
posZ = CurveValue(CameraZ(#CAMERA), NodeZ(hovercraft(id)\cameraNode), 100)
posY = CurveValue(CameraY(#CAMERA), NodeY(hovercraft(id)\node) + 1, 100)
If posY < TerrainHeight(#NUMTERRAIN,posX,posZ) + 1
posY = TerrainHeight(#NUMTERRAIN,posX,posZ) + 1
EndIf
Case #SideView
cameraAngle = CurveValue(cameraAngle, NodeYaw(hovercraft(id)\node) + 90, 100)
posX = CurveValue(CameraX(#CAMERA), NEWXVALUE(NodeX(hovercraft(id)\node), cameraAngle, 8), 100)
posY = CurveValue(CameraY(#CAMERA), NodeY(hovercraft(id)\node) + 4, 100)
posZ = CurveValue(CameraZ(#CAMERA), NEWZVALUE(NodeZ(hovercraft(id)\node), cameraAngle, 8), 100)
EndSelect
CameraLocate(#CAMERA, posX, posY, posZ)
CameraLookAt(#CAMERA, NodeX(hovercraft(id)\node), NodeY(hovercraft(id)\node), NodeZ(hovercraft(id)\node))
EndProcedure
DisableExplicit
;************************************************************************************
;- ---- Main program ----
;************************************************************************************
If InitEngine3D() = 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
;- Window & Screen
OpenWindow(0,0, 0, 800 , 500 ,"Hovercraft race")
OpenWindowedScreen(WindowID(0),0,0, 800, 500,0,0,0,#PB_Screen_SmartSynchronization)
;- 3d archives
Add3DArchive("meshes/", #PB_3DArchive_FileSystem)
Add3DArchive("materials/", #PB_3DArchive_FileSystem)
Add3DArchive("textures/", #PB_3DArchive_FileSystem)
Add3DArchive("medias/", #PB_3DArchive_FileSystem)
Parse3DScripts()
;- 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
;- Camera
CreateCamera(#CAMERA, 0, 0, 100, 100)
CameraBackColor(#CAMERA,$FF7755)
CameraLocate(#CAMERA,0,50,150)
;- Arrow
arrowMesh = LoadMesh(#PB_Any,"arrow.mesh")
arrowEntity = CreateEntity(#PB_Any,MeshID(arrowMesh),#PB_Material_None)
ScaleEntity(arrowEntity,0.5,0.5,0.5)
;- Terrain definition
SetupTerrains(LightID(light), 3000, #PB_Terrain_NormalMapping)
CreateTerrain(#NUMTERRAIN, 1025, 1000, 50, 3, "hovercraft", "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_2.png", ty % 2, tx % 2)
Next
Next
BuildTerrain(#NUMTERRAIN)
TerrainPhysicBody(#NUMTERRAIN,0.1,2.0)
If imported = #True
InitBlendMaps()
UpdateTerrain(#NUMTERRAIN)
SaveTerrain(#NUMTERRAIN, #False)
EndIf
;- Wireframe material
; (used To display the hovercraft's physics entity)
CreateTexture(999,16,16)
StartDrawing(TextureOutput(999))
Box(0,0,16,16,$FFFF00)
StopDrawing()
CreateMaterial(999,TextureID(999))
DisableMaterialLighting(999, State)
MaterialShadingMode(999, #PB_Material_Wireframe)
;- Hovercrafts
createHovercraft(0,"hovercraft.mesh",0,150,1,0.1,2.0,15,0.4) ; player
radius.f = 5
For i=1 To #NB_HOVERCRAFTS
posX = radius * Cos(Radian(i * 36))
posZ = 150 + radius * Sin(Radian(i * 36))
radius + 0.5
createHovercraft(i,"hovercraft.mesh",posX,posZ,1,0.1,2.0,14.5,0.4) ; opponents (slightly slower)
Next i
;- Crates
cubeMesh = CreateCube(#PB_Any,1)
createCrates(#NB_CRATESTACKS)
;- Trees
createTrees(#NB_TREES)
;- Checkpoint
currentCheckpoint\particle = GetScriptParticleEmitter(#PB_Any,"flareFountain")
currentCheckpoint\x = 0
currentCheckpoint\z = 0
currentCheckpoint\radius = 3
currentCheckpoint\node = CreateNode(#PB_Any)
AttachNodeObject(currentCheckpoint\node,ParticleEmitterID(currentCheckpoint\particle))
;- Score sprites
For i = 0 To #NB_TEAMS
scoreSprite(i) = CreateSprite(#PB_Any,64,20)
DRAWSCORESPRITE(i)
Next i
;- --- Main loop ---
showPhysicBody = #False
wireframe = #False
cameraMode = #rearView
Repeat
While WindowEvent(): Wend
;- Controls
forward = #False:backward=#False:left=#False:right=#False
If ExamineKeyboard()
If KeyboardPushed(#PB_Key_Up)
forward = #True
ElseIf KeyboardPushed(#PB_Key_Down)
backward=#True
EndIf
If KeyboardPushed(#PB_Key_Left)
left = #True
ElseIf KeyboardPushed(#PB_Key_Right)
right=#True
EndIf
;Change camera view & target
If KeyboardReleased(#PB_Key_F1)
cameraMode = (cameraMode + 1) % #END_VIEWLIST
EndIf
If KeyboardReleased(#PB_Key_F2)
cameraTarget = (cameraTarget + 1) % (#NB_HOVERCRAFTS + 1)
EndIf
; 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
; Wireframe display
If KeyboardReleased(#PB_Key_F6)
wireframe = 1 - wireframe
If wireframe = #True
CameraRenderMode(#CAMERA,#PB_Camera_Wireframe)
Else
CameraRenderMode(#CAMERA,#PB_Camera_Textured)
EndIf
EndIf
EndIf
;- Checkpoint
manageCheckpoint(@currentCheckpoint)
;- Move the hovercrafts
moveHovercraft(0,forward,backward,left,right)
moveAiHovercraft()
;- Move the camera
ManageCamera(cameraMode,cameraTarget)
;- Display hud (3D)
MoveCamera(#CAMERA,0,1.60,-5)
EntityLocate(arrowEntity,CameraX(#CAMERA),CameraY(#CAMERA),CameraZ(#CAMERA))
RotateEntity(arrowEntity,30,ANGLE2CHECKPOINT(cameraTarget),0)
MoveCamera(#CAMERA,0,-1.60,5)
RenderWorld()
;- Display scores (2D)
For i = 0 To #NB_TEAMS
DisplayTransparentSprite(scoreSprite(i),i*80,8)
Next i
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)