Isometric tiled map issue

Hello guys

I have this issue with tile map, I’m trying to work around isometric map but when I include it on defold it does not respect the map tile height property.

Defold result
defold

Tiled editor

I’m using defold 2 editor, tiled map editor 1.0.3, I also tested the map in other engines and works well.

Any idea what is wrong?

thanks

Well, Defold doesn’t support isometric tilemaps. @sven experimented a bit with a normal 2D tilemap that he rotated to get an isometric tilemap. Perhaos he can explain more/share something?

2 Likes

If interested I created this video stream where I in 3 sessions create this isometric small techdemo.
First part is more about the normal “isometric” stuff and then I get a little more advanced from there. But it shouldn’t really be hard to convert Tiled-data to isometric.

5 Likes

I did explore an idea I had for an isometric looking RTS, but it wasn’t quite what you are trying to achieve. I would recommend checking out Andreas video above. :slight_smile:

1 Like

Thanks, I’ll watch the video

1 Like

Hello,

how exactly did you achieve your result? Did you try using the libdefold plugin? The best way to use Defold in conjunction with Defold in order to create an isometric game is to write your own rendering routine, which will load the output generated by Tiled (a lua/json file) and compensate for height difference based on presets of individual tilesets.

1 Like

For small isometric map there is able to use GO.factory and .lua file from Tiled.
I tried this way here: http://dragosha.com/adventure/

Map Go contains Factory block.go and this script:
Map loader script:

local tiles={}
local WIDTH = tonumber(sys.get_config("display.width"))
local HEIGHT = tonumber(sys.get_config("display.height"))

-- Get info about flipping of tile. Based on object GID in the object layer
-- @param gid GID from .tmx
-- @return realGID (int), flipX (bool), flipY (bool)
local function flippedGID(gid)
	local bit31   = 2147483648
	local bit30   = 1073741824
	local bit29   = 536870912
	local flipX   = false
	local flipY   = false
	local flipD   = false
	local realgid = gid

	if realgid >= bit31 then
		realgid = realgid - bit31
		flipX   = true
	end

	if realgid >= bit30 then
		realgid = realgid - bit30
		flipY   = true
	end

	if realgid >= bit29 then
		realgid = realgid - bit29
		flipD   = not flipD
	end
	return realgid, flipX, flipY
end

-- @return file name without path and extension
local  function pureName(name)
	name=string.gsub(name,"%w+/+","")
	name=name:gsub("../+","")
	name=string.gsub(name,".png","")
	return name
end

local isoToScreen = function(ix,iy,tw,th)
	local x = (ix-1)*tw/2 - (iy-1)*tw/2
	local y = (ix-1)*th/2 + (iy-1)*th/2
	return x,y
end

--- Project isometric position to cartesian position
function convert_isometric_to_screen(map, x, y)
	local mapH    = map.height
	local tileW   = map.tilewidth
	local tileH   = map.tileheight
	local tileX   = x / tileH
	local tileY   = y / tileH
	local offsetX = mapH * tileW / 2


	return
		(tileX - tileY) * tileW / 2 + offsetX,
		mapH*tileH-(tileX + tileY) * tileH / 2
end

--
local function build_board(self, level)
	local pos = vmath.vector3()
	local layers=#level.layers
	local tileset=level.tilesets[1]
	local scale = vmath.vector3()
	local rot

	for i=1,layers do
		local layer=level.layers[i]
		for j,obj in pairs(layer.objects) do
			local gid,flipX,flipY=flippedGID(obj.gid)
			local tileInfo=tileset.tiles[gid]
			local img=pureName(tileInfo.image)


			if level.orientation=="isometric" then
				pos.x,pos.y=convert_isometric_to_screen(level, obj.x, obj.y)
				--pos.x=200+obj.x+tileInfo.width/2-obj.y/2
				--pos.y=(level.height*level.tileheight)-obj.y+tileInfo.height/2
				pos.z=0
			else
				pos.x=obj.x+tileInfo.width/2
				pos.y=(level.height*level.tileheight)-obj.y+tileInfo.height/2
				pos.z=0
			end

			if obj.width ~= tileInfo.width then
				scale.x= obj.width/tileInfo.width
				scale.y= obj.height/tileInfo.height
				scale.z= 1
			else
				scale.x=1 scale.y=1 scale.z=1
			end
			if obj.rotation ~=0 then
				local angle=-obj.rotation * math.pi/180
				rot=vmath.quat_rotation_z(angle)
				-- print(rot)
			else
				rot=nil
			end

			local y=pos.y
			if layer.name=="floor" then
				pos.y=-obj.height
			else
				pos.y=HEIGHT+obj.height
			end

			local id=factory.create("#factory",pos,rot,{img=hash(img),flipX=flipX,flipY=flipY},scale)

			local duration=y/HEIGHT
			--duration = math.random(duration * 0.9, duration * 1.1)
			local delay = j*.01
			go.animate(id, "position.y", go.PLAYBACK_ONCE_FORWARD, y, go.EASING_OUTBACK, duration, delay)

			table.insert(tiles,{id=id,x=pos.x,y=y,layer=layer.name, height=obj.height})
		end

	end

end

local function boardAnimation(self)

	local pos=vmath.vector3()
	for i,t in pairs(tiles) do
		local duration=t.y/HEIGHT
		local delay = i*.01
		local y
		if t.layer=="floor" then
			y=-t.height
		else
			y=HEIGHT+t.height
		end

		go.animate(t.id, "position.y", go.PLAYBACK_ONCE_FORWARD, y, go.EASING_INBACK, duration, delay)
	end

end
local function boardAnimation2(self)

	local pos=vmath.vector3()
	for i,t in pairs(tiles) do
		local duration=t.y/HEIGHT
		local delay = i*.01
		go.animate(t.id, "position.y", go.PLAYBACK_ONCE_FORWARD, t.y, go.EASING_OUTCUBIC, duration, delay)
	end

end


function init(self)
	build_board(self, require "main/Tiles/map2")
	msg.post(".","acquire_input_focus")
end




function final(self)
	-- Add finalization code here
	-- Remove this function if not needed
	msg.post(".","release_input_focus")
end

function update(self, dt)
	-- Add update code here
	-- Remove this function if not needed
end

function on_message(self, message_id, message, sender)
	-- Add message-handling code here
	-- Remove this function if not needed
end

function on_input(self, action_id, action)
	if action_id==hash("click") and action.pressed then
		if self.anim then
			boardAnimation2(self)
			self.anim=false
			else
			boardAnimation(self)
			self.anim=true
		end
	end

end

in this implementation method ‘convert_isometric_to_screen’ works not correct, need to fix, i used not isometric map in Tiled in example

Block GO contains “sprite” component and this script:
Block.script:

go.property("img",hash("none"))
go.property("flipX", false)
go.property("flipY", false)
function init(self)
	-- Add initialization code here
	-- Remove this function if not needed
	--go.set_scale(1)

	if self.flipX then
		sprite.set_hflip("#sprite", true)
	end

	if self.flipY then
		sprite.set_vflip("#sprite", true)
	end


	if self.img ~= hash("none") then
		msg.post("#sprite","play_animation", {id=self.img})
	else
		msg.post("#sprite","disable")
	end

end

Sprite component uses atlas with images that have same names as in Tiled editor.

6 Likes

Wow, nice!

1 Like

Nice demo, I like it :slight_smile:

I’d just like to add that you can use (collection) factories to draw large maps (in Kanji Adventure , the exploration map is 100x100 tiles large), you just have to create a routine that manages creation and deletion of tiles that are on-/offscreen respectively.

Oh, and one (pretty significant) performance optimization that I found out a couple days back - make sure to cut up the data that you are going to use into multiple lua tables. Accessing the following tables:

self.tile_styles = self.tilemap()["layers"][1]["data"]
self.object_styles = self.tilemap()["layers"][3]["data"]
self.large_object_styles = self.tilemap()["layers"][4]["data"]
self.grayscale_mods = self.tilemap()["layers"][5]["data"]
self.tilesets = self.tilemap()["tilesets"]

is much faster than accessing them via

local res = sys.load_resource("/maps/" .. self.map_name .. ".lua")
self.tilemap = assert(loadstring(res))

There is also a helpful list of tips on performance in Lua over at https://www.lua.org/gems/sample.pdf

3 Likes

It’s still impossible to use isometric tile imported from tiled correctly in the editor, any update ? is in the roadmap ?

No, I’m afraid not. Not in the short term at least.

EDIT: Well, you could use a normal 2D grid map and setup your camera so that you get an isometric view. It would require a bit of fiddling with how sprites and other things are rendered though.

1 Like

Me and my team we currently have an C++ isometric 2D mmorpg that we would like to switch to defold, but suddenly it could be very complicated, we want to use defold for a lot of reasons, but the isometric issue brakes a little bit. All our assets are isometric view already etc.

for example

1 Like

You could quite easily create it using game objects instead. It should be performant enough.

It’s will be painful to move my characters overs this kind of map no ?

No, why would it be difficult? How is your character rendered btw? 2D flipbook animations in four directions? How are your maps described/created? Using Tiled?

My map are created using tiled, my character are 8Direction characters (Dofus-Like).

I can export tiled map into lua files, and then create game object in defold i think

Yes, this would work.

And do you move freely or is it basically tile/grid based movement?

1 Like

Freely, also i plan to use spine model animation in defold because it’s seem’s really great.

1 Like

@Alex_8BitSkull is developing an awesome isometric game in Defold - Fates of Ort :wink:

6 Likes

Yes, Fates of Ort is proof that it is possible. And @Tomires used to develop an isometric game as well.

2 Likes