Collision not working

image



I’ve implemented Collision as a part of my tilemap, but whenever I run the program, the player character just gets launched upwards, but doesn’t even stop when he is no longer on the tilemap tiles (I did have a video but it won’t upload). How do I fix this?
Ideally, I want the player character to be able to walk across the ground tiles and not be able to move onto tiles assigned object or water groups (I’ve only assigned some tiles those groups, such as the fountain or the house, i didn’t want to waste time assigning all the tiles if it doesn’t work).

You created the tilesource collision group as “objects” and used “object” on the players mask field. Also, add “objects” to the collision group (on the collision object) as well.

Have a look at this example as it explains the setup involved:

In the defold Tilemap collisions tutorial, it says that the mask field is for what you want the collision object to interact with. I want the player to collide with the “objects” collision group (which should only be stuff I’ve set it too, such as the fountain or the house tiles).
It also says that when there are multiple collision groups within a tilesource, to leave the collision group blank and it will use the collision groups I set the tiles to.

I already followed that, I didn’t put the code in but I’ve just tried that and the result doesn’t change at all

There is one massive gotcha when using a tile source for collisions.
The tile source collision property needs to be explicitly set to the same thing as image map. I think this should be done by default, I don’t understand why it is not as most of the time it is want you want. At the least there should be a way to highlight it in the editor. It does tell you in the manual, it is easy to miss.

Could you elaborate on what I need to do for that?

I noticed that you’ve set the collision object type to Dynamic. You should use either Static or Kinematic. If it is Dynamic it means that it will be affected by gravity and your whole map will start falling :slight_smile:

I also recommend that you turn on physics debugging to see the shapes and how they interact: Debugging in Defold

In the Outline window for the tile source set the Collision field to the same thing as you have set the image image to. For example:

Done that and now the map stays in place lol.
But nothing happens when I walk into the tiles that I’m meant to collide with,
I haven’t coded anything to tell it how what to do when it they collide,
I just want the player not to be able to walk onto tiles where I have set collision, how would I go about coding that?

You need to resolve the collisions using the contact points of the collision:

Also take a look at https://github.com/defold/sample-pixel-line-platformer

1 Like

I’ve just gotten around to implementing this, where am I meant to include this within my main.collection?
image

You should add the script on the same games object which has the collision object, just like in that picture. Is it not working?

I copied this code from “Resolving kinematic collisions in Defold” into the script and then put it in the main collection, I can’t see any points where I might have had to change variables to fit my code instead of the ones they put in.

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

    function update(self, dt)
      -- reset correction
      self.correction = vmath.vector3()
    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

Did you put it in a script attached to the player game object, ie the same object as the one having the collision object and the player sprite?

I encourage you to compare your project with one of the example project showing how to use a tilemap with collisions and a player game object. For instance this platformer:

I know it’s been a few days, but i’ve only just gotten back to working on this, I’ve had a look at the other project, and I compared how it was laid out to how mine was and I cannot figure out where i’m going wrong. I tried using the code in that for mine, changing and removing some things that I thought I needed to change or remove but it did not work.

were you ever able to get this to work, because I am having the same/ a similar issue

Can you describe in detail what is not working and perhaps also share some screenshots of your configuration of collision objects?

Have you looked at the linked example project and compared with your own project?

the player object is not colliding with the Black border, or any other elements. I have looked at the example project.

I have also handled a collision as seen below. this is in my player script

local CONTACT_POINT_RESPONSE = hash("contact_point_response")
local BORDER = hash("border")



function init(self)
	msg.post(".","acquire_input_focus")
	msg.post("@render", "use_camera_projection")
	camera.acquire_focus("operatorMap#cameramap")
	self.correction = vmath.vector3(0, 0, 0)
	self.vel = vmath.vector3(0, 0, 0) -- Initialize velocity
end


local function flip(direction)
	sprite.set_hflip("#sprite", direction < 0) --flips sprite horizontally, first file, 2nd true false if they Should be flipped
end

local function play_animation(self, newAnimation)
	if self.animation ~= newAnimation then
		sprite.play_flipbook("#sprite", newAnimation) --first is file that controls it, second is name of animation
		self.animation = newAnimation
	end
end

local function animate(self)
	if self.groundContact then
		if self.velocity == 0 then
			play_animation(self, "IdleMap")
		else 
			play_animation(self, "IdleMap") --idle is stand in for movement animation
		end
	else
		play_animation(self, "IdleMap") -- idle is stand in for jumping animation
	end
end


function update(self, dt)
	local pos = go.get_position() -- Get current position
	pos = pos + self.vel * dt -- Update position based on velocity
	go.set_position(pos) -- Set new position
	self.vel.x = 0 -- Reset velocity
	self.vel.y = 0

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

function on_input(self, action_id, action)
	if action_id == hash("up") then
		self.vel.y = BASEVELOCITY -- Move up
	elseif action_id == hash("down") then
		self.vel.y = -BASEVELOCITY -- Move down
	elseif action_id == hash("left") then
		self.vel.x = -BASEVELOCITY -- Move left
	elseif action_id == hash("right") then
		self.vel.x = BASEVELOCITY -- Move right
	elseif action_id == hash("esc") and action.released then
		msg.post("menu#PauseMenu", "enable")
	end
end


local function handleLevelCollisions(self, normal, distance)
	if normal == nil then
		print("Error: normal is nil")
		return
	end

	print("Collision Normal:", normal)

	-- 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 distance > 0 then
		-- First, project the accumulated correction onto
		-- the penetration vector
		local proj = vmath.project(self.correction, normal * distance)
		if proj < 1 then
			-- Only care for projections that does not overshoot.
			local comp = (distance - distance * proj) * normal
			-- Apply compensation
			go.set_position(go.get_position() + comp)
			-- Accumulate correction done
			self.correction = self.correction + comp
		end
	end
end

function on_message(self, message_id, message, sender)
	if message_id == CONTACT_POINT_RESPONSE then
		if message.group == BORDER then
			handleLevelCollisions(self, message.normal, message.distance)
		end
	end

	if message_id == hash("startRecievingInput") then
		recievingInputs = true
		print("restarting inputs")
	end

	if message_id == hash("stopRecievingInput") then
		recievingInputs = false --this isn't connecting properlt eith itself in this script
		print("Stopping all inputs")
	end
end

What if you enable physics debugging, do you see shapes where you expect them to be?