How do I stop the walk animation for my player when they walk into a wall?

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

Thank you :slight_smile:

1 Like

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 :wink: )

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 updated my code to account for what you mentioned, 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

Something like this

    if (move_direction == 1 and not r_colliding) or (move_direction == -1 and not l_colliding then
        animate(walk)
    else
        animate(idle)
    end

You might have to mess with it but that should give you the idea of how to do it.