Left and Right movement not working as expected

I’m having trouble with my game again, I have an action in which if you press the up key, the character swings a sword, I want it to be that if you are moving, you stop in place whilst the animation plays and continue on afterwards.
Moving up or down, it works as expected, but when moving left and right, the player just continues walking whilst swinging and i am stuck as to why. This is my code, it is the exact same for up and down as for left and right:

	if action_id == hash("sword") then
		if self.vel.y ~= 0 or self.vel.x ~= 0 then
			walking = true
		else
			walking = false
		end
		
		if direction == "up" then -- checks what direction the player is facing
			self.vel.x = 0 -- sets their x speed to 0
			self.vel.y = 0 -- sets their y speed to 0
			msg.post(".", "release_input_focus") -- stops the player from moving while the animation plays
			sprite.play_flipbook("#sprite", hash("NU_Attack"), function() -- plays the attack animation
				msg.post(".", "acquire_input_focus") -- allows the player to move again
				if walking == true then
					sprite.play_flipbook("#sprite", hash("NU_Walk")) -- Changes Animation to walk
				else
					sprite.play_flipbook("#sprite", hash("NU_Idle")) -- plays the idle animation
				end
			end)
			
		elseif direction == "down" then -- checks what direction the player is facing
			self.vel.x = 0 -- sets their x speed to 0
			self.vel.y = 0 -- sets their y speed to 0
			msg.post(".", "release_input_focus") -- stops the player from moving while the animation plays
			sprite.play_flipbook("#sprite", hash("ND_Attack"), function() -- plays the attack animation
				msg.post(".", "acquire_input_focus") -- allows the player to move again
				if walking == true then
					sprite.play_flipbook("#sprite", hash("ND_Walk")) -- Changes Animation to walk
				else
					sprite.play_flipbook("#sprite", hash("ND_Idle")) -- plays the idle animation
				end
			end)

		elseif direction == "left" then -- checks what direction the player is facing
			self.vel.x = 0 -- sets their x speed to 0
			self.vel.y = 0 -- sets their y speed to 0
			msg.post(".", "release_input_focus") -- stops the player from moving while the animation plays
			sprite.play_flipbook("#sprite", hash("NL_Attack"), function() -- plays the attack animation
				msg.post(".", "acquire_input_focus") -- allows the player to move again
				if walking == true then
					sprite.play_flipbook("#sprite", hash("NL_Walk")) -- Changes Animation to walk
				else
					sprite.play_flipbook("#sprite", hash("NL_Idle")) -- plays the idle animation
				end
			end)
			
		elseif direction == "right" then -- checks what direction the player is facing
			self.vel.x = 0 -- sets their x speed to 0
			self.vel.y = 0 -- sets their y speed to 0
			msg.post(".", "release_input_focus") -- stops the player from moving while the animation plays
			sprite.play_flipbook("#sprite", hash("NR_Attack"), function() -- plays the attack animation
				msg.post(".", "acquire_input_focus") -- allows the player to move again
				if walking == true then
					sprite.play_flipbook("#sprite", hash("NR_Walk")) -- Changes Animation to walk
				else
					sprite.play_flipbook("#sprite", hash("NR_Idle")) -- plays the idle animation
				end
			end)
		end
	end

If needed I can zip my project and send it if a closer look is needed to find the issue.

Please do not share your code as an image. Please share it as text instead and enclose it in three backticks (`)

oh alright, no problem, i’ll edit it into that

1 Like

This is asynchronous, and will enable/disable your game object to receive input.
This approach is not recommended as a solution, especially if you would also have more than 16 players&enemies using that mechanic (as the input stack is fixed size).

Instead, I recommend you keep the state of your character in your script.
E.g.

if action_id == hash("sword") then
    self.state = hash("attack_sword")
    ...

    ...
    self.state = hash("walking") -- or  hash("idle")
1 Like

What would the hash() variables be in self.state?
How would I assign them and how would they work?

These can help you keep track of which state your character is in. Is the character attacking, walking or idle? That sort of thing. You could go further and create a state machine for more complex character states and player interactions, but for a simple game it is sufficient to track the states like in the example.

I’d probably take it on step further and move the states to constants:


local STATE_SWORD_ATTACK = hash("attack_sword")
local STATE_WALKING = hash("walking")
local STATE_IDLE = hash("idle")

function on_input(self, action_id, action)
    if action_id == hash("sword") then
        self.state = STATE_SWORD_ATTACK
        ...

        ...
        self.state = STATE_WALKING -- or STATE_IDLE

The advantage is that there is less risk of typos, especially if you use a code linter/language server.

How does this help me though?
I’m not exactly sure how this would help solve my issue

The “walking” variable is a similar state.
What we propose is to keep a single variable (called “state”) with a value that tells you what state the character is in.
Hashes are good that way, since they are essentially an integer, but can be debug printed as a string.

So, keeping a state value to keep track of the state you are in, so that you can avoid certain code paths, like not triggering another sword attack if you are in a bad state.

E.g.

local function can_attack(self)
    return self.state == STATE_WALKING or self.state == STATE_IDLE
end

local function change_state(self,  state)
    self.state = state
    play_animation(self, state) -- left as an exercise
end

function update(self, dt)
    if self.input_attack and can_attack(self) then
        change_state(self, STATE_ATTACK)
    end
    self.input_attack = false
end

Doing it this way, the state is solely controlled by the logic in this script, and not the timings of enabling/disabling the input stack for the game objects.

This pattern is very common, and can vary in detail/features. It’s commonly known as a “state machine” and there is plenty of information online about such implementations.

2 Likes

I don’t quite understand how I’d go about changing my code to implement this to be honest.