I am making a 2D platformer with Lua using Defold, and when my player collides with a wall, I can’t manage to get the walking animation to stop.
I tried to use flags as you can see in the code to prevent this, but it has not worked. The walk animation continues to play, and the player continues to push against the wall.
local right = hash("right") -- using a hash of the action_ids saves time
local left = hash("left") -- prehashing also saves resources, as it does not have to be hashed each time input detected
local idle = hash("idle") -- prehashing of animation names, saves resources
local walk = hash("walk")
local current_anim = idle -- set to idle by default, as this is the starting animation
local r_colliding = false -- sets flags to false at start of level
local l_colliding = false
local x_movement = 200 -- not hardcoded, so can be changed if need be
local move_direction = 0
function init(self)
msg.post(".", "acquire_input_focus") -- allows the script to handle inputs
end
local function animate(anim) -- dedicated for animations, improves modularity
if current_anim ~= anim then -- checks that the animation is not already being played
sprite.play_flipbook("#sprite", anim)
current_anim = anim -- updates the current animation
end
if move_direction == 1 then -- if facing right
sprite.set_hflip("#sprite",false) -- flip -> false
elseif move_direction == -1 then -- if facing left
sprite.set_hflip("#sprite",true) -- flip -> true
end
end
local function collision_anim(message)
if message.normal.x > 0.7 then -- if collision on right
r_colliding = true
l_colliding = false
elseif message.normal.x < -0.7 then -- if collision on left
r_colliding = false
l_colliding = true
else -- if not, reset flags to false
r_colliding = false
l_colliding = false
end
end
function on_message(self, message_id, message, sender)
if message_id == hash("contact_point_response") then -- if collision, call function
collision_anim(message)
end
end
function fixed_update(self, dt)
local pos = go.get_position() -- gets the current position
pos.x = pos.x + x_movement * move_direction * dt -- x_position + x_movement, * dir & diff between prev frame
go.set_position(pos) -- updates pos
if move_direction ~= 0 then -- if player is not moving
animate(walk) -- call animation function, with walk as argument
else -- if player not moving
animate(idle) -- call animaton function, with idle as argument
end
end
function on_input(self, action_id, action)
if action_id == right and not r_colliding then -- only move right, when not colliding with right
move_direction = 1 -- sets direction
elseif action_id == left and not l_colliding then -- only move left when not colliding with left
move_direction = -1
end
if action.released then
move_direction = 0 -- sets direction to 0, so player does not move
end
end
You only set move_direction to 0 when releasing key (not specifying which one). Isn’t this explain the behavior you are describing? (I’m not sure, you need to add more - are you pressing keys, standing near wall etc )
Maybe you could make a nested if - something like:
if action_id == right then
if action.pressed then ...
else if action.released then ...
end
end
Also - utilize the powerful Defold debugger, it might help you understand a bit more:
Thank you for suggesting the debugger, I will try to see if there’s anything I can do.
I’ve made changes to my code which account for this, also I was having issues with pressing both keys at the same time, so that fixed this.
Apologies for not providing enough detail earlier - the main issue is, that when the player holds the movement key, and reaches a wall, instead of the walk animation stopping, the animation continues to play. The way I tried to stop this, is by only allowing them to move in either direction if they are not colliding with something, but this does not seem to work, and the animation continues to play.
local right = hash("right") -- using a hash of the action_ids saves time
local left = hash("left") -- prehashing also saves resources, as it does not have to be hashed each time input detected
local idle = hash("idle") -- prehashing of animation names, saves resources
local walk = hash("walk")
local current_anim = idle -- set to idle by default, as this is the starting animation
local r_colliding = false -- sets flags to false at start of level
local l_colliding = false
local x_movement = 200 -- not hardcoded, so can be changed if need be
local move_direction = 0
function init(self)
msg.post(".", "acquire_input_focus") -- allows the script to handle inputs
end
local function animate(anim) -- dedicated for animations, improves modularity
if current_anim ~= anim then -- checks that the animation is not already being played
sprite.play_flipbook("#sprite", anim)
current_anim = anim -- updates the current animation
end
if move_direction == 1 then -- if facing right
sprite.set_hflip("#sprite",false) -- flip -> false
elseif move_direction == -1 then -- if facing left
sprite.set_hflip("#sprite",true) -- flip -> true
end
end
local function collision_anim(message)
if message.normal.x > 0.7 then -- if collision on right
r_colliding = true
l_colliding = false
elseif message.normal.x < -0.7 then -- if collision on left
r_colliding = false
l_colliding = true
else -- if not, reset flags to false
r_colliding = false
l_colliding = false
end
end
function on_message(self, message_id, message, sender)
if message_id == hash("contact_point_response") then -- if collision, call function
collision_anim(message)
end
end
function fixed_update(self, dt)
local pos = go.get_position() -- gets the current position
pos.x = pos.x + x_movement * move_direction * dt -- x_position + x_movement, * dir & diff between prev frame
go.set_position(pos) -- updates pos
if move_direction ~= 0 then -- if player is not moving
animate(walk) -- call animation function, with walk as argument
else -- if player not moving
animate(idle) -- call animaton function, with idle as argument
end
end
function on_input(self, action_id, action)
-- If the key is released, stop movement
if action.released then
if action_id == right and move_direction == 1 then
move_direction = 0 -- Stop moving right when right is released
elseif action_id == left and move_direction == -1 then
move_direction = 0 -- Stop moving left when left is released
end
else
-- Handle right input
if action_id == right and move_direction == 0 and not r_colliding then
move_direction = 1 -- Move right if no direction is currently active
-- Handle left input
elseif action_id == left and move_direction == 0 and not l_colliding then
move_direction = -1 -- Move left if no direction is currently active
end
end
end
Thank you for this, apologies for the late reply. I think I’ve nailed down the issue, but I’m not sure how exactly to fix it? So I think the problem lies within the collision_anim function. Every time a collision is detected it is called, so even if the player is colliding with the side of the object, another collision, say the floor will also be passed into this function, setting the values of r_colliding and l_colliding to false.
I only want to account for the side collisions, but I’m not sure how to do this.