Godot Version
godot 4.4.1
Question
just as the title says, chunk generation in a minecraft clone im working on is incredibly slow, despite all i’ve done to try to make it faster. i know very little about how to do any of this efficiently, and im trying to learn as i go, but there arent many resources out there that i can understand very well (i learn best with very specific overexplained instructions)
i dont really know what to even provide here other than the project itself for people to take a look at, but im not sure how i’d even do that really
little snippets of some of the more important code (not the entire script files):
world script:
func generate_chunks(pos : Vector3i) -> void:
var chunk : MeshInstance3D = chunk_node.instantiate()
chunk.position = pos
chunk.name = "chunk" + str(pos)
add_child(chunk)
chunks[pos] = chunk # "chunks" is a dictionary containing the chunk positions as the keys
gen_block_data(chunk)
func gen_block_data(chunk : MeshInstance3D) -> void:
for x : int in range(chunk_size.x):
for y : int in range(chunk_size.y):
for z : int in range(chunk_size.z):
var pos : Vector3i = Vector3i(x + roundi(chunk.position.x), y + roundi(chunk.position.y), z + roundi(chunk.position.z))
blocks.get_or_add(pos, gen_base_blocks(pos))
# gen_base_blocks is returns the block id based on some noise at the block position
chunk script:
func gen_chunk() -> void:
clear_data()
for x : int in range(get_parent().chunk_size.x): # parent is the world, chunk_size is a vector3
for y : int in range(get_parent().chunk_size.y):
for z : int in range(get_parent().chunk_size.z):
if is_block_covered(Vector3i(x, y, z) + Vector3i(position)) == false and get_parent().blocks[Vector3i(x, y, z) + Vector3i(position)] != 0:
# is_block_covered checks the six neighbor blocks and returns false (block NOT covered) if
# any of the six blocks are transparent in some way, and skips air blocks (block id 0)
visible_blocks.append(Vector3i(x, y, z) + Vector3i(position))
gen_block_mesh()
func gen_block_mesh() -> void:
for i : Vector3i in visible_blocks:
if checked_block_ids.has(get_parent().blocks[i]) == false:
if IDs.block_ids[get_parent().blocks[i]].has("class"):
checked_block_ids.append(get_parent().blocks[i])
# adds the id of the block to an array to prevent blocks from getting checked if that id has already been checked
var new_block : world_block = IDs.block_ids[get_parent().blocks[i]]["class"].new()
# block ids are stored in an autoload as a dictionary with id being the key and all
# block parameters being the value (as another dictionary). one of the parameters is
# the block's script, and i have blocks as separate scripts to more easily control the generation
new_block.gen_block(visible_blocks, self)
one of the block scripts:
extends world_block # script that just extends Node. idk
class_name block_grass
func gen_vertices(where : Vector3i, offset : Vector3) -> PackedVector3Array:
var vertex : PackedVector3Array
if where == Vector3i.LEFT:
## NEG X
vertex.append(Vector3(0 + offset.x, 0 + offset.y, 0 + offset.z))
vertex.append(Vector3(0 + offset.x, 1 + offset.y, 0 + offset.z))
vertex.append(Vector3(0 + offset.x, 1 + offset.y, 1 + offset.z))
vertex.append(Vector3(0 + offset.x, 0 + offset.y, 1 + offset.z))
elif where == Vector3i.DOWN:
## NEG Y
vertex.append(Vector3(1 + offset.x, 0 + offset.y, 1 + offset.z))
vertex.append(Vector3(1 + offset.x, 0 + offset.y, 0 + offset.z))
vertex.append(Vector3(0 + offset.x, 0 + offset.y, 0 + offset.z))
vertex.append(Vector3(0 + offset.x, 0 + offset.y, 1 + offset.z))
elif where == Vector3i.FORWARD:
## NEG Z
vertex.append(Vector3(1 + offset.x, 0 + offset.y, 0 + offset.z))
vertex.append(Vector3(1 + offset.x, 1 + offset.y, 0 + offset.z))
vertex.append(Vector3(0 + offset.x, 1 + offset.y, 0 + offset.z))
vertex.append(Vector3(0 + offset.x, 0 + offset.y, 0 + offset.z))
elif where == Vector3i.RIGHT:
## POS X
vertex.append(Vector3(1 + offset.x, 0 + offset.y, 1 + offset.z))
vertex.append(Vector3(1 + offset.x, 1 + offset.y, 1 + offset.z))
vertex.append(Vector3(1 + offset.x, 1 + offset.y, 0 + offset.z))
vertex.append(Vector3(1 + offset.x, 0 + offset.y, 0 + offset.z))
elif where == Vector3i.UP:
## POS Y
vertex.append(Vector3(1 + offset.x, 1 + offset.y, 0 + offset.z))
vertex.append(Vector3(1 + offset.x, 1 + offset.y, 1 + offset.z))
vertex.append(Vector3(0 + offset.x, 1 + offset.y, 1 + offset.z))
vertex.append(Vector3(0 + offset.x, 1 + offset.y, 0 + offset.z))
elif where == Vector3i.BACK:
## POS Z
vertex.append(Vector3(0 + offset.x, 0 + offset.y, 1 + offset.z))
vertex.append(Vector3(0 + offset.x, 1 + offset.y, 1 + offset.z))
vertex.append(Vector3(1 + offset.x, 1 + offset.y, 1 + offset.z))
vertex.append(Vector3(1 + offset.x, 0 + offset.y, 1 + offset.z))
return vertex
func gen_indices(face : int) -> PackedInt32Array:
var index : PackedInt32Array
index.append(00 + face * 4)
index.append(01 + face * 4)
index.append(02 + face * 4)
index.append(00 + face * 4)
index.append(02 + face * 4)
index.append(03 + face * 4)
return index
func gen_block(blocks : PackedVector3Array, chunk : MeshInstance3D) -> void:
for i : Vector3i in blocks:
if chunk.get_parent().blocks[i] == 2:
## NEG X
if chunk.get_block(i + Vector3i.LEFT) == 0 or IDs.block_ids[chunk.get_block(i + Vector3i.LEFT)]["block_type"].has(IDs.block_type.solid) == false:
chunk.vertices_solid.append_array(gen_vertices(Vector3i.LEFT, i - Vector3i(chunk.position)))
chunk.indices_solid.append_array(gen_indices(chunk.face_count_solid))
chunk.face_count_solid += 1
chunk.vertices.append_array(gen_vertices(Vector3i.LEFT, i - Vector3i(chunk.position)))
chunk.indices.append_array(gen_indices(chunk.face_count))
chunk.face_count += 1
chunk.gen_uvs(Vector4(16, 16, 0, 32))
## NEG Y
if chunk.get_block(i + Vector3i.DOWN) == 0 or IDs.block_ids[chunk.get_block(i + Vector3i.DOWN)]["block_type"].has(IDs.block_type.solid) == false:
chunk.vertices_solid.append_array(gen_vertices(Vector3i.DOWN, i - Vector3i(chunk.position)))
chunk.indices_solid.append_array(gen_indices(chunk.face_count_solid))
chunk.face_count_solid += 1
chunk.vertices.append_array(gen_vertices(Vector3i.DOWN, i - Vector3i(chunk.position)))
chunk.indices.append_array(gen_indices(chunk.face_count))
chunk.face_count += 1
chunk.gen_uvs(Vector4(0, 16, 0, 16))
## NEG Z
if chunk.get_block(i + Vector3i.FORWARD) == 0 or IDs.block_ids[chunk.get_block(i + Vector3i.FORWARD)]["block_type"].has(IDs.block_type.solid) == false:
chunk.vertices_solid.append_array(gen_vertices(Vector3i.FORWARD, i - Vector3i(chunk.position)))
chunk.indices_solid.append_array(gen_indices(chunk.face_count_solid))
chunk.face_count_solid += 1
chunk.vertices.append_array(gen_vertices(Vector3i.FORWARD, i - Vector3i(chunk.position)))
chunk.indices.append_array(gen_indices(chunk.face_count))
chunk.face_count += 1
chunk.gen_uvs(Vector4(16, 16, 0, 32))
## POS X
if chunk.get_block(i + Vector3i.RIGHT) == 0 or IDs.block_ids[chunk.get_block(i + Vector3i.RIGHT)]["block_type"].has(IDs.block_type.solid) == false:
chunk.vertices_solid.append_array(gen_vertices(Vector3i.RIGHT, i - Vector3i(chunk.position)))
chunk.indices_solid.append_array(gen_indices(chunk.face_count_solid))
chunk.face_count_solid += 1
chunk.vertices.append_array(gen_vertices(Vector3i.RIGHT, i - Vector3i(chunk.position)))
chunk.indices.append_array(gen_indices(chunk.face_count))
chunk.face_count += 1
chunk.gen_uvs(Vector4(16, 16, 0, 32))
## POS Y
if chunk.get_block(i + Vector3i.UP) == 0 or IDs.block_ids[chunk.get_block(i + Vector3i.UP)]["block_type"].has(IDs.block_type.solid) == false:
chunk.vertices_solid.append_array(gen_vertices(Vector3i.UP, i - Vector3i(chunk.position)))
chunk.indices_solid.append_array(gen_indices(chunk.face_count_solid))
chunk.face_count_solid += 1
chunk.vertices.append_array(gen_vertices(Vector3i.UP, i - Vector3i(chunk.position)))
chunk.indices.append_array(gen_indices(chunk.face_count))
chunk.face_count += 1
chunk.gen_uvs(Vector4(32, 16, 0, 48))
## POS Z
if chunk.get_block(i + Vector3i.BACK) == 0 or IDs.block_ids[chunk.get_block(i + Vector3i.BACK)]["block_type"].has(IDs.block_type.solid) == false:
chunk.vertices_solid.append_array(gen_vertices(Vector3i.BACK, i - Vector3i(chunk.position)))
chunk.indices_solid.append_array(gen_indices(chunk.face_count_solid))
chunk.face_count_solid += 1
chunk.vertices.append_array(gen_vertices(Vector3i.BACK, i - Vector3i(chunk.position)))
chunk.indices.append_array(gen_indices(chunk.face_count))
chunk.face_count += 1
chunk.gen_uvs(Vector4(16, 16, 0, 32))
apologies for the walls of code, i just wanted to provide something for people to be able to see the main stuff going on to see where i might be able to optimize (probably many areas)
im just grasping at straws here man im just so lost. any help, tips, direction, etc would be greatly appreciated!