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
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 GitHub - defold/sample-pixel-line-platformer: Defold sample project for a platformer game.
I’ve just gotten around to implementing this, where am I meant to include this within my main.collection?
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?