3d-tilemap example (tilemap to mesh)

#1

Hi there!

Here is my code example for creating a mesh from a tilemap in runtime:

An example is well commented, hope it helps someone to open the wonderful world of Defold meshes :slight_smile:

Try it here: HTML 5 demo

How to use:

  1. Copy ‘mtool.lua’ module to your project.
  2. Create a standard tilemap.
  3. Add to scene a game object with a mesh component. We will use it as target later.
  4. In your code require mtool: local mtool = require "src.mtool"
  5. Fill the options table:
local options = {
		tilemap = "level#level", -- Tilemap URL.
		layer = "layer1", -- Tilemap layer name.
		w = 16, -- Horizontal number of tiles in tileset (texture atlas).
		h = 16, -- Vertical number of tiles in tileset (texture atlas).
		tilesize = 16, -- Size of tile in pixels (it will be use as scale factor when a script generates quads).
		
		-- Note: The same image that using as tilesource image we are using as a texture for generated mesh.
		-- Each tile in tilemap layer will represented as box.
		-- 
		-- Each box contains 6 edges (faces). We can replacement their textures by setting tile number for each edge.
		-- '1' is front edge, '2' - top, etc.
		--    [2]
		-- [4][1][5][6]
		--    [3]
		-- For example we want see a mixed grass tile (N) on front edge and pure green tile (M) on top edge.
		-- So, mapping it as: [N] = {N, M, N, N, N, N}
		-- 
		
		tile_info = {
			[2] = {2, 18, 34, 1, 1, 1},
			[3] = {3, 19, 35, 1, 1, 1},
			[4] = {4, 20, 36, 1, 1, 1},
			[6] = {6, 19, 35, 1, 1, 1},
			[51] = {51, 49, 49, 49, 49, 49},
			[53] = {53, 49, 49, 49, 49, 49},
		},

		-- You also can setup function 'tile_info_fn' for dynamic setting tile number. It may useful for generating levels in runtime.
		-- tile_info_fn = function(tileno, x, y)
		--  	if tileno == 1 then return {1, 4, 1, 1, 1, 1} end
		-- end

		optimize = false, -- If 'true' a script will culling the hidden by neighbors faces (edges 2,3,4,5).
		optimize_back = false -- If 'true' a script will culling back face (6) for all tiles.

		-- Also you may setup a texture atlas and setup for some tile numbers UV coordinates directly way.
		-- It's optionaly and made for further commits.
		-- All units are in pixels. Top-left corner is 0,0.

		-- For example:
		-- texture = {
		-- 	width = 512,
		-- 	height = 512,
		-- 	[2] = {x = 128, y = 0, w = 128, h = 256},
		-- }
	}
  1. Create a mesh from tilemap:
	self.grid = mtool.create_mesh_from_tilemap("go#mesh", options)
  1. Hide origin tilemap.
	msg.post(options.tilemap, "disable")

An example contains utility camera contoller script and uses rendercam extension.
Custom render script is modified rendercam render script where fixed render ordering 3d models and 2d objects. In example you may see that sprites are drawing in the same space as mesh tilemap and their can overlap each other.

If you do not need to see light source and want to do flat colors then remove “Diffuse light calculations” sections in the mesh fragment shader (assets/material/mesh.fp). In this case it should looks like

void main()
{
    // Pre-multiply alpha since all runtime textures already are
    vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w);
    vec4 color = texture2D(tex0, var_texcoord0.xy)*tint_pm;
    gl_FragColor = vec4(color.rgb*var_color0.rgb, color.a*var_color0.a);
}

Happy Defolding!

22 Likes

#2

This is really great! Thank you for sharing.

5 Likes

#3

How did you?! :flushed: Looking soo cool! :star_struck:

0 Likes

#4

Thanks for sharing this, this looks like a great way to do a classic brawler game like Super Smash Brothers or something along those lines. Would it be cool to adapt this example for use in a game I started working on? This would be a great way to render the levels since I’m working on a top down shooter style game.

2 Likes