(Cela fait un bout de temps que je n'ai rien posté, mais je manque un peu de temps, désolé...)
Voici ma dernière expérimentation: afficher un monde à la façon de Minecraft. (Falsam, ça va te plaire, y'a des cubes partout.

ça marche bien, le programme n'affiche que les faces visibles de chaque cube et recrée à la volée celles qui manquent quand on creuse. De plus, le stockage en mémoire est assez économe (2 octets par cube, soit 128Ko pour une matrice de 32x128x32).
Ici, un zip avec programme + textures:
http://keleb.free.fr/codecorner/downloa ... eclone.zip
[UPDATE 22/11/2013]
Grosse mise à jour sur l'affichage: un seul mesh par chunk, et plusieurs chunks à l'écran, créés à la volée quant ils arrivent dans le champ de vision.
Mais j'ai dû désactiver (provisoirement?) les ombres, et je n'ai plus qu'un seul materiau; j'ai pris l'herbe, car elle offre une bonne visibilité. Je remettrai les autres quand j'aurai trouvé comment faire...
N'oubliez pas de récupérer l'include "PerlinNoise" (dans le zip ou plus bas, après le source).
[UPDATE 08/11/2013]
- Grosse optimisation de la création / mise à jour d'un chunk, ce qui permet d'avoir des terrains plus grands.
- Ajout de plusieurs chunk autour du chunk où se trouve le joueur, afin d'agrandir encore le terrain visible. Ces chunks sont créés / détruits à la volée quand il entrent / sortent du champ de vision. Mais multiplier les groupes de géométrie statiques a un impact assez lourd sur les perfs (plus que d'augmenter le nombre de polygones)

(Récupérez bien le zip, car il y a des nouvelles textures).
[UPDATE 06/11/2013]
Ajout des collisions et du saut; ça commence à être sympa!

[UPDATE 05/11/2013]
Je me heurte cependant à un problème: ça rame. En affichant à peine 14000 polygones, je tombe tout de suite à 30-35 FPS. Pourtant, 14000 polygones, de nos jours, ce n'est vraiment pas la mer à boire... Quelqu'un saurait où est le problème?
Grâce à G-Rom, ça ne rame plus du tout! Tout le décor est passé en géométrie statique et ça booste!

Le mouse-picking remarche, si vous êtes assez près de ce que vous visez (pour ne pas dégommer des cubes à l'autre bout du terrain).
La mise à jour du terrain prend un peu longtemps quand vous détruisez un cube, donc je vous conseille de désactiver le debugger.
Prochaine étape: ajouter les collisions avec le décor.
Touches:
- W = affichage fil de fer
- L = Jour / Nuit
- Souris + touches curseur = déplacements
Code:
Code : Tout sélectionner
;************************************************************************************
; Minecraft clone
; PB version: 5.21
; Date: November, 22, 2013
;
;- In game:
;- L -> Day / night
;- P -> Display physic bodies
;- W -> Wireframe view
;
;************************************************************************************
; Great Perlin noise generator given by G-Rom!
XIncludeFile "perlinGenerator.pbi"
;************************************************************************************
;- ---- Constants and structures ----
;************************************************************************************
; Window size
#SCREENWIDTH = 800
#SCREENHEIGHT = 500
; Camera
#CAMERA = 0
#CAMERASPEED = 0.005
#VIEWING_RANGE = 30
; Sides of a cube
Enumeration
#TOPSIDE
#BOTTOMSIDE
#LEFTSIDE
#RIGHTSIDE
#FRONTSIDE
#BACKSIDE
EndEnumeration
; Size of a chunk (group of cubes that are prepared/built/rendered at the same time)
#CHUNKWIDTH = 15
#CHUNKHEIGHT = 63
#CHUNKLENGTH = 15
; Chunk states
Enumeration
#CHUNK_NOSTATE
#CHUNK_PREPARED
#CHUNK_BUILT
#CHUNK_RENDERED
EndEnumeration
; Size of the world, in chunks
#WORLDWIDTH = 100
#WORLDHEIGHT = 1 ; only "1" is supported
#WORLDLENGTH = 100
; In a cube, there's six sides, and each one can be either visible or not.
; => 64 possible configurations (%111111)
Global Dim cubeMesh.i(%111111 + 1)
Global Dim faceValue.i(6) ; Top = %000001, Bottom = %000010, Left = %000100, etc..
; Cube materials (ground, grass, wood, stone, etc..
Structure cubeMat_struct
mtIntact.i
mtDamaged.i
mtAlmostBroken.i
opaque.b
soundWhenHit.i ; sound played when left-clicked
ptLossWhenHit.i ; solidity points lost when left-clicked
EndStructure
Global Dim cubeMat.cubeMat_struct(128) ; 127 cube types maximum (.b dans cube_struct, 0 = empty)
; World infos
Structure cube_struct
numMat.b
solidity.b ; 127 = intact, 0 = destroyed
EndStructure
Global boundingBox.i
Structure chunkArray_struct
Array chunk.cube_struct(#CHUNKWIDTH+1,#CHUNKHEIGHT+1,#CHUNKLENGTH+1)
queued.b
state.b
numMesh.i
boundingBoxEntity.i
EndStructure
Global Dim chunkArray.chunkArray_struct(#WORLDWIDTH,#WORLDLENGTH)
Structure toDo_struct
chunkCoordX.i
chunkCoordZ.i
distance.f
EndStructure
Global NewList toDo.toDo_struct()
; Collisions
Structure coords_struct
x.f
y.f
z.f
EndStructure
Global NewList collPointsForZ.coords_struct()
Global NewList collPointsForX.coords_struct()
Global NewList collPointsForFall.coords_struct()
Global NewList collPointsForJump.coords_struct()
; Player
Structure player_struct
x.f
y.f
z.f
xChunk.i
yChunk.i
zChunk.i
verticalSpeed.f ; Jumping or falling
onGround.b ; You can jump only if you're on the ground
EndStructure
Global player.player_struct
; Misc
Global wmain.i
Global mapSprite.i
EnableExplicit
;************************************************************************************
;- ---- Macros ----
;************************************************************************************
; Display FPS in a corner of the screen
Macro DISPLAY_FPS(timer)
; Display FPS
If showFps = #True
If timer - fpsTimer > 1000
StartDrawing(SpriteOutput(fpsSprite))
DrawText(0,0,Str(CountRenderedTriangles()) + " rendered polys, " + Str(Engine3DFrameRate(#PB_Engine3D_Current))+ " FPS " )
DrawText(0,20,"Chunk " + Str(player\xChunk) + "," + Str(player\zChunk) + " : " + Str(player\x) + "," + Str(player\y) + "," + Str(player\z) + " ")
StopDrawing()
fpsTimer = timer
EndIf
DisplayTransparentSprite(fpsSprite,0,0)
EndIf
EndMacro
; Check what kind of block is at x,y,z. If there's nothing or the coords are off-limit, result is zero.
Macro GETCELLCONTENT(x,y,z, result)
; If x < 0 Or x > #CHUNKWIDTH Or y < 0 Or y > #CHUNKHEIGHT Or z < 0 Or z > #CHUNKLENGTH
; result = 0
; Else
result = chunkArray(Int(x/(#CHUNKWIDTH+1)),Int(z/(#CHUNKLENGTH+1)))\chunk(x % (#CHUNKWIDTH+1),y,z % (#CHUNKLENGTH+1))\numMat
; EndIf
EndMacro
; Check if there's a visible side in the cube at x,y,z
; The result is stored in visibleSides as a six bits field ( %000001, %001010, etc..)
Macro CHECKVISIBLESIDES(xChunk,zChunk,x,y,z,visibleSides)
; Which sides of the cube are visible ?
visibleSides = 0
; Top
If y < #CHUNKHEIGHT And cubeMat(chunkArray(xChunk,zChunk)\chunk(x,(y)+1,z)\numMat)\opaque = 0
visibleSides | faceValue(#TOPSIDE)
EndIf
; Bottom
If y > 0 And cubeMat(chunkArray(xChunk,zChunk)\chunk(x,(y)-1,z)\numMat)\opaque = 0
visibleSides | faceValue(#BOTTOMSIDE)
EndIf
; Left
If x = 0
If chunkArray(xChunk-1,zChunk)\state >= #CHUNK_PREPARED And cubeMat(chunkArray(xChunk-1,zChunk)\chunk(#CHUNKWIDTH,y,z)\numMat)\opaque = 0
visibleSides | faceValue(#LEFTSIDE)
EndIf
Else
If cubeMat(chunkArray(xChunk,zChunk)\chunk((x)-1,y,z)\numMat)\opaque = 0
visibleSides | faceValue(#LEFTSIDE)
EndIf
EndIf
; Right
If x = #CHUNKWIDTH
If chunkArray(xChunk+1,zChunk)\state >= #CHUNK_PREPARED And cubeMat(chunkArray(xChunk+1,zChunk)\chunk(0,y,z)\numMat)\opaque = 0
visibleSides | faceValue(#RIGHTSIDE)
EndIf
Else
If cubeMat(chunkArray(xChunk,zChunk)\chunk((x)+1,y,z)\numMat)\opaque = 0
visibleSides | faceValue(#RIGHTSIDE)
EndIf
EndIf
; Back
If z = 0
If chunkArray(xChunk,zChunk-1)\state >= #CHUNK_PREPARED And cubeMat(chunkArray(xChunk,zChunk-1)\chunk(x,y,#CHUNKLENGTH)\numMat)\opaque = 0
visibleSides | faceValue(#BACKSIDE)
EndIf
Else
If cubeMat(chunkArray(xChunk,zChunk)\chunk(x,y,(z)-1)\numMat)\opaque = 0
visibleSides | faceValue(#BACKSIDE)
EndIf
EndIf
; Front
If z = #CHUNKLENGTH
If chunkArray(xChunk,zChunk+1)\state >= #CHUNK_PREPARED And cubeMat(chunkArray(xChunk,zChunk+1)\chunk(x,y,0)\numMat)\opaque = 0
visibleSides | faceValue(#FRONTSIDE)
EndIf
Else
If cubeMat(chunkArray(xChunk,zChunk)\chunk(x,y,(z)+1)\numMat)\opaque = 0
visibleSides | faceValue(#FRONTSIDE)
EndIf
EndIf
EndMacro
Macro ADDCHUNKTOQUEUE(xChunkAdded,zChunkAdded,newState)
AddElement(toDo())
toDo()\chunkCoordX = xChunkAdded
toDo()\chunkCoordZ = zChunkAdded
todo()\distance = (xChunkAdded - player\xChunk)*(xChunkAdded - player\xChunk) + (zChunkAdded - player\zChunk)*(zChunkAdded - player\zChunk)
; Manage closer chunks first
SortStructuredList(todo(),#PB_Sort_Ascending,OffsetOf(todo_struct\distance),#PB_Float)
chunkArray(xChunkAdded,zChunkAdded)\queued = #True
chunkArray(xChunkAdded,zChunkAdded)\state = newState
Debug "Adding to queue: " + Str(toDo()\chunkCoordX) + "," + Str(toDo()\chunkCoordZ) + " state = " + Str(newState)
EndMacro
Macro CHANGECHUNKSTATE(xChunkAdded,zChunkAdded,newState)
If chunkArray(xChunkAdded,zChunkAdded)\queued = #True
Debug "Changing state: " + Str(xChunkAdded) + "," + Str(zChunkAdded) + " state " + Str(chunkArray(xChunkAdded,zChunkAdded)\state) + " => " + Str(newState)
chunkArray(xChunkAdded,zChunkAdded)\state = newState
Else
ADDCHUNKTOQUEUE(xChunkAdded,zChunkAdded,newState)
EndIf
EndMacro
;************************************************************************************
;- ---- Procedures ----
;************************************************************************************
; Initializes the lists of points to check for collision
Procedure initializeCollisionPoints()
Protected x.f
Restore CollisionPointsForZMove
Read.f x
While x <> -999999
AddElement(collPointsForZ())
collPointsForZ()\x = x
Read.f collPointsForZ()\y
Read.f collPointsForZ()\z
Read.f x
Wend
Restore CollisionPointsForXMove
Read.f x
While x <> -999999
AddElement(collPointsForX())
collPointsForX()\x = x
Read.f collPointsForX()\y
Read.f collPointsForX()\z
Read.f x
Wend
Restore CollisionPointsForFalling
Read.f x
While x <> -999999
AddElement(collPointsForFall())
collPointsForFall()\x = x
Read.f collPointsForFall()\y
Read.f collPointsForFall()\z
Read.f x
Wend
Restore CollisionPointsForJumping
Read.f x
While x <> -999999
AddElement(collPointsForJump())
collPointsForJump()\x = x
Read.f collPointsForJump()\y
Read.f collPointsForJump()\z
Read.f x
Wend
EndProcedure
; Read and initialize the material
Procedure initializeMaterials()
Protected numMat.i, numtex.i
Protected matName.s, soundName.s
Restore MaterialDatas
Read.s matName
While matName <> "XXX END XXX"
numMat+1
; Texture
numTex = LoadTexture(#PB_Any,matName)
cubeMat(numMat)\mtIntact = CreateMaterial(#PB_Any,TextureID(numTex) )
MaterialFilteringMode(cubeMat(numMat)\mtIntact, #PB_Material_Anisotropic, 6)
; Sound when hit
Read.s soundName
If soundName <> ""
cubeMat(numMat)\soundWhenHit = LoadSound(#PB_Any,soundName)
EndIf
; Opaque or not
Read.b cubeMat(numMat)\opaque
If cubeMat(numMat)\opaque = #False
MaterialBlendingMode(cubeMat(numMat)\mtIntact, #PB_Material_AlphaBlend)
EndIf
; "Damaged" materials
cubeMat(numMat)\mtDamaged = CopyMaterial(cubeMat(numMat)\mtIntact,#PB_Any)
ScrollMaterial(cubeMat(numMat)\mtDamaged,0,0.25,#PB_Material_Fixed)
cubeMat(numMat)\mtAlmostBroken = CopyMaterial(cubeMat(numMat)\mtIntact,#PB_Any)
ScrollMaterial(cubeMat(numMat)\mtAlmostBroken,0,0.50,#PB_Material_Fixed)
; Solidity points lost when hit
Read.i cubeMat(numMat)\ptLossWhenHit
Read.s matName
Wend
EndProcedure
; Load or Build the needed meshes
Procedure buildCubeMeshes()
Protected i.i,j.i, k.i
Protected nbVert.i,nbFaces.i
Protected x.f,y.f,z.f
Protected nx.f,ny.f,nz.f
Protected u.f,v.f
Protected v1.i,v2.i,v3.i
Protected vertStart.i
Protected cubeMesh.i
; Create the directory where meshes are stored
If FileSize("meshes") <> -2
CreateDirectory("meshes")
EndIf
; Associate each face with a bit position in a 6 digits binary number.
; Top = %000001, Bottom = %000010, Left = %000100, etc..
For i=#TOPSIDE To #BACKSIDE
faceValue(i) = Pow(2,i)
Next i
; For each combination, create the mesh.
For i=%000001 To %111111
; Load the mesh
cubeMesh(i) = LoadMesh(#PB_Any,"cube_" + RSet(Bin(i),6,"0") + ".mesh")
If cubeMesh(i) = 0
; Create the mesh
Debug "Mesh " + "cube_" + RSet(Bin(i),6,"0") + ".mesh" + " not found; building it..."
vertStart = 0
cubeMesh(i) = CreateMesh(#PB_Any)
For j=#TOPSIDE To #BACKSIDE
; If the mesh must not have the current side, skip to the next.
If i & faceValue(j) = 0
Continue
EndIf
; Get the correct datas
Select j
Case #TOPSIDE
Restore meshTopDatas
Case #BOTTOMSIDE
Restore meshBottomDatas
Case #LEFTSIDE
Restore meshLeftDatas
Case #RIGHTSIDE
Restore meshRightDatas
Case #FRONTSIDE
Restore meshFrontDatas
Case #BACKSIDE
Restore meshBackDatas
EndSelect
; Read number of vertices and triangles
Read.i nbVert:Read.i nbFaces
; Add the vertices to mesh
For k = 1 To nbVert
Read.f x:Read.f y:Read.f z
Read.f nx:Read.f ny:Read.f nz
Read.f u:Read.f v
MeshVertexPosition(x,y,z)
MeshVertexNormal(nx,ny,nz)
MeshVertexTextureCoordinate(u,v)
Next k
; Add the triangles to mesh
For k = 1 To nbFaces
Read.i v1:Read.i v2:Read.i v3
MeshFace(v1+vertStart,v2+vertStart,v3+vertStart)
Next k
vertstart + nbVert
Next j
; Finalize mesh
FinishMesh(#True)
BuildMeshShadowVolume(cubeMesh(i))
BuildMeshTangents(cubeMesh(i))
SaveMesh(cubeMesh(i),"meshes/cube_" + RSet(Bin(i),6,"0") + ".mesh")
EndIf
; GetMeshData(cubeMesh(i),0,vertexInfos(),#PB_Mesh_Vertex|#PB_Mesh_UVCoordinate,0,MeshVertexCount(cubeMesh(i))-1 )
; GetMeshData(cubeMesh(i),0,faceInfos(),#PB_Mesh_Face,0,MeshVertexCount(cubeMesh(i))*1.5 -1 )
; cubeEntity(i) = CreateEntity(#PB_Any,MeshID(cubeMesh(i)),#PB_Material_None,-999+i,-999,-999)
; EntityRenderMode(cubeEntity(i),0)
; HideEntity(cubeEntity(i),#True)
Next i
boundingBox = CreateCube(#PB_Any,1)
EndProcedure
; Initialize a random world
Procedure prepareChunk(xChunk.i,zChunk.i)
Protected divW.f = 2 / (#WORLDWIDTH)
Protected divL.f = 2 / (#WORLDLENGTH)
Protected noise.d,height.i
Protected x.i,y.i,z.i, fill.i
For z = 0 To #CHUNKLENGTH
For x = 0 To #CHUNKWIDTH
noise = PERLIN_unsigned(PERLIN_generateNoise2D(divW * (x + xChunk * (#CHUNKWIDTH+1)), divL * (z + zChunk * (#CHUNKLENGTH+1)), 4, 4, 10))
height = 10 + Int(noise * (#CHUNKHEIGHT-20))
; Fill what's underground
For fill = height To 0 Step -1
chunkArray(xChunk,zChunk)\chunk(x,fill,z)\numMat = 1
Next fill
Next x
Next z
; Tree
; chunkArray(xChunk,zChunk)\chunk(14,21,14)\numMat = 3
; chunkArray(xChunk,zChunk)\chunk(14,22,14)\numMat = 3
; chunkArray(xChunk,zChunk)\chunk(14,23,14)\numMat = 3
; chunkArray(xChunk,zChunk)\chunk(14,24,14)\numMat = 3
; i=2
; For y = 0 To i
; For x = 0 To i
; For z = 0 To i
; If chunkArray(xChunk,zChunk)\chunk(13+x,23+y,13+z)\numMat = 0 And Random(100) > 25
; chunkArray(xChunk,zChunk)\chunk(13+x,23+y,13+z)\numMat = 4
; EndIf
; Next z
; Next x
; Next y
; Post-traitement: les cubes de terre avec rien au-dessus sont en herbe
For y = 0 To #CHUNKHEIGHT
For x = 0 To #CHUNKWIDTH
For z = 0 To #CHUNKLENGTH
If chunkArray(xChunk,zChunk)\chunk(x,y,z)\numMat > 0
chunkArray(xChunk,zChunk)\chunk(x,y,z)\solidity = 127
If chunkArray(xChunk,zChunk)\chunk(x,y,z)\numMat = 1 And y < #CHUNKHEIGHT And chunkArray(xChunk,zChunk)\chunk(x,y+1,z)\numMat = 0
chunkArray(xChunk,zChunk)\chunk(x,y,z)\numMat = 2
EndIf
EndIf
Next z
Next x
Next y
Debug "Chunk " + Str(xChunk) + "," + Str(zChunk) + " is prepared."
chunkArray(xchunk,zchunk)\state = #CHUNK_PREPARED
If chunkArray(xchunk-1,zchunk)\state >= #CHUNK_BUILT
CHANGECHUNKSTATE(xchunk-1,zchunk,#CHUNK_PREPARED)
EndIf
If chunkArray(xchunk+1,zchunk)\state >= #CHUNK_BUILT
CHANGECHUNKSTATE(xchunk+1,zchunk,#CHUNK_PREPARED)
EndIf
If chunkArray(xchunk,zchunk-1)\state >= #CHUNK_BUILT
CHANGECHUNKSTATE(xchunk,zchunk-1,#CHUNK_PREPARED)
EndIf
If chunkArray(xchunk,zchunk+1)\state >= #CHUNK_BUILT
CHANGECHUNKSTATE(xchunk,zchunk+1,#CHUNK_PREPARED)
EndIf
EndProcedure
; Create a mesh with the visibles parts of a chunk
Procedure buildChunk(xChunk.i=2,zChunk.i=2,xOri.i=0,yOri.i=0,zOri.i=0,xEnd.i=#CHUNKWIDTH,yEnd.i=#CHUNKHEIGHT,zEnd.i=#CHUNKLENGTH)
Protected x.i,y.i,z.i,i.i
Protected visibleSides.i, mat.i
Protected index.i
Protected Dim vertInfos.PB_MeshVertex(0)
Protected Dim faceInfos.PB_MeshFace(0)
Protected decalX.f,decalY.f,decalZ.f
Protected t.i
t = ElapsedMilliseconds()
If chunkArray(xChunk,zChunk)\numMesh <> 0
FreeMesh(chunkArray(xChunk,zChunk)\numMesh)
EndIf
chunkArray(xChunk,zChunk)\numMesh = CreateMesh(#PB_Any)
For y = yOri To yEnd
For x = xOri To xEnd
For z = zOri To zEnd
; Check if there's anything at x,y,z
If chunkArray(xChunk,zChunk)\chunk(x,y,z)\numMat > 0
; List the visible sides at this location
CHECKVISIBLESIDES(xChunk,zChunk,x,y,z,visibleSides)
; If there's at least one visible face, create the entity with the correct material
If visibleSides > 0
;If chunk(x,y,z)\solidity <= 64
; mat = MaterialID(cubeMat(chunk(x,y,z)\numMat)\mtAlmostBroken)
;ElseIf chunk(x,y,z)\solidity <= 96
; mat = MaterialID(cubeMat(chunk(x,y,z)\numMat)\mtDamaged)
;Else
; mat = MaterialID(cubeMat(chunk(x,y,z)\numMat)\mtIntact)
;EndIf
;SetEntityMaterial(cubeEntity(visibleSides),mat)
GetMeshData(cubeMesh(visibleSides),0,vertInfos(),#PB_Mesh_Vertex|#PB_Mesh_Normal|#PB_Mesh_UVCoordinate,0,MeshVertexCount(cubeMesh(visibleSides))-1 )
GetMeshData(cubeMesh(visibleSides),0,faceInfos(),#PB_Mesh_Face,0,MeshVertexCount(cubeMesh(visibleSides))*1.5 -1 )
For i = 0 To MeshVertexCount(cubeMesh(visibleSides))-1
MeshVertexPosition(vertInfos(i)\x+x,vertInfos(i)\y+y,vertInfos(i)\z+z)
MeshVertexNormal(vertInfos(i)\NormalX,vertInfos(i)\NormalY,vertInfos(i)\NormalZ)
MeshVertexTangent(vertInfos(i)\TangentX,vertInfos(i)\TangentY,vertInfos(i)\TangentZ)
MeshVertexTextureCoordinate(vertInfos(i)\u,vertInfos(i)\v)
Next i
For i = 0 To MeshVertexCount(cubeMesh(visibleSides))*1.5-1 Step 3
MeshFace(faceInfos(i)\Index + index,faceInfos(i+1)\Index + index,faceInfos(i+2)\Index + index)
Next i
index + MeshVertexCount(cubeMesh(visibleSides))
EndIf
EndIf
Next z
Next x
Next y
FinishMesh(chunkArray(xChunk,zChunk)\numMesh)
t = ElapsedMilliseconds()
chunkArray(xChunk,zChunk)\state = #CHUNK_BUILT
Debug "Chunk " + Str(xChunk) + "," + Str(zChunk) + " is built."
decalX = (#CHUNKWIDTH + 1) / 2 + xChunk * (#CHUNKWIDTH + 1)
decalY = (#CHUNKHEIGHT + 1) / 2
decalZ = (#CHUNKLENGTH + 1) / 2 + zChunk * (#CHUNKLENGTH + 1)
chunkArray(xChunk,zChunk)\boundingBoxEntity = CreateEntity(#PB_Any,MeshID(boundingBox),#PB_Material_None,decalX,decalY,decalZ)
ScaleEntity(chunkArray(xChunk,zChunk)\boundingBoxEntity,#CHUNKWIDTH+1,#CHUNKHEIGHT+1,#CHUNKLENGTH+1,#PB_Absolute)
HideEntity(chunkArray(xChunk,zChunk)\boundingBoxEntity,#True)
EndProcedure
Procedure displayWorld(xPlayer.i,yPlayer.i,zPlayer.i)
Protected x.i, z.i
Protected chunkEntity.i
Protected found.b
Protected t.i,t1.i, nbEnt.i
StartDrawing(SpriteOutput(mapSprite))
Box(0,0,80,80,$000000)
t = ElapsedMilliseconds()
CreateStaticGeometry(0, (#CHUNKWIDTH+1)*#WORLDWIDTH, (#CHUNKHEIGHT+1)*#WORLDHEIGHT, (#CHUNKLENGTH+1)*#WORLDLENGTH, #False)
For z = zPlayer-5 To zPlayer+5
For x = xPlayer-5 To xPlayer+5
Box((x-xPlayer+5)*8,(z-zPlayer+5)*8,7,7,$777777)
; If the chunk is not in the viewing range, skip it
If (x - xPlayer)*(x - xPlayer) + (z - zPlayer)*(z - zPlayer) > #VIEWING_RANGE
Continue
EndIf
; If it's in the viewing range but not built yet, add it to queue (if not queued already) and skip
If chunkArray(x,z)\numMesh = 0
If chunkArray(x,z)\queued = #False
ADDCHUNKTOQUEUE(x,z,chunkArray(x,z)\state) ; don't change chunk's state
EndIf
Continue
EndIf
; If the chunk is built and visible, add it to static geometry
If CheckObjectVisibility(#CAMERA,EntityID(chunkArray(x,z)\boundingBoxEntity))
Box((x-xPlayer+5)*8,(z-zPlayer+5)*8,7,7,$FFFFFF)
chunkEntity = CreateEntity(#PB_Any,MeshID(chunkArray(x,z)\numMesh),MaterialID(cubeMat(2)\mtIntact))
AddStaticGeometryEntity(0, EntityID(chunkEntity), x * (#CHUNKWIDTH+1),0,z * (#CHUNKLENGTH+1))
FreeEntity(chunkEntity)
If chunkArray(x,z)\state = #CHUNK_BUILT
chunkArray(x,z)\state = #CHUNK_RENDERED
EndIf
nbEnt + 1
Else
; Not on screen but previously rendered? => goes back to "built" state
If chunkArray(x,z)\state = #CHUNK_RENDERED
chunkArray(x,z)\state = #CHUNK_BUILT
EndIf
EndIf
Next x
Next z
Box(5*8+1,5*8+1,5,5,$0000FF)
StopDrawing()
t1 = ElapsedMilliseconds()
BuildStaticGeometry(0)
Debug "Building static geometry : " + Str(ElapsedMilliseconds() - t1) + " ms."
If nbEnt > 0
Debug "----------"
Debug "Rendered " + Str(nbEnt) + " chunks in " + Str(ElapsedMilliseconds() - t) + " ms."
EndIf
EndProcedure
Procedure deleteCube(x.i,y.i,z.i)
Protected i.i
Protected xOri.i,yOri.i,zOri.i
Protected xEnd.i,yEnd.i,zEnd.i
Protected xChunk.i,zChunk.i
; Delete the block
xChunk = Int(x / (#CHUNKWIDTH+1))
zChunk = Int(z / (#CHUNKLENGTH+1))
x = (x % (#CHUNKWIDTH+1))
z = (z % (#CHUNKLENGTH+1))
If chunkArray(xChunk,zChunk)\chunk(x,y,z)\solidity =< 0
chunkArray(xChunk,zChunk)\chunk(x,y,z)\numMat = 0
; Set the limits of the borders scan
xOri = x-1
If xOri < 0: xOri = 0 : EndIf
yOri = y-1
If yOri < 0: yOri = 0 : EndIf
zOri = z-1
If zOri < 0: zOri = 0 : EndIf
xEnd = x+1
If xEnd > #CHUNKWIDTH: xEnd = #CHUNKWIDTH : EndIf
yEnd = y+1
If yEnd > #CHUNKHEIGHT: yEnd = #CHUNKHEIGHT : EndIf
zEnd = z+1
If zEnd > #CHUNKLENGTH: zEnd = #CHUNKLENGTH : EndIf
Else
; The block is still here; no need to redraw the surroundings.
xOri = x: yOri=y: zOri = z
xEnd = x: yEnd=y: zEnd = z
EndIf
; Update the display with the changes we've just made.
;displayWorld(xOri,yOri,zOri,xEnd,yEnd,zEnd) ; redraw only what's necessary
If x = 0 And chunkArray(xChunk-1,zChunk)\state >= #CHUNK_BUILT
CHANGECHUNKSTATE(xChunk-1,zChunk,#CHUNK_PREPARED)
EndIf
If x = #CHUNKWIDTH And chunkArray(xChunk+1,zChunk)\state >= #CHUNK_BUILT
CHANGECHUNKSTATE(xChunk+1,zChunk,#CHUNK_PREPARED)
EndIf
If z = 0 And chunkArray(xChunk,zChunk-1)\state >= #CHUNK_BUILT
CHANGECHUNKSTATE(xChunk,zChunk-1,#CHUNK_PREPARED)
EndIf
If z = #CHUNKLENGTH And chunkArray(xChunk,zChunk+1)\state >= #CHUNK_BUILT
CHANGECHUNKSTATE(xChunk,zChunk+1,#CHUNK_PREPARED)
EndIf
CHANGECHUNKSTATE(xChunk,zChunk,#CHUNK_PREPARED) ; chunk is already prepared. Now rebuild and render it.
EndProcedure
;************************************************************************************
;- ---- Game Procedure ----
;************************************************************************************
Procedure playGame()
Protected wireframe.b, viewBodies.b, dontQuit.b = #True, eventId.i
Protected mousePick.b, mouseX.f, mouseY.f, mouseClickable.b, visibleSides.i
Protected xPick.i,yPick.i,zPick.i, result.b
Protected xdir.f,ydir.f,zdir.f
Protected fpsSprite.i, fpsTimer.i, showFps.b = #True
Protected timer.i, oldTimer.i, loopTime.f
Protected cursorMesh.i, mtCursor.i, cursor.i
Protected isDayTime.b, i.i,j.i
Protected oldxChunk.i, oldzChunk.i
Protected oldx.f,oldy.f,oldz.f,newX.f,newY.f,newZ.f
Protected xColl.i,yColl.i,zColl.i
Protected oldTimerRefresh.i
Protected mustRedraw.b
;- Sprite used to display FPS
fpsSprite = CreateSprite(#PB_Any,640,38)
mapSprite = CreateSprite(#PB_Any,90,90)
;- Camera
CreateCamera(#CAMERA, 0, 0, 100, 100)
CameraBackColor(#CAMERA,$000000)
;CameraFOV(#CAMERA,60)
;-Light
CreateLight(1,$FFFFFF,CameraX(#CAMERA),CameraY(#CAMERA),CameraZ(#CAMERA))
LightAttenuation(1,20,0)
WorldShadows(#PB_Shadow_Additive)
Fog($000000,50,10,30)
;- 3D cursor
cursorMesh = CreateCube(#PB_Any,1.1)
mtCursor = CreateMaterial(#PB_Any,TextureID(LoadTexture(#PB_Any,"cursor.png")))
DisableMaterialLighting(mtCursor,#True)
MaterialShadingMode(mtCursor,#PB_Material_Flat|#PB_Material_Wireframe)
ScrollMaterial(mtCursor, 1, 1, #PB_Material_Animated)
cursor = CreateEntity(#PB_Any,MeshID(cursorMesh),MaterialID(mtCursor),16,22,16,$00010)
EntityRenderMode(cursor,0)
DisableEntityBody(cursor,#True)
;- World
RandomSeed(123456789) ; Change this to change the world !
player\x = 328 : player\y = 60 : player\z = 328
player\xChunk = Int(player\x/(#CHUNKWIDTH+1))
player\zChunk = Int(player\z/(#CHUNKLENGTH+1))
oldxChunk = player\xChunk
oldzChunk = player\zChunk
ADDCHUNKTOQUEUE(player\xChunk,player\zChunk,#CHUNK_NOSTATE)
;- Main loop
oldTimer = ElapsedMilliseconds()
KeyboardMode(#PB_Keyboard_International)
Repeat
Delay(1)
; Windows events
eventID = WindowEvent()
While eventID <> 0 And dontQuit = #True
eventID = WindowEvent()
Wend
ExamineKeyboard()
;- Function keys (W, P, L)
; Activate wireframe render
If KeyboardReleased(#PB_Key_W)
wireframe = 1-wireframe
If wireframe = #True
CameraRenderMode(0,#PB_Camera_Wireframe)
Else
CameraRenderMode(0,#PB_Camera_Textured)
EndIf
EndIf
; Activate physics render
If KeyboardReleased(#PB_Key_P)
viewBodies = 1-viewBodies
If viewBodies = #True
WorldDebug(#PB_World_DebugBody)
Else
WorldDebug(#PB_World_DebugNone)
EndIf
EndIf
; Change day / night
If KeyboardReleased(#PB_Key_L)
isDayTime = 1 - isDayTime
If isDayTime = #True
AmbientColor($777777)
CreateLight(0,$FFFFFF,2000,4000,3000)
CameraBackColor(#CAMERA,$D9A789)
LightAttenuation(1,10,1)
Fog($C2AF80,20,10,100)
Else
FreeLight(0)
CameraBackColor(#CAMERA,$000000)
LightAttenuation(1,20,0)
Fog($000000,50,10,30)
EndIf
EndIf
If KeyboardReleased(#PB_Key_R)
mustRedraw = #True
EndIf
;- Movements (mouse + arrows)
timer = ElapsedMilliseconds()
loopTime = 1 + (timer - oldtimer)
If looptime > 32
looptime = 32
EndIf
oldtimer = timer
; Look around
If ExamineMouse()
MouseX = -(MouseDeltaX()/20)
MouseY = -(MouseDeltaY()/20)
If MouseX <> 0
For j = player\zChunk - 5 To player\zChunk + 5
For i = player\xChunk -5 To player\xChunk +5
If (i - player\xChunk )*(i - player\xChunk ) + (j - player\zChunk )*(j - player\zChunk ) <= #VIEWING_RANGE
If chunkArray(i,j)\state = #CHUNK_BUILT And CheckObjectVisibility(#CAMERA,EntityID(chunkArray(i,j)\boundingBoxEntity))
mustRedraw = #True
Break 2
EndIf
EndIf
Next i
Next j
EndIf
RotateCamera(#CAMERA, MouseY, MouseX, 0, #PB_Relative)
EndIf
xdir = CameraDirectionX(#CAMERA)
ydir = CameraDirectionY(#CAMERA)
zdir = CameraDirectionZ(#CAMERA)
oldx = player\x : oldy = player\y : oldz = player\z
newX = oldX : newY = oldY : newZ = oldZ
; Walk
If KeyboardPushed(#PB_Key_Up)
newX + xDir * (#CAMERASPEED * loopTime)
newZ + zDir * (#CAMERASPEED * loopTime)
EndIf
If KeyboardPushed(#PB_Key_Down)
newX - xDir * (#CAMERASPEED * loopTime)
newZ - zDir * (#CAMERASPEED * loopTime)
EndIf
; Strafe
If KeyboardPushed(#PB_Key_Left)
newX + (xDir*Cos(Radian(90)) + zDir*Sin(Radian(90))) * (#CAMERASPEED * loopTime)
newZ + (-xDir*Sin(Radian(90)) + zDir*Cos(Radian(90))) * (#CAMERASPEED * loopTime)
EndIf
If KeyboardPushed(#PB_Key_Right)
newX - (xDir*Cos(Radian(90)) + zDir*Sin(Radian(90))) * (#CAMERASPEED * loopTime)
newZ - (-xDir*Sin(Radian(90)) + zDir*Cos(Radian(90))) * (#CAMERASPEED * loopTime)
EndIf
; Jump
If KeyboardPushed(#PB_Key_Space) And player\onGround = #True
player\verticalSpeed = 0.015
EndIf
;- Collisions
If newZ <> oldZ
ForEach collPointsForZ()
xColl = oldX + collPointsForZ()\x
yColl = oldY + collPointsForZ()\y
zColl = newZ + collPointsForZ()\z
GETCELLCONTENT(xColl,yColl,zColl, result)
If result > 0
newZ = oldZ
Break
EndIf
Next collPointsForZ()
player\zChunk = Int(player\z / (#CHUNKLENGTH+1))
If oldzChunk <> player\zChunk
mustRedraw = #True
oldzChunk = player\zChunk
EndIf
EndIf
If newX <> oldX
ForEach collPointsForX()
xColl = newX + collPointsForX()\x
yColl = oldY + collPointsForX()\y
zColl = oldZ + collPointsForX()\z
GETCELLCONTENT(xColl,yColl,zColl, result)
If result > 0
newX = oldX
Break
EndIf
Next collPointsForX()
player\xChunk = Int(player\x / (#CHUNKWIDTH+1))
If oldxChunk <> player\xChunk
mustRedraw = #True
oldxChunk = player\xChunk
EndIf
EndIf
; Gravity
If player\verticalSpeed > -0.02
player\verticalSpeed - (0.000055 * loopTime)
EndIf
newY + (player\verticalSpeed * loopTime)
player\onGround = #False
If player\verticalSpeed < 0
ForEach collPointsForFall()
xColl = oldX + collPointsForFall()\x
yColl = newY + collPointsForFall()\y
zColl = oldZ + collPointsForFall()\z
GETCELLCONTENT(xColl,yColl,zColl, result)
If result > 0
newY = oldY
player\verticalSpeed = 0
player\onGround = #True
Break
EndIf
Next collPointsForFall()
Else
ForEach collPointsForJump()
xColl = oldX + collPointsForJump()\x
yColl = newY + collPointsForJump()\y
zColl = oldZ + collPointsForJump()\z
GETCELLCONTENT(xColl,yColl,zColl, result)
If result > 0
newY = oldY
player\verticalSpeed = 0
Break
EndIf
Next collPointsForJump()
EndIf
; Now, we can place the player and the camera at their new position
player\x = newX : player\y = newY : player\z = newZ
MoveCamera(#CAMERA,player\x - xDir/2,player\y + 1.7 - yDir/2,player\z - zdir/2,#PB_Absolute)
MoveLight(1,player\x,player\y + 1.5,player\z,#PB_Absolute)
;- Left button click
; Get camera's direction and check if there's something in this direction
mousePick = #False
For i = 1 To 4
xPick = player\x + xdir * i
yPick = player\y + 1.7 + ydir * i
zPick = player\z + zdir * i
; Boundary check
GETCELLCONTENT(xPick,yPick,zPick, result)
; The search is over as soon as we find something visible
If result > 0
CHECKVISIBLESIDES( Int(xPick/(#CHUNKWIDTH+1)),Int(zPick/(#CHUNKLENGTH+1)),(xPick % (#CHUNKWIDTH+1)),yPick,(zPick % (#CHUNKLENGTH+1)), visibleSides)
If visibleSides <> 0
mousePick = #True
Break
EndIf
EndIf
Next i
; If the mousepick was succesfull, allow the player to dig.
If mousePick = #True
HideEntity(cursor,#False)
MoveEntity(cursor,xPick,yPick,zPick, #PB_Absolute)
If MouseButton(#PB_MouseButton_Left) <> 0
If mouseClickable = #True
mouseClickable = #False
If cubeMat(chunkArray(Int(xPick / (#CHUNKWIDTH+1)),Int(zPick / (#CHUNKLENGTH+1)))\chunk((xPick % (#CHUNKWIDTH+1)),yPick,(zPick % (#CHUNKLENGTH+1)))\numMat)\soundWhenHit <> 0
PlaySound(cubeMat(chunkArray(Int(xPick / (#CHUNKWIDTH+1)),Int(zPick / (#CHUNKLENGTH+1)))\chunk((xPick % (#CHUNKWIDTH+1)),yPick,(zPick % (#CHUNKLENGTH+1)))\numMat)\soundWhenHit,#PB_Sound_MultiChannel)
EndIf
chunkArray(Int(xPick / (#CHUNKWIDTH+1)),Int(zPick / (#CHUNKLENGTH+1)))\chunk((xPick % (#CHUNKWIDTH+1)),yPick,(zPick % (#CHUNKLENGTH+1)))\solidity - cubeMat(chunkArray(Int(xPick / (#CHUNKWIDTH+1)),Int(zPick / (#CHUNKLENGTH+1)))\chunk((xPick % (#CHUNKWIDTH+1)),yPick,(zPick % (#CHUNKLENGTH+1)))\numMat)\ptLossWhenHit
deleteCube(xPick,yPick,zPick)
EndIf
Else
mouseClickable = #True
EndIf
Else
HideEntity(cursor,#True)
EndIf
;- Prepare the display
If ListSize(toDo()) > 0
FirstElement(toDo())
;Debug Str(toDo()\chunkCoordX) + "," + Str(toDo()\chunkCoordZ) + ":" + Str(chunkArray(toDo()\chunkCoordX,toDo()\chunkCoordZ)\prepared) + " | " + Str(chunkArray(toDo()\chunkCoordX,toDo()\chunkCoordZ)\built) + " | " + Str(chunkArray(toDo()\chunkCoordX,toDo()\chunkCoordZ)\rendered)
If chunkArray(toDo()\chunkCoordX,toDo()\chunkCoordZ)\state < #CHUNK_PREPARED
prepareChunk(toDo()\chunkCoordX,toDo()\chunkCoordZ)
ElseIf chunkArray(toDo()\chunkCoordX,toDo()\chunkCoordZ)\state < #CHUNK_BUILT
buildChunk(toDo()\chunkCoordX,toDo()\chunkCoordZ)
ElseIf chunkArray(toDo()\chunkCoordX,toDo()\chunkCoordZ)\state = #CHUNK_BUILT
chunkArray(toDo()\chunkCoordX,toDo()\chunkCoordZ)\queued = #False
DeleteElement(toDo())
mustRedraw = #True
EndIf
EndIf
If mustRedraw = #True
displayWorld(player\xChunk,0,player\zChunk)
mustRedraw = #False
EndIf
;- Render
RenderWorld()
;- Display FPS
DISPLAY_FPS(timer)
DisplayTransparentSprite(mapSprite,700,0)
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape) Or dontQuit = #False
FreeCamera(#PB_All)
FreeLight(#PB_All)
EndProcedure
;************************************************************************************
;- ---- Main program ----
;************************************************************************************
;- Initialization
InitEngine3D()
InitSprite()
InitKeyboard()
InitMouse()
UsePNGImageDecoder()
Add3DArchive("textures",#PB_3DArchive_FileSystem)
Add3DArchive("meshes",#PB_3DArchive_FileSystem)
;- Window
OpenWindow(Wmain,0, 0, #SCREENWIDTH,#SCREENHEIGHT ,"Cube environnement",#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(Wmain), 0, 0, #SCREENWIDTH,#SCREENHEIGHT, 0, 0, 0,#PB_Screen_NoSynchronization)
;-Materials
initializeMaterials()
;- Meshes
buildCubeMeshes()
;- Prepare collision checks
initializeCollisionPoints()
;- Game
playGame()
End
;************************************************************************************
;- ---- Datas ----
;************************************************************************************
;- Meshes datas
DataSection
meshTopDatas:
; Nb vertices, nb triangles
Data.i 4,2
; Vertices: pos / normals / uv
Data.f -0.5,0.5,-0.5
Data.f 0,1,0
Data.f 0,0
Data.f 0.5,0.5,-0.5
Data.f 0,1,0
Data.f 0.25,0
Data.f 0.5,0.5,0.5
Data.f 0,1,0
Data.f 0.25,0.25
Data.f -0.5,0.5,0.5
Data.f 0,1,0
Data.f 0,0.25
; Faces
Data.i 2,1,0
Data.i 0,3,2
MeshBottomDatas:
; Nb vertices, nb triangles
Data.i 4,2
; Vertices: pos / normals / uv
Data.f -0.50,-0.50,0.50
Data.f 0.00,-1.00,0.00
Data.f 0.50,0.00
Data.f 0.50,-0.50,0.50
Data.f 0.00,-1.00,0.00
Data.f 0.75,0.00
Data.f 0.50,-0.50,-0.50
Data.f 0.00,-1.00,0.00
Data.f 0.75,0.25
Data.f -0.50,-0.50,-0.50
Data.f 0.00,-1.00,0.00
Data.f 0.50,0.25
; Faces
Data.i 2,1,0
Data.i 0,3,2
MeshLeftDatas:
; Nb vertices, nb triangles
Data.i 4,2
; Vertices: pos / normals / uv
Data.f -0.50,0.50,-0.50
Data.f -1.00,0.00,0.00
Data.f 0.25,0.00
Data.f -0.50,0.50,0.50
Data.f -1.00,0.00,0.00
Data.f 0.50,0.00
Data.f -0.50,-0.50,0.50
Data.f -1.00,0.00,0.00
Data.f 0.50,0.25
Data.f -0.50,-0.50,-0.50
Data.f -1.00,0.00,0.00
Data.f 0.25,0.25
; Faces
Data.i 2,1,0
Data.i 0,3,2
MeshRightDatas:
; Nb vertices, nb triangles
Data.i 4,2
; Vertices: pos / normals / uv
Data.f 0.50,0.50,0.50
Data.f 1.00,0.00,0.00
Data.f 0.25,0.00
Data.f 0.50,0.50,-0.50
Data.f 1.00,0.00,0.00
Data.f 0.50,0.00
Data.f 0.50,-0.50,-0.50
Data.f 1.00,0.00,0.00
Data.f 0.50,0.25
Data.f 0.50,-0.50,0.50
Data.f 1.00,0.00,0.00
Data.f 0.25,0.25
; Faces
Data.i 2,1,0
Data.i 0,3,2
MeshFrontDatas:
; Nb vertices, nb triangles
Data.i 4,2
; Vertices: pos / normals / uv
Data.f -0.50,0.50,0.50
Data.f 0.00,0.00,1.00
Data.f 0.25,0.00
Data.f 0.50,0.50,0.50
Data.f 0.00,0.00,1.00
Data.f 0.50,0.00
Data.f 0.50,-0.50,0.50
Data.f 0.00,0.00,1.00
Data.f 0.50,0.25
Data.f -0.50,-0.50,0.50
Data.f 0.00,0.00,1.00
Data.f 0.25,0.25
; Faces
Data.i 2,1,0
Data.i 0,3,2
MeshBackDatas:
; Nb vertices, nb triangles
Data.i 4,2
; Vertices: pos / normals / uv
Data.f 0.50,0.50,-0.50
Data.f 0.00,0.00,-1.00
Data.f 0.25,0.00
Data.f -0.50,0.50,-0.50
Data.f 0.00,0.00,-1.00
Data.f 0.50,0.00
Data.f -0.50,-0.50,-0.50
Data.f 0.00,0.00,-1.00
Data.f 0.50,0.25
Data.f 0.50,-0.50,-0.50
Data.f 0.00,0.00,-1.00
Data.f 0.25,0.25
; Faces
Data.i 2,1,0
Data.i 0,3,2
;- Materials datas
MaterialDatas:
Data.s "ground.png", "" ; texture, sound
Data.b #True ; opaque or not
Data.i 48 ; solidity points lost when hit
Data.s "grass.png", ""
Data.b #True
Data.i 48
Data.s "wood.png", ""
Data.b #True
Data.i 48
Data.s "leaf.png", ""
Data.b #False
Data.i 128
Data.s "XXX END XXX"
;- Collision points datas
CollisionPointsForZMove:
Data.f -0.45, 0 ,-0.45
Data.f 0.45 , 0 ,-0.45
Data.f -0.45, 0 ,0.45
Data.f 0.45 , 0 ,0.45
Data.f -0.45, 0.9 ,-0.45
Data.f 0.45 , 0.9 ,-0.45
Data.f -0.45, 0.9 ,0.45
Data.f 0.45 , 0.9 ,0.45
Data.f -0.45, 1.8 ,-0.45
Data.f 0.45 , 1.8 ,-0.45
Data.f -0.45, 1.8 ,0.45
Data.f 0.45 , 1.8 ,0.45
Data.f -999999
CollisionPointsForXMove:
Data.f -0.45, 0 ,-0.45
Data.f -0.45 , 0 ,0.45
Data.f 0.45, 0 ,-0.45
Data.f 0.45 , 0 ,0.45
Data.f -0.45, 0.9 ,-0.45
Data.f -0.45 , 0.9 ,0.45
Data.f 0.45, 0.9 ,-0.45
Data.f 0.45 , 0.9 ,0.45
Data.f -0.45, 1.8 ,-0.45
Data.f -0.45 , 1.8 ,0.45
Data.f 0.45, 1.8 ,-0.45
Data.f 0.45 , 1.8 ,0.45
Data.f -999999
CollisionPointsForFalling:
Data.f -0.45, 0 ,-0.45
Data.f -0.45 , 0 ,0.45
Data.f 0.45, 0 ,-0.45
Data.f 0.45 , 0 ,0.45
Data.f -999999
CollisionPointsForJumping:
Data.f -0.45, 1.8 ,-0.45
Data.f -0.45 , 1.8 ,0.45
Data.f 0.45, 1.8 ,-0.45
Data.f 0.45 , 1.8 ,0.45
Data.f -999999
EndDataSection
Code : Tout sélectionner
;************************************************************************************
;- ---- Constants, structures, globals ----
;************************************************************************************
#PERLIN_B = $100
#PERLIN_BM = $FF
#PERLIN_N = $1000
#PERLIN_NP = 16 ; 2^N
#PERLIN_NM = $FF
Structure PERLIN_InnerDoubleArray
d.d[0]
EndStructure
Global Dim PERLIN_p.i(#PERLIN_B + #PERLIN_B + 1)
Global Dim PERLIN_g1.d(#PERLIN_B + #PERLIN_B + 1)
Global Dim PERLIN_g2.d(#PERLIN_B + #PERLIN_B + 1, 1)
Global Dim PERLIN_g3.d(#PERLIN_B + #PERLIN_B + 1, 2)
Global PERLIN_start.i = 1
;************************************************************************************
;- ---- Macros ----
;************************************************************************************
Macro PERLIN_unsigned(value)
((value) + 1) / 2
EndMacro
Macro PERLIN_s_curve(t)
( t * t * ( 3 - 2 * t ) )
EndMacro
Macro PERLIN_lerp(t, a, b)
( a + t * (b - a) )
EndMacro
Macro PERLIN_setup(i,b0,b1,r0,r1)
t = vec(i) + #PERLIN_N
b0 = Int(t) & #PERLIN_BM
b1 = (b0 + 1) & #PERLIN_BM
r0 = t - Int(t)
r1 = r0 - 1.
EndMacro
Macro PERLIN_at2(rx,ry)
( rx * *q\d[0] + ry * *q\d[1] )
EndMacro
Macro PERLIN_at3(rx,ry,rz)
( rx * *q\d[0] + ry * *q\d[1] + rz * *q\d[2] )
EndMacro
;************************************************************************************
;- ---- Procedures ----
;************************************************************************************
Declare PERLIN_initialize()
Declare.d PERLIN_noise1(arg.d)
Declare.d PERLIN_noise2(Array vec.d(1))
Declare.d PERLIN_noise3(Array vec.d(1))
Declare PERLIN_normalize2(d.i)
Declare PERLIN_normalize3(d.i)
Declare.d PERLIN_generateNoise1D(x.d, alpha.d, beta.d, n.i);
Declare.d PERLIN_generateNoise2D(x.d, y.d, alpha.d, beta.d, n.i);
Declare.d PERLIN_generateNoise3D(x.d, y.d, z.d, alpha.d, beta.d, n.i);
Procedure.d PERLIN_noise1(arg.d)
Protected bx0.i, bx1.i
Protected rx0.d, rx1.d, sx.d, t.d, u.d, v.d
Protected Dim vec.d(1)
vec(0) = arg
If PERLIN_start <> 0
PERLIN_start = 0
PERLIN_initialize()
EndIf
PERLIN_setup(0,bx0,bx1,rx0,rx1)
sx = PERLIN_s_curve(rx0)
u = rx0 * PERLIN_g1( PERLIN_p( bx0 ) )
v = rx1 * PERLIN_g1( PERLIN_p( bx1 ) )
ProcedureReturn PERLIN_lerp(sx, u, v)
EndProcedure
Procedure.d PERLIN_noise2(Array vec.d(1))
Protected bx0.i, bx1.i, by0.i, by1.i, b00.i, b10.i, b01.i, b11.i
Protected rx0.d, rx1.d, ry0.d, ry1.d, *q.PERLIN_InnerDoubleArray, sx.d, sy.d, a.d, b.d, t.d, u.d, v.d
Protected i.i, j.i
If PERLIN_start <> 0
PERLIN_start = 0
PERLIN_initialize()
EndIf
PERLIN_setup(0, bx0,bx1, rx0,rx1)
PERLIN_setup(1, by0,by1, ry0,ry1)
i = PERLIN_p( bx0 )
j = PERLIN_p( bx1 )
b00 = PERLIN_p( i + by0 )
b10 = PERLIN_p( j + by0 )
b01 = PERLIN_p( i + by1 )
b11 = PERLIN_p( j + by1 )
sx = PERLIN_s_curve(rx0)
sy = PERLIN_s_curve(ry0)
*q = @PERLIN_g2( b00, 0 ) : u = PERLIN_at2(rx0,ry0)
*q = @PERLIN_g2( b10, 0 ) : v = PERLIN_at2(rx1,ry0)
a = PERLIN_lerp(sx, u, v)
*q = @PERLIN_g2( b01, 0 ) : u = PERLIN_at2(rx0,ry1)
*q = @PERLIN_g2( b11, 0 ) : v = PERLIN_at2(rx1,ry1)
b = PERLIN_lerp(sx, u, v)
Protected rv.d = PERLIN_lerp(sy, a, b)
ProcedureReturn rv
EndProcedure
Procedure.d PERLIN_noise3(Array vec.d(1))
Protected bx0.i, bx1.i, by0.i, by1.i, bz0.i, bz1.i, b00.i, b10.i, b01.i, b11.i
Protected rx0.d, rx1.d, ry0.d, ry1.d, rz0.d, rz1.d, *q.PERLIN_InnerDoubleArray, sy.d, sz.d, a.d, b.d, c.d, d.d, t.d, u.d, v.d
Protected i.i, j.i
If PERLIN_start <> 0
PERLIN_start = 0
PERLIN_initialize()
EndIf
PERLIN_setup(0, bx0,bx1, rx0,rx1);
PERLIN_setup(1, by0,by1, ry0,ry1);
PERLIN_setup(2, bz0,bz1, rz0,rz1);
i = PERLIN_p( bx0 )
j = PERLIN_p( bx1 )
b00 = PERLIN_p( i + by0 )
b10 = PERLIN_p( j + by0 )
b01 = PERLIN_p( i + by1 )
b11 = PERLIN_p( j + by1 )
t = PERLIN_s_curve(rx0)
sy = PERLIN_s_curve(ry0)
sz = PERLIN_s_curve(rz0)
*q = @PERLIN_g3( b00 + bz0, 0 ) : u = PERLIN_at3(rx0,ry0,rz0)
*q = @PERLIN_g3( b10 + bz0, 0 ) : v = PERLIN_at3(rx1,ry0,rz0)
a = PERLIN_lerp(t, u, v)
*q = @PERLIN_g3( b01 + bz0, 0 ) : u = PERLIN_at3(rx0,ry1,rz0);
*q = @PERLIN_g3( b11 + bz0, 0 ) : v = PERLIN_at3(rx1,ry1,rz0);
b = PERLIN_lerp(t, u, v);
c = PERLIN_lerp(sy, a, b);
*q = @PERLIN_g3( b00 + bz1, 0 ) : u = PERLIN_at3(rx0,ry0,rz1);
*q = @PERLIN_g3( b10 + bz1, 0 ) : v = PERLIN_at3(rx1,ry0,rz1);
a = PERLIN_lerp(t, u, v);
*q = @PERLIN_g3( b01 + bz1, 0 ) : u = PERLIN_at3(rx0,ry1,rz1);
*q = @PERLIN_g3( b11 + bz1, 0 ) : v = PERLIN_at3(rx1,ry1,rz1);
b = PERLIN_lerp(t, u, v);
d = PERLIN_lerp(sy, a, b);
ProcedureReturn PERLIN_lerp(sz, c, d);
EndProcedure
Procedure PERLIN_normalize2(*v.PERLIN_InnerDoubleArray)
Protected s.d = Sqr(*v\d[0] * *v\d[0] + *v\d[1] * *v\d[1])
*v\d[0] = *v\d[0] / s
*v\d[1] = *v\d[1] / s
EndProcedure
Procedure PERLIN_normalize3(*v.PERLIN_InnerDoubleArray)
Protected s.d = Sqr(*v\d[0] * *v\d[0] + *v\d[1] * *v\d[1] + *v\d[2] * *v\d[2])
*v\d[0] = *v\d[0] / s
*v\d[1] = *v\d[1] / s
*v\d[2] = *v\d[2] / s
EndProcedure
Procedure PERLIN_initialize()
Protected i.i, j.i, k.i, tmp.i
Protected *t.PERLIN_InnerDoubleArray
i = 0
While i < #PERLIN_B
PERLIN_p(i) = i
tmp = ((Random(2147483647) % (#PERLIN_B + #PERLIN_B)) - #PERLIN_B)
PERLIN_g1(i) = tmp / #PERLIN_B
For j = 0 To 1
tmp = ((Random(2147483647) % (#PERLIN_B + #PERLIN_B)) - #PERLIN_B)
PERLIN_g2(i, j) = tmp / #PERLIN_B
Next j
PERLIN_normalize2(@PERLIN_g2(i, 0))
For j = 0 To 2
tmp = ((Random(2147483647) % (#PERLIN_B + #PERLIN_B)) - #PERLIN_B)
PERLIN_g3(i, j) = tmp / #PERLIN_B
Next j
PERLIN_normalize3(@PERLIN_g3(i, 0))
i + 1
Wend
i - 1
While i > 0
i - 1
k = PERLIN_p(i)
j = Random(2147483647) % #PERLIN_B
PERLIN_p(i) = PERLIN_p(j)
PERLIN_p(j) = k;
Wend
i = 0
While i < #PERLIN_B + 2
PERLIN_p(#PERLIN_B + i) = PERLIN_p(i)
PERLIN_g1(#PERLIN_B + i) = PERLIN_g1(i)
For j = 0 To 1
PERLIN_g2(#PERLIN_B + i, j) = PERLIN_g2(i, j)
Next j
For j = 0 To 2
PERLIN_g3(#PERLIN_B + i, j) = PERLIN_g3(i, j)
Next j
i + 1
Wend
EndProcedure
Procedure.d PERLIN_generateNoise1D(x.d, alpha.d, beta.d, iterations.i)
Protected i.i
Protected val.d = 0, sum.d = 0
Protected p.d = 1, scale.d = 1
p = x
For i = 1 To iterations
val = PERLIN_noise1(p)
sum + val / scale
scale * alpha
p * beta
Next i
ProcedureReturn(sum)
EndProcedure
Procedure.d PERLIN_generateNoise2D(x.d ,y.d, alpha.d, beta.d, iterations.i)
Protected i.i
Protected val.d = 0, sum.d = 0
Protected scale.d = 1
Protected Dim args.d(1)
args(0) = x
args(1) = y
For i = 1 To iterations
val = PERLIN_noise2(args())
sum + val / scale
scale * alpha
args(0) * beta
args(1) * beta
Next i
ProcedureReturn(sum)
EndProcedure
Procedure.d PERLIN_generateNoise3D(x.d, y.d, z.d, alpha.d, beta.d, iterations.i)
Protected i.i
Protected val.d = 0, sum.d = 0
Protected scale.d = 1
Protected Dim args.d(2)
args(0) = x
args(1) = y
args(2) = z
For i = 1 To iterations
val = PERLIN_noise3(args())
sum = sum + (val / scale)
scale * alpha
args(0) * beta
args(1) * beta
args(2) * beta
Next i
ProcedureReturn(sum)
EndProcedure