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