Working on a minecraft-like voxel mining game in defold, any tips?

hey, i’m trying to build a minecraft style mining game (but single chunk) in defold and generate voxel terrain and meshes from code. i’m planning to use a texture atlas and only build visible faces and greedy meshing, but i feel like there are probably things i’m missing or mistakes people usually run into.

has anyone here tried something similar in defold? i’d like to know if there are engine limitations or performance issues i should watch out for before going too far. any general advice or things you wish you knew earlier would help a lot. thanks.

recording_20260202_162722

recording_20260202_173743

imagine this video is edited to the gif https://www.youtube.com/watch?v=bApd0QFsErU

1 Like

I’m sure @aglitchman and @d954mas have some great tips to share. They’ve both done similar things in the past. Perhaps also @morgerion ?

Yes, I’ve implemented a rendering system for a voxel-based game, somewhat similar to how it’s done in Minecraft. In my case, however, I used a chunk-based system that supports streaming and LOD switching, so distant chunks are rendered with lower polygon counts. I also implemented smooth terrain generation, because to be honest, classic Minecraft cubes really annoy me — and there’s nothing particularly difficult about smoothing a cubic landscape to achieve more visually pleasing shapes.

In addition to that, I implemented a large set of geometric primitives, similar in spirit to Minecraft, but without leaning so heavily into the cubic aesthetic. I use stairs, arches, diagonal prisms, cylinders, and so on. The system uses an 8×8 texture atlas (64 materials total), with each material being 1024×1024 pixels and including full PBR maps, normal maps, and DF height maps.

I also implemented a prefab system and a fairly advanced editor that allows you to manipulate all of this content comfortably.

To answer the original question: I haven’t encountered a single engine limitation or any performance issues along the way. On the contrary, I find Defold extremely convenient and well-optimized for this kind of project. My first prototypes were written entirely in Lua, without using C++ at all.

As for advice, I’d recommend being mentally prepared to write most of the terrain generation and maintenance code in C++. Alternatively, you can always offload that work to a modern neural network.

8 Likes

my game is just one infinite vertical chunk.

Idk why it is scaled

recording_20260202_202701

local function example_7(self)
	local mesh_go = create_mesh(self)

	-- Define 8 vertices of a unit cube
	local v = {
		vmath.vector3(-0.5, -0.5, 0.5), -- 1
		vmath.vector3(0.5, -0.5, 0.5), -- 2
		vmath.vector3(0.5, 0.5, 0.5), -- 3
		vmath.vector3(-0.5, 0.5, 0.5), -- 4
		vmath.vector3(-0.5, -0.5, -0.5), -- 5
		vmath.vector3(0.5, -0.5, -0.5), -- 6
		vmath.vector3(0.5, 0.5, -0.5), -- 7
		vmath.vector3(-0.5, 0.5, -0.5) -- 8
	}

	-- Define indices for 12 triangles (6 faces)
	local indices = {
		-- Front
		1, 2, 3, 1, 3, 4,
		-- Back
		6, 5, 8, 6, 8, 7,
		-- Top
		4, 3, 7, 4, 7, 8,
		-- Bottom
		5, 6, 2, 5, 2, 1,
		-- Right
		2, 6, 7, 2, 7, 3,
		-- Left
		5, 1, 4, 5, 4, 8
	}

	-- create a buffer with a position and uv stream
	local buf = buffer.create(#indices, {
		{ name = hash("position"),  type = buffer.VALUE_TYPE_FLOAT32, count = 3 },
		{ name = hash("texcoord0"), type = buffer.VALUE_TYPE_FLOAT32, count = 2 }
	})

	local positions = buffer.get_stream(buf, "position")
	local texcoord0 = buffer.get_stream(buf, "texcoord0")

	-- Square UVs (repeated for each face)
	local uv = {
		0, 0, 1, 0, 1, 1,
		0, 0, 1, 1, 0, 1
	}

	for i, idx in ipairs(indices) do
		local vert = v[idx]
		positions[(i - 1) * 3 + 1] = vert.x
		positions[(i - 1) * 3 + 2] = vert.y
		positions[(i - 1) * 3 + 3] = vert.z

		-- Simple UV mapping
		local uv_idx = ((i - 1) % 6) * 2 + 1
		texcoord0[(i - 1) * 2 + 1] = uv[uv_idx]
		texcoord0[(i - 1) * 2 + 2] = uv[uv_idx + 1]
	end

	local buffer_resource = resource.create_buffer(string.format(PATCH_BUFFER, 7), { buffer = buf })
	go.set(mesh_go.mesh_url, "vertices", buffer_resource)

	local atlas = resource.get_atlas(self.game_atlas)
	go.set(mesh_go.mesh_url, "texture0", hash(atlas.texture))

	-- Position the cube at origin
	go.set_position(vmath.vector3(0, 0, 0), mesh_go.go_id)
	-- Scale it up
	go.set_scale(vmath.vector3(100, 100, 100), mesh_go.go_id)
end

because of size of windows screen it was cube always :smile:

enabled auto aspect ratio

1 Like

recording_20260202_224312
top and bottom have different uv, I did because maybe it can give interesting look

2 Likes

recording_20260202_233232

now greedy mesh time

7 Likes

@morgerion how did you solve atlas texturing and repeating UV because of greedy mesh? can I send custom vertex data to material? The same issue in godot Texture Atlases and Repeating UVs - Shaders - Godot Forum

1 Like

I actually tried greedy meshing too, and at first I even used the material ID as one of the merge/split criteria (i.e. quads only merge if the material matches, so the material becomes part of the “surface key” for greedy meshing).

But after profiling it on real levels, the results were honestly disappointing: in my case greedy meshing reduced the final polygon/vertex count by only ~1–3% per level.

The problem is that greedy meshing usually requires an additional pass where you analyze basically all voxels in the chunk (or at least all potentially visible faces) to find merge candidates and build the quad runs. That CPU cost ended up being much higher than the benefit of saving just a few percent of triangles.

So I completely dropped greedy meshing. For my content it wasn’t worth the extra complexity and CPU time — the small reduction in vertices didn’t justify it.

(As always: if you have huge flat areas with large uniform materials, your numbers might be better — but I’d strongly recommend profiling with your actual world content before committing.)

3 Likes

This guy… casually made an awesome networking system for Defold and a dynamic physics based Minecraft with smoothed geometry while he was at it. :exploding_head:

2 Likes

Everything about that video was awesome, nice work. Is the frame rate really that bad, or was it just rendered that way?