Top Down 4 Direction movement

Hi I’m trying to create 4 directional movement for a Top Down game , I managed to somewhat code it based from the tutorials but there is some weird quirks I found:
it being the player character(in this case the Astronaut)

  1. When I press right key and hold it(it moves right), later I press and hold up or down key it would go up or down.

  2. When I press left key and hold it(it moves left), later I press and hold up or down key, it doesn’t move up or down it just keeps going left.

  3. When I press up key and hold it(it moves up), and later I hold and press the left or right key, only the left key let it moves (to the left), while right does nothing

  4. Same with (3) except this is when I test press and hold down key

I don’t really understand why this is happening.

My first goal was to make the game just follow the first key being pressed and hold.

The code for astronaut.script


local speed = 100

local anim_idle = hash("idle")
local anim_move_up = hash("move_up")
local anim_move_down = hash("move_down")
local anim_move_left = hash("move_left")
local anim_move_right = hash("move_right")

function init(self)
	msg.post(".", "acquire_input_focus")
	self.dir = vmath.vector3(0,0,0)
	self.dir_pressed = false
	self.anim = nil
end


local function play_animation(self, anim)
	-- only play animations which are not already playing
	if self.anim ~= anim then
		-- tell the sprite to play the animation
		msg.post("#sprite", "play_animation", {id = anim})
		-- remember which animation is playing
		self.anim = anim
	end
end

local function update_animations(self)
	if self.dir.y == 1 then
		play_animation(self, anim_move_up)
	elseif self.dir.y == -1 then
		play_animation(self, anim_move_down)
	elseif self.dir.x == -1 then
		play_animation(self, anim_move_left)
	elseif self.dir.x == 1 then
		play_animation(self, anim_move_right)		
	else
		play_animation(self, anim_idle)
	end
end


function update(self, dt)
	local pos = go.get_position()
	--if vmath.length(self.dir) > 0 then
	--	self.dir = vmath.normalize(self.dir)
	--end
	go.set_position(pos + self.dir * speed * dt)
	
	update_animations(self)
	self.dir = vmath.vector3()
end

function on_message(self, message_id, message, sender)
	-- later
end

function on_input(self, action_id, action)
	if action_id == hash("right") and self.dir.x == 0 and self.dir.y == 0 then
		self.dir.x = 1
		self.dir.y = 0
	elseif action_id == hash("left") and self.dir.x == 0 and self.dir.y == 0 then
		self.dir.x = -1
		self.dir.y = 0
	elseif action_id == hash("front") and self.dir.y == 0 and self.dir.x == 0 then
		self.dir.y = -1
		self.dir.x = 0
	elseif action_id == hash("back") and self.dir.y == 0 and self.dir.x == 0 then
		self.dir.y = 1
		self.dir.x = 0
	end

end

It’s impossible to say why your code behaves this way unless you post the code.

My guess is that you have a dependency on the order of the if-statements in your code.

2 Likes

What is important to understand is that each keypress generates a separate call to on_input. If you press and hold a certain key you will get one call when the key is pressed (action.pressed is set to true), you will later get calls with action.repeated set to true and finally you will get one call when the key is released, with action.released set to true.

Now, this happens for every single key you press. If you want to only care about first presses, you can do the following:

  1. If a key is pressed, set a state variable (self.current_key, for instance) to that key value.
  2. If the state variable is set, ignore all key presses.
  3. If the key stored in the state variable is released, unset the variable.
3 Likes

oh my, I’ve completely forgot to copy and paste the code while making that post. sorry :disappointed_relieved: I’ll update when I get on my PC

1 Like

Thanks! the code works.

I’ve added self.curr_key = hash("") in the init function.
heres part of the code edited

function update(self, dt)
	local pos = go.get_position()
	--if vmath.length(self.dir) > 0 then
	--	self.dir = vmath.normalize(self.dir)
	--end
	go.set_position(pos + self.dir * speed * dt)
	
	update_animations(self)
	if self.curr_key == hash("") then
		self.dir = vmath.vector3()
	end
end
	
function on_message(self, message_id, message, sender)
	-- later
end

function on_input(self, action_id, action)
	if self.curr_key == hash("") then
		if action_id == hash("right") then
			self.dir.x = 1
			self.dir.y = 0
			self.curr_key = hash("right")
		elseif action_id == hash("left") then
			self.dir.x = -1
			self.dir.y = 0
			self.curr_key = hash("left")
		elseif action_id == hash("front") then
			self.dir.y = -1
			self.dir.x = 0
			self.curr_key = hash("front")
		elseif action_id == hash("back") then
			self.dir.y = 1
			self.dir.x = 0
			self.curr_key = hash("back")
		end
	end
	
	if action.released then
		self.curr_key = hash("")
	end
end

1 Like