Horizontal force applied to game object from tile map collision shape

It looks like my game object is currently receiving a contact_point_response message containing a horizontal contact point (assuming that’s what the debug arrows indicate) while walking along a flat surface, which causes the horizontal movement to be abrupt. The movement is fine while the game object is in the air as it isn’t colliding with any surfaces. Here’s an example screen recording of what is currently happening:


Mirror: https://forum.defold.com/uploads/default/original/3X/e/0/e0b23953077be7058e1499dbd07adf9057f0dfd1.mp4

Here is what the game object’s update function looks like:

function update(self, dt)
	local target_speed = self.move_input * self.max_speed
	local speed_diff = target_speed - self.velocity.x
	local acceleration = vmath.vector3(0, self.gravity, 0)

	if speed_diff ~= 0 then
		if speed_diff < 0 then
			acceleration.x = -self.move_acceleration
		else
			acceleration.x = self.move_acceleration
		end
	end

	local dv = acceleration * dt

	if math.abs(dv.x) > math.abs(speed_diff) then
		dv.x = speed_diff
	end

	local v0 = self.velocity

	self.velocity = self.velocity + dv
	
	local dp = (v0 + self.velocity) * dt * 0.5

	go.set_position(go.get_position() + dp)

	self.correction = vmath.vector3()
	self.move_input = 0
	self.ground_contact = false
end

Here’s what the function that handles collision detection looks like:

function on_message(self, message_id, message, sender)
	if message_id == msg_contact_point_response then
		if message.group == group_geometry then
			handle_geometry_contact(self, message.normal, message.distance)
		end
	end
end

local function handle_geometry_contact(self, normal, distance)
	local proj = vmath.dot(self.correction, normal)
	local comp = (distance - proj) * normal
	self.correction = self.correction + comp
	go.set_position(go.get_position() + comp)

	if normal.y > 0.7 then
		self.ground_contact = true
	end

	proj = vmath.dot(self.velocity, normal)

	if proj < 0 then
		self.velocity = self.velocity - proj * normal
	end
end

What might be causing this?

Is your ground made with a tilemap or otherwise with multiple collision shapes? If so then read this post.

Assuming that’s the issue, as far as I can find there is no perfect solution that solves this correctly in all circumstances. The simplest solution is to make your player body rounded or beveled on the bottom. That works well enough if you’re not too picky.

2 Likes

Ideally all collision objects should be made with minimal amount of shapes. So in this case it should be just a single big rectangle.

This may be related to Issue-4152 outlined here:

I thought it may be an issue with multiple collision shapes, as if I ignore tilesource collisions and just draw a single collision body over the entire tilemap, the collisions work as expected. It appears to draw a single contiguous rectangle over the tile map while debug draw is enabled though so I wasn’t sure.

Using a rounded collision body doesn’t seem to provide as precise collision detection as I would like (the game object “bounces” every time it leaves a tile) so I may try to implement something else or tweak it more. Thanks for the advice.

This is an annoying problem which has impacted my projects in the past. Tilemap collision shapes need smarter welding of points. It would be nice if we could visualize points with debug on too.

Which solutions in the past have worked out the best for you while implementing tile map collisions?

Yeah, the debug drawing doesn’t show the edges, so you can’t really tell, but each tile is a separate shape. You can change tiles however you want at runtime, so this makes sense.

This reddit thread has a few different suggestions, I haven’t tried to implement them with Defold.

Using raycasts instead of shape collision is probably the the most precise and reliable method you can use with Defold. @dmitriy, have you done this?

I stopped using tilemaps for collisions.

Also @ross.grams mentioned it but if you use a water tight pill shape it can be better but that has its own drawbacks for certain game types.

Here’s one I use, it is flat on top and rounded on bottom.

pill.zip (217 Bytes)

2019-09-26%2011_35_46-Window

Instead of adding a shape component you set the shape to this file in the collision.

2019-09-26%2011_36_06-Window

1 Like

The typical way (…) can have this done in hours.
An intermediate solution (…) have this done in 1 evening.
The “correct” solution (…) took me 1 year to get all the details right.

Yikes.

1 Like

More or less.

Here(don’t forget to jump to the well) and here some sort of old unfinished short demos. You can try them if you want to “feel” how ray casts works. They are still implemented with async raycast, so no slopes in them.

5 Likes