I think many of us already tried to create a minecraft like world.
I did, and i didn't succeed, at least not to the degree I wanted.
So let me jump in here and present a little code to create voxel worlds, build out of one sided planes, they are not combined to one object yet.
One sided plane means you can fly inside the cube and look out, so the other side doesn't take up render time.
// Project: craft-a-lite
// Created: 2018-01-20
// show all errors
SetErrorMode(2)
// set window properties
SetWindowTitle( "craft-a-lite" )
SetWindowSize( 1024, 768, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window
// set display properties
SetVirtualResolution( 1024, 768 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 1200, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts
SetGenerateMipmaps(1)
// setcameras
SetCameraRange(1,1,200)
SetCameraRotation(1,0,90,0)
// setup a skybox
SetSunActive(1)
SetSkyBoxHorizonSize(4.0,4)
SetSkyBoxHorizonColor(0,0,0)
SetSkyBoxSkyColor(0,0,50)
SetSkyBoxVisible(1)
SetFogColor(0,0,0)
SetFogRange(150,180)
SetFogMode(1)
// constants types and such
#Constant VERTEX_OFFSET = 60
global IndexOffset
#constant DDOWN 0
#constant DUP 5
#constant DLEFT 1
#constant DRIGHT 4
#constant DFRONT 2
#constant DBACK 3
type CubeData
ID
Face as integer[5] //6 faces of a cube
endtype
global Cube as CubeData[9,9,9]
// build level
for CubeX=1 to 7
for CubeY=1 to 7
for CubeZ=1 to 7
CreateCube(CubeX,CubeY,CubeZ,1)
next CubeZ
next CubeY
next CubeX
// some tests
DeleteCube(7,7,7)
DeleteCube(6,6,6)
DeleteCube(6,7,6)
CreateCube(5,5,8,1)
// main loop
do
Print( ScreenFPS() )
ControlCamera()
Sync()
loop
end
// I put all functions in this file to share it
// world building functions
function CreateCube(CubeX,CubeY,CubeZ,CubeType)
Cube[CubeX,CubeY,CubeZ].ID=CubeType
if Cube[CubeX,CubeY+1,CubeZ].ID>0
DeleteFace(CubeX,CubeY+1,CubeZ,DDOWN)
endif
if Cube[CubeX,CubeY-1,CubeZ].ID>0
DeleteFace(CubeX,CubeY-1,CubeZ,DUP)
endif
if Cube[CubeX+1,CubeY,CubeZ].ID>0
DeleteFace(CubeX+1,CubeY,CubeZ,DLEFT)
endif
if Cube[CubeX-1,CubeY,CubeZ].ID>0
DeleteFace(CubeX-1,CubeY,CubeZ,DRIGHT)
endif
if Cube[CubeX,CubeY,CubeZ-1].ID>0
DeleteFace(CubeX,CubeY,CubeZ-1,DBACK)
endif
if Cube[CubeX,CubeY,CubeZ+1].ID>0
DeleteFace(CubeX,CubeY,CubeZ+1,DFRONT)
endif
if Cube[CubeX,CubeY-1,CubeZ].ID=0
CreateFace(CubeX,CubeY,CubeZ,DDOWN)
endif
if Cube[CubeX,CubeY+1,CubeZ].ID=0
CreateFace(CubeX,CubeY,CubeZ,DUP)
endif
if Cube[CubeX-1,CubeY,CubeZ].ID=0
CreateFace(CubeX,CubeY,CubeZ,DLEFT)
endif
if Cube[CubeX+1,CubeY,CubeZ].ID=0
CreateFace(CubeX,CubeY,CubeZ,DRIGHT)
endif
if Cube[CubeX,CubeY,CubeZ+1].ID=0
CreateFace(CubeX,CubeY,CubeZ,DBACK)
endif
if Cube[CubeX,CubeY,CubeZ-1].ID=0
CreateFace(CubeX,CubeY,CubeZ,DFRONT)
endif
endfunction
function DeleteCube(CubeX,CubeY,CubeZ)
Cube[CubeX,CubeY,CubeZ].ID=0
if Cube[CubeX,CubeY,CubeZ].Face[DDOWN]>0
DeleteFace(CubeX,CubeY,CubeZ,DDOWN)
endif
if Cube[CubeX,CubeY,CubeZ].Face[DUP]>0
DeleteFace(CubeX,CubeY,CubeZ,DUP)
endif
if Cube[CubeX,CubeY,CubeZ].Face[DLEFT]>0
DeleteFace(CubeX,CubeY,CubeZ,DLEFT)
endif
if Cube[CubeX,CubeY,CubeZ].Face[DRIGHT]>0
DeleteFace(CubeX,CubeY,CubeZ,DRIGHT)
endif
if Cube[CubeX,CubeY,CubeZ].Face[DBACK]>0
DeleteFace(CubeX,CubeY,CubeZ,DBACK)
endif
if Cube[CubeX,CubeY,CubeZ].Face[DFRONT]>0
DeleteFace(CubeX,CubeY,CubeZ,DFRONT)
endif
if Cube[CubeX,CubeY+1,CubeZ].ID>0
CreateFace(CubeX,CubeY+1,CubeZ,DDOWN)
endif
if Cube[CubeX,CubeY-1,CubeZ].ID>0
CreateFace(CubeX,CubeY-1,CubeZ,DUP)
endif
if Cube[CubeX+1,CubeY,CubeZ].ID>0
CreateFace(CubeX+1,CubeY,CubeZ,DLEFT)
endif
if Cube[CubeX-1,CubeY,CubeZ].ID>0
CreateFace(CubeX-1,CubeY,CubeZ,DRIGHT)
endif
if Cube[CubeX,CubeY,CubeZ-1].ID>0
CreateFace(CubeX,CubeY,CubeZ-1,DBACK)
endif
if Cube[CubeX,CubeY,CubeZ+1].ID>0
CreateFace(CubeX,CubeY,CubeZ+1,DFRONT)
endif
endfunction
function DeleteFace(CubeX,CubeY,CubeZ,Direction)
DeleteObject(Cube[CubeX,CubeY,CubeZ].Face[Direction])
Cube[CubeX,CubeY,CubeZ].Face[Direction]=0
endfunction
function SetCubeVisible(CubeX,CubeY,CubeZ,Visible)
for Direction=0 to 5
if GetObjectExists(Cube[CubeX,CubeY,CubeZ].Face[Direction])=1 then SetObjectVisible(Cube[CubeX,CubeY,CubeZ].Face[Direction],Visible)
next Direction
endfunction
function CreateFace(CubeX,CubeY,CubeZ,Direction)
if Cube[CubeX,CubeY,CubeZ].Face[Direction]=0
Size#=0.5
MemblockID=CreateMeshMemblock()
select Direction
case DUP:
SetMemblockVec3(MemblockID,VERTEX_OFFSET+0,CubeX-Size#,CubeY+Size#,CubeZ+Size#) // Vertex
SetMemblockVec3(MemblockID,VERTEX_OFFSET+3*4,0,1,0) // Normals
SetMemblockVec2(MemblockID,VERTEX_OFFSET+6*4,0,0) // UV
SetMemblockVec3(MemblockID,VERTEX_OFFSET+8*4,CubeX-Size#,CubeY+Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+11*4,0,1,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+14*4,0,1)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+16*4,CubeX+Size#,CubeY+Size#,CubeZ+Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+19*4,0,1,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+22*4,1,0)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+24*4,CubeX+Size#,CubeY+Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+27*4,0,1,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+30*4,1,1)
endcase
case DDOWN:
SetMemblockVec3(MemblockID,VERTEX_OFFSET+0,CubeX-Size#,CubeY-Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+3*4,0,-1,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+6*4,0,0)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+8*4,CubeX-Size#,CubeY-Size#,CubeZ+Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+11*4,0,-1,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+14*4,0,1)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+16*4,CubeX+Size#,CubeY-Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+19*4,0,-1,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+22*4,1,0)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+24*4,CubeX+Size#,CubeY-Size#,CubeZ+Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+27*4,0,-1,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+30*4,1,1)
endcase
case DRIGHT:
SetMemblockVec3(MemblockID,VERTEX_OFFSET+0,CubeX+Size#,CubeY-Size#,CubeZ+Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+3*4,1,0,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+6*4,0,0)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+8*4,CubeX+Size#,CubeY+Size#,CubeZ+Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+11*4,1,0,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+14*4,0,1)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+16*4,CubeX+Size#,CubeY-Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+19*4,1,0,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+22*4,1,0)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+24*4,CubeX+Size#,CubeY+Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+27*4,1,0,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+30*4,1,1)
endcase
case DLEFT:
SetMemblockVec3(MemblockID,VERTEX_OFFSET+0,CubeX-Size#,CubeY+Size#,CubeZ+Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+3*4,-1,0,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+6*4,0,0)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+8*4,CubeX-Size#,CubeY-Size#,CubeZ+Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+11*4,-1,0,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+14*4,0,1)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+16*4,CubeX-Size#,CubeY+Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+19*4,-1,0,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+22*4,1,0)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+24*4,CubeX-Size#,CubeY-Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+27*4,-1,0,0)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+30*4,1,1)
endcase
case DFRONT:
SetMemblockVec3(MemblockID,VERTEX_OFFSET+0,CubeX-Size#,CubeY+Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+3*4,0,0,-1)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+6*4,0,0)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+8*4,CubeX-Size#,CubeY-Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+11*4,0,0,-1)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+14*4,0,1)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+16*4,CubeX+Size#,CubeY+Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+19*4,0,0,-1)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+22*4,1,0)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+24*4,CubeX+Size#,CubeY-Size#,CubeZ-Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+27*4,0,0,-1)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+30*4,1,1)
endcase
case DBACK:
SetMemblockVec3(MemblockID,VERTEX_OFFSET+0,CubeX+Size#,CubeY+Size#,CubeZ+Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+3*4,0,0,1)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+6*4,0,0)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+8*4,CubeX+Size#,CubeY-Size#,CubeZ+Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+11*4,0,0,1)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+14*4,0,1)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+16*4,CubeX-Size#,CubeY+Size#,CubeZ+Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+19*4,0,0,1)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+22*4,1,0)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+24*4,CubeX-Size#,CubeY-Size#,CubeZ+Size#)
SetMemblockVec3(MemblockID,VERTEX_OFFSET+27*4,0,0,1)
SetMemblockVec2(MemblockID,VERTEX_OFFSET+30*4,1,1)
endcase
endselect
//~ Indices
SetMemblockInt(MemblockID,IndexOffset+0*4,0)
SetMemblockInt(MemblockID,IndexOffset+1*4,1)
SetMemblockInt(MemblockID,IndexOffset+2*4,2)
SetMemblockInt(MemblockID,IndexOffset+3*4,2)
SetMemblockInt(MemblockID,IndexOffset+4*4,1)
SetMemblockInt(MemblockID,IndexOffset+5*4,3)
Cube[CubeX,CubeY,CubeZ].Face[Direction]=BuildMeshMemblock(MemblockID)
//~ SetFaceTexture(CubeX,CubeY,CubeZ,Direction)
endif
endfunction
//~ function SetFaceTexture(CubeX,CubeY,CubeZ,Direction)
//~ if Cube[CubeX,CubeY,CubeZ].Face[Direction]<>0
//~ select Cube[CubeX,CubeY,CubeZ].ID
//~ case 1:
//~ if Cube[CubeX,CubeY+1,CubeZ].ID=0 and Direction=DUP
//~ setobjectimage(Cube[CubeX,CubeY,CubeZ].Face[Direction],CubeImageID[0],0)
//~ else
//~ setobjectimage(Cube[CubeX,CubeY,CubeZ].Face[Direction],CubeImageID[1],0)
//~ endif
//~ endcase
//~ case 2:
//~ if Cube[CubeX,CubeY+1,CubeZ].ID=0 and Direction=DUP
//~ setobjectimage(Cube[CubeX,CubeY,CubeZ].Face[Direction],CubeImageID[2],0)
//~ else
//~ setobjectimage(Cube[CubeX,CubeY,CubeZ].Face[Direction],CubeImageID[3],0)
//~ endif
//~ endcase
//~ endselect
//~ endif
//~ endfunction
// here starts the memblock manipulation functions
function CreateMeshMemblock()
VertexCount=4
IndexCount=6
Attributes=3
VertexSize=3*4+3*4+2*4
IndexOffset=VERTEX_OFFSET+(VertexCount*VertexSize)
MemblockID=Creatememblock(VERTEX_OFFSET+(VertexCount*VertexSize)+(IndexCount*4))
SetMemblockInt(MemblockID,0,VertexCount)
SetMemblockInt(MemblockID,4,IndexCount)
SetMemblockInt(MemblockID,8,Attributes)
SetMemblockInt(MemblockID,12,VertexSize)
SetMemblockInt(MemblockID,16,VERTEX_OFFSET)
SetMemblockInt(MemblockID,20,IndexOffset)
AttributeOffset=24
SetMemblockByte(MemblockID,AttributeOffset,0) // Float type component
SetMemblockByte(MemblockID,AttributeOffset+1,3) // number of components
SetMemblockByte(MemblockID,AttributeOffset+2,0) // normalize flag
SetMemblockByte(MemblockID,AttributeOffset+3,12) // string length
SetMemblockString(MemblockID,AttributeOffset+4,"position"+chr(0)) // string
inc AttributeOffset,16
SetMemblockByte(MemblockID,AttributeOffset,0) // Float type component
SetMemblockByte(MemblockID,AttributeOffset+1,3) // number of components
SetMemblockByte(MemblockID,AttributeOffset+2,0) // normalize flag
SetMemblockByte(MemblockID,AttributeOffset+3,8) // string length
SetMemblockString(MemblockID,AttributeOffset+4,"normal"+chr(0)) // string
inc AttributeOffset,12
SetMemblockByte(MemblockID,AttributeOffset,0) // Float type component
SetMemblockByte(MemblockID,AttributeOffset+1,2) // number of components
SetMemblockByte(MemblockID,AttributeOffset+2,0) // normalize flag
SetMemblockByte(MemblockID,AttributeOffset+3,4) // string length
SetMemblockString(MemblockID,AttributeOffset+4,"uv"+chr(0)) // string
for Offset=VERTEX_OFFSET to VERTEX_OFFSET+(VertexCount*VertexSize) step 4
SetMemblockFloat(MemblockID,Offset, 0.0)
next Offset
endfunction MemblockID
function BuildMeshMemblock(MemblockID)
ObjectID=CreateObjectFromMeshMemblock(MemblockID)
DeleteMemblock(MemblockID)
endfunction ObjectID
function SetMemblockVec3(MemblockID,Offset,x#,y#,z#)
SetMemblockFloat(MemblockID,Offset,x#)
SetMemblockFloat(MemblockID,Offset+4,y#)
SetMemblockFloat(MemblockID,Offset+8,z#)
endfunction
function SetMemblockVec2(MemblockID,Offset,u#,v#)
SetMemblockFloat(MemblockID,Offset,u#)
SetMemblockFloat(MemblockID,Offset+4,v#)
endfunction
// put all functions you can not define here
function ControlCamera()
global startx#
global starty#
global angx#
global angY#
speed#=40*GetFrameTime()
// move the camera with keys
if GetKeyboardExists()=1
if(GetRawKeyState(87)) then MoveCameraLocalZ(1, speed# )
if(GetRawKeyState(83)) then MoveCameraLocalZ(1, -speed# )
if(GetRawKeyState(65)) then MoveCameraLocalX(1, -speed# )
if(GetRawKeyState(68)) then MoveCameraLocalX(1, speed# )
if(GetRawKeyState(81)) then MoveCameraLocalY(1, -speed# )
if(GetRawKeyState(69)) then MoveCameraLocalY(1, speed# )
else
JoystickSize#=GetVirtualHeight()*0.25
SetJoystickScreenPosition(GetScreenBoundsLeft()+JoystickSize#*0.5,GetScreenBoundsBottom()-JoystickSize#*0.5,JoystickSize#)
MoveCameraLocalZ( 1, -GetJoystickY() * speed# )
MoveCameraLocalX( 1, GetJoystickX() * speed# )
endif
// rotate the camera
if GetPointerPressed()=1
startx# = GetPointerX()
starty# = GetPointerY()
angx# = GetCameraAngleX(1)
angy# = GetCameraAngleY(1)
endif
if GetPointerState()=1
fDiffX# = (GetPointerX() - startx#)
fDiffY# = (GetPointerY() - starty#)
newX# = angx# + fDiffY#
if ( newX# > 89 ) then newX# = 89
if ( newX# < -89 ) then newX# = -89
SetCameraRotation( 1, newX#, angy# + fDiffX#, 0 )
endif
endfunction
Play with create/deletecube.
Beware I started at index 1,1,1 and end at 8,8,8 even if you have space in 0,0,0 and 9,9,9 of the array ... I choose it, so I don't need to check bounds every time I create or delete a cube. (I.e. I traded memory against run time)
You can go from here and add them to one object to form your chunk... If you have done that I may present you with another pice of code