Player gets stuck in tilemap collision shape

Hey Defolders! I’m new to Defold and am trying to make a simple platformer as my study project.
I ran into a problem: when i set the collision shape to tilemap, it seems like the player sometimes (sometimes not) gets stuck in the tile borders or something like that and doesn’t respond to user input, thus does not move left and right. But, when i delete the tilemap collision shape and simply add a few box shapes everything works fine, that’s why i thought the problem is in tilemap collision shape.

1) Using tilemap collision object: (doesn’t work)

Properties of map collision object:

Properties of player collision object:

2)using simple box collision shape: (works)

Properties of map collision object:

Properties of player collision object in that case are the same as in the previous one

Here’s the whole script for the reference that I mostly composed of codes from different tutorials. I initially thought the issue might be in the script, but now I kinda think script is not the issue here.

function init(self)
	msg.post(".", "acquire_input_focus")

	self.moving = false

	self.input = vmath.vector3()
	self.dir = vmath.vector3(0, 1, 0)
	self.speed = 150

	-- correction vector
	self.correction = vmath.vector3()
end

function final(self)                                -- [7]
	msg.post(".", "release_input_focus")            -- [8]
end

function update(self, dt)
	-- reset correction
	self.correction = vmath.vector3()
	
	local pos = go.get_position()
	pos.y = pos.y - 200 *dt
	if self.moving then
		pos = pos + self.dir * self.speed * dt
	end
	go.set_position(pos)

	self.input.x = 0
	self.input.y = 0

	self.moving = false
end

function on_input(self, action_id, action)          -- [14]
	if action_id == hash("left") then
		self.input.x = -1
	elseif action_id == hash("right") then
		self.input.x = 1
	end

	if vmath.length(self.input) > 0 then
		self.moving = true 
		self.dir = vmath.normalize(self.input)      
	end
end

function on_message(self, message_id, message, sender)
	-- Handle collision
	if message_id == hash("contact_point_response") then
		-- Get the info needed to move out of collision. We might
		-- get several contact points back and have to calculate
		-- how to move out of all of them by accumulating a
		-- correction vector for this frame:
		if message.distance > 0 then
			-- First, project the accumulated correction onto
			-- the penetration vector
			local proj = vmath.project(self.correction, message.normal * message.distance)
			if proj < 1 then
				-- Only care for projections that does not overshoot.
				local comp = (message.distance - message.distance * proj) * message.normal
				-- Apply compensation
				go.set_position(go.get_position() + comp)
				-- Accumulate correction done
				self.correction = self.correction + comp
			end
		end
	end
end

Here’s also a link to my GitHub. It has two branches that represent both cases. I’m not sure if my git is at all usefull for understanding the problem, but i thought it might help:

Any ideas what might be wrong?
Thanks a lot in advance!

1 Like

Try using a sphere as the collision shape for the player. You’ll have less ‘sticking’ problems that way.

Also, try turning on ‘debug’ in the physics section of game.project. Handy for visualising collision issues.

3 Likes

In addition to @benjames171’s answer: Wall-clipping collision issue - Questions - Defold game engine forum

1 Like

Oh, thank you that actually helped with the problem, but now i have another one.
The acceleration of the character looks kinda wonky, and not even:

You can definetily see it better with slower acceleration:

From what i can understand, it is because of the compensating forces from different tiles, that occur on colision. But how do i fix that?

How are you resolving the collisions? Like this? Resolving kinematic collsions in Defold

Yes, exactly! I am using the code section from the very end of that page.

Hmm, odd. What if you try the platformer template project which you can access from the welcome screen of the editor? It should not show these kinds of problems.

Alright sooooo…

1)When i try the platformer template everything works fine, as t should be:

2) When I replace in the tutorial only the tilesource, tilemap and the character, everything works just fine as well:

The script that the tutorial includes does not use acceleration in it’s movement component:

pos = pos + self.velocity * dt

3)BUT!

As soon as i try using this script:
https://defold.com/tutorials/platformer/
Which is very similar to included in the platformer tutorial script, but with acceleration included

Or as soon as i try using this script rigth here, which is basically a bit different approach composed by me of https://defold.com/examples/basics/movement_speed/and https://defold.com/manuals/physics-resolving-collisions/,

go.property("max_speed", 150)
go.property("acc", 10)
go.property("decc",200)

function init(self)
	msg.post(".", "acquire_input_focus")

	self.moving = false

	self.input = vmath.vector3()
	self.dir = vmath.vector3(0, 1, 0)
	self.speed = 0

	-- correction vector
	self.correction = vmath.vector3()
end

function final(self)                                -- [7]
	msg.post(".", "release_input_focus")            -- [8]
end

function update(self, dt)
	-- reset correction
	self.correction = vmath.vector3()

	--gravity component
	local pos = go.get_position()
	pos.y = pos.y - 200 *dt
	
	--calculating speed
	if self.moving then
		self.speed = self.speed + self.acc * dt
		self.speed = math.min(self.speed, self.max_speed)
	else
		self.speed = self.speed - self.decc * dt
		self.speed = math.max(self.speed, 0)
	end

	--seting position
	pos = pos + self.dir * self.speed * dt
	go.set_position(pos)

	--resetting values
	self.input.x = 0
	self.input.y = 0

	self.moving = false
end

function on_input(self, action_id, action)          -- [14]
	if action_id == hash("left") then
		self.input.x = -1
	elseif action_id == hash("right") then
		self.input.x = 1
	end

	if vmath.length(self.input) > 0 then
		self.moving = true 
		self.dir = vmath.normalize(self.input)      
	end
end

function on_message(self, message_id, message, sender)
	-- Handle collision
	if message_id == hash("contact_point_response") then
		-- Get the info needed to move out of collision. We might
		-- get several contact points back and have to calculate
		-- how to move out of all of them by accumulating a
		-- correction vector for this frame:
		if message.distance > 0 then
			-- First, project the accumulated correction onto
			-- the penetration vector
			local proj = vmath.project(self.correction, message.normal * message.distance)
			if proj < 1 then
				-- Only care for projections that does not overshoot.
				local comp = (message.distance - message.distance * proj) * message.normal
				-- Apply compensation
				go.set_position(go.get_position() + comp)
				-- Accumulate correction done
				self.correction = self.correction + comp
			end
		end
	end
end

…Stuff doesn’t seem to work smoothly:

Two slighly different scripts give pretty much the same wonky results:


We can see that occuring blue diagonal lines, which i suppose are like forces that act on character, do not affect the movement in cases without acceleration. However, if the acceleration is introduced, it seems to me like the presence of it messes up the “compensating” or “correcting” forces that counteract gravity. I am not at all sure though if this is the case, that’s just my best guess.

Anyway, I am very confused and have no idea how to fix that issue or how to make a smooth accelerated movement on the tile surface in general.

Hopefully some of you guys know the answer

Thanks in advance

Could you please share your project as a zip file here? (Exclude build and .internal folders)

Here’s a project with script from https://defold.com/tutorials/platformer/:
platformer.zip (566.4 KB)

Thanks. I’ve tested your project and it does indeed behave very strangely. I can’t really explain what’s going on without really breaking down your example completely.

I spent some time adding acceleration to the template-platformer project in a branch. Have a look at the implementation and see if it is useful to you: