I’m using a sprite the moves 8 directions, and I also have a 4 Idle animation for him, Up, Down Left, Right.
The problem is that the up animation the only one that’ll show after a while.
For example If I go right and stop it’ll show the Right Idle animation then start to move left It’ll show the left Idle animation and won’t show the right Idle animation then the down won’t show both the left and right Idle animation, and the up doesn’t show the Right, Left and, Down Idle animation
function update(self, dt)
if self.actions[hash("Left")] then
play_animation(self, hash("Player Left"))
self.direction.x = -self.speed
elseif self.actions[hash("Right")] then
play_animation(self, hash("Player Right"))
self.direction.x = self.speed
else
self.direction.x = 0
end
if self.actions[hash("Up")] then
play_animation(self, hash("Player Up"))
self.direction.y = self.speed
elseif self.actions[hash("Down")] then
play_animation(self, hash("Player Down"))
self.direction.y = -self.speed
else
self.direction.y = 0
end
if self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Up")] == false then
play_animation(self, hash("Idle Up"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Down")] == false then
play_animation(self, hash("Idle Down"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Left")] == false then
play_animation(self, hash("Idle Left"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Right")] == false then
play_animation(self, hash("Idle Right"))
end
I’d store the current actions in a table, and process them like this:
self.keypress = {
up = false,
down = false,
left = false,
right = false
}
if action_id == hash("<any_keypress_here>") and action.pressed then
self.keypress.<the_opposite_keypress> = false
self.keypress.<that_keypress> = true
-- and repeat for each keypress
-- THEN
if action_id == hash("<any_keypress_here>") and action.released then
self.keypress.<that_keypress> = false
-- Now you process the keypresses
if action_id == hash("<keypress1>") or action_id == hash("<keypress2>") or action_id == hash("<keypress3>") or action_id == hash("<keypress4>") then
if self.keypress.up == true and <nothing else is true> then
-- North animation
-- repeat for West, South, and East movements
-- Now, combos:
if self.keypress.up == true and self.keypress.left = true then
-- Northwest animation
-- and repeat for the 4 combinations
Woops, I’m sorry. I was basing my answer off of your post in another topic.
Let me take a look at your code. I re-read what you said. I was confused when you were trying to give an example, but now I understand. The problem you’re having is that the Up animation is getting stuck after a while? Oh, or did you mean that when you press Up, all the other idle animations no longer work?
Could you include the code for how you set the self.actions table?
when I press Up, all the other idle animations no longer work
go.property("speed", 5)
local function play_animation(self, animation)
if self.current_animation ~= animation then
self.current_animation = animation
msg.post("#sprite", "play_animation", { id = animation })
end
end
function init(self)
msg.post(".", "acquire_input_focus")
self.direction = vmath.vector3(0,0,0)
self.actions = {}
self.current_animation = nil
end
function final(self)
msg.post(".", "release_input_focus")
end
function update(self, dt)
if self.actions[hash("Left")] then
play_animation(self, hash("Player Left"))
self.direction.x = -self.speed
elseif self.actions[hash("Right")] then
play_animation(self, hash("Player Right"))
self.direction.x = self.speed
else
self.direction.x = 0
end
if self.actions[hash("Up")] then
play_animation(self, hash("Player Up"))
self.direction.y = self.speed
elseif self.actions[hash("Down")] then
play_animation(self, hash("Player Down"))
self.direction.y = -self.speed
else
self.direction.y = 0
end
if self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Up")] == false then
play_animation(self, hash("Idle Up"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Down")] == false then
play_animation(self, hash("Idle Down"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Left")] == false then
play_animation(self, hash("Idle Left"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Right")] == false then
play_animation(self, hash("Idle Right"))
end
go.set_position(go.get_position() + self.direction * dt)
end
function on_input(self, action_id, action)
if action_id then
if action.pressed then
self.actions[action_id] = true
elseif action.released then
self.actions[action_id] = false
end
end
end
if self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Up")] == false then
play_animation(self, hash("Idle Up"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Down")] == false then
play_animation(self, hash("Idle Down"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Left")] == false then
play_animation(self, hash("Idle Left"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.actions[hash("Right")] == false then
play_animation(self, hash("Idle Right"))
end
This block here is running the same check for each statement, which essentially defaults it to the first statement that returns correctly. The reason that Up breaks all the other idle animations is because it’s the first statement. Another thing: It doesn’t break it until you press the Up key because self.actions[hash(“Up”)] is equal to nil until it’s first pressed.
This should fix your issue:
-- You can add this for simplicity,
-- or just put the values back into your if statements. Place this in function init()
self.actions = {
up = hash("Up"),
down = hash("Down"),
left = hash("Left"),
right = hash("Right")
}
-- State this variable in function init(), otherwise you'll have errors.
self.last_pressed = ""
function on_input(self, action_id, action)
if action_id then
if action.pressed then
self.actions[action_id] = true
-- ADD THIS:
if action_id == self.actions.up or action_id == self.actions.down or action_id == self.actions.left or action_id == self.actions.right then
self.last_pressed = action_id
end
--
elseif action.released then
self.actions[action_id] = false
end
end
end
if self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.up then
play_animation(self, hash("Idle Up"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.down then
play_animation(self, hash("Idle Down"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.left then
play_animation(self, hash("Idle Left"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.right then
play_animation(self, hash("Idle Right"))
end
go.property("speed", 5)
local function play_animation(self, animation)
if self.current_animation ~= animation then
self.current_animation = animation
msg.post("#sprite", "play_animation", { id = animation })
end
end
function init(self)
msg.post(".", "acquire_input_focus")
self.direction = vmath.vector3(0,0,0)
self.actions = {}
self.current_animation = nil
end
self.actions = {
up = hash("Up"),
down = hash("Down"),
left = hash("Left"),
right = hash("Right")
}
self.last_pressed = ""
function final(self)
msg.post(".", "release_input_focus")
end
function update(self, dt)
if action_id then
if action.pressed then
self.actions[action_id] = true
-- ADD THIS:
if action_id == self.actions.up or action_id == self.actions.down or action_id == self.actions.left or action_id == self.actions.right then
self.last_pressed = action_id
end
--
elseif action.released then
self.actions[action_id] = false
end
end
end
if self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.up then
play_animation(self, hash("Idle Up"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.down then
play_animation(self, hash("Idle Down"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.left then
play_animation(self, hash("Idle Left"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.right then
play_animation(self, hash("Idle Right"))
end
go.property("speed", 5)
local function play_animation(self, animation)
if self.current_animation ~= animation then
self.current_animation = animation
msg.post("#sprite", "play_animation", { id = animation })
end
end
function init(self)
msg.post(".", "acquire_input_focus")
self.direction = vmath.vector3(0,0,0)
self.actions = {
up = hash("Up"),
down = hash("Down"),
left = hash("Left"),
right = hash("Right")
}
self.last_pressed = ""
self.current_animation = nil
end
function final(self)
msg.post(".", "release_input_focus")
end
function update(self, dt)
if action_id then
if action.pressed then
self.actions[action_id] = true
-- ADD THIS:
if action_id == self.actions.up or action_id == self.actions.down or action_id == self.actions.left or action_id == self.actions.right then
self.last_pressed = action_id
end
--
elseif action.released then
self.actions[action_id] = false
end
end
end
if self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.up then
play_animation(self, hash("Idle Up"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.down then
play_animation(self, hash("Idle Down"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.left then
play_animation(self, hash("Idle Left"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.right then
play_animation(self, hash("Idle Right"))
end
This should be fixed up, but no guarantees since I’m on my phone
go.property("speed", 5)
local function play_animation(self, animation)
if self.current_animation ~= animation then
self.current_animation = animation
msg.post("#sprite", "play_animation", { id = animation })
end
end
function init(self)
msg.post(".", "acquire_input_focus")
self.direction = vmath.vector3(0,0,0)
self.actions = {
up = hash("Up"),
down = hash("Down"),
left = hash("Left"),
right = hash("Right")
}
self.last_pressed = ""
self.current_animation = nil
end
function final(self)
msg.post(".", "release_input_focus")
end
function update(self, dt)
if self.actions[hash("Left")] then
play_animation(self, hash("Player Left"))
self.direction.x = -self.speed
elseif self.actions[hash("Right")] then
play_animation(self, hash("Player Right"))
self.direction.x = self.speed
else
self.direction.x = 0
end
if self.actions[hash("Up")] then
play_animation(self, hash("Player Up"))
self.direction.y = self.speed
elseif self.actions[hash("Down")] then
play_animation(self, hash("Player Down"))
self.direction.y = -self.speed
else
self.direction.y = 0
end
if self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.up then
play_animation(self, hash("Idle Up"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.down then
play_animation(self, hash("Idle Down"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.left then
play_animation(self, hash("Idle Left"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.actions.right then
play_animation(self, hash("Idle Right"))
end
go.set_position(go.get_position() + self.direction * dt)
end
function update(self, dt)
if action_id then
if action.pressed then
self.actions[action_id] = true
-- ADD THIS:
if action_id == self.actions.up or action_id == self.actions.down or action_id == self.actions.left or action_id == self.actions.right then
self.last_pressed = action_id
end
--
elseif action.released then
self.actions[action_id] = false
end
end
end
Ok I found why it wasn’t moving you had the
function on_input(self, action_id, action) as a update. But still when I fixed it, it stopped showing the Idle animations and will just play the walking animations
I think you need to rethink where you put the movement logic. You’re duplicating a lot of information by storing key state in a variable and the rechecking it in update. It’s better to deal with setting movement direction and animation in on_input() where you have all of the information you need available. I’ve created an example here:
Alright, I’m back on my PC. Sorry for the wait. I agree with britzl. Your code isn’t optimal, but it’s a learning process. I overwrote one of your variables by accident.
I tested this in an empty project, and it worked! Let me know if you have any issues:
go.property("speed", 5)
local function play_animation(self, animation)
if self.current_animation ~= animation then
self.current_animation = animation
msg.post("#sprite", "play_animation", { id = animation })
end
end
function init(self)
msg.post(".", "acquire_input_focus")
self.direction = vmath.vector3(0,0,0)
self.actions = {}
self.key = {
up = hash("Up"),
down = hash("Down"),
left = hash("Left"),
right = hash("Right")
}
self.last_pressed = ""
self.current_animation = nil
end
function final(self)
msg.post(".", "release_input_focus")
end
function update(self, dt)
if self.actions[hash("Left")] then
play_animation(self, hash("Player Left"))
self.direction.x = -self.speed
elseif self.actions[hash("Right")] then
play_animation(self, hash("Player Right"))
self.direction.x = self.speed
else
self.direction.x = 0
end
if self.actions[hash("Up")] then
play_animation(self, hash("Player Up"))
self.direction.y = self.speed
elseif self.actions[hash("Down")] then
play_animation(self, hash("Player Down"))
self.direction.y = -self.speed
else
self.direction.y = 0
end
if self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.key.up then
play_animation(self, hash("Idle Up"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.key.down then
play_animation(self, hash("Idle Down"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.key.left then
play_animation(self, hash("Idle Left"))
elseif self.direction.x == 0 and self.direction.y == 0 and self.last_pressed == self.key.right then
play_animation(self, hash("Idle Right"))
end
go.set_position(go.get_position() + self.direction * dt)
end
function on_input(self, action_id, action)
if action_id then
if action.pressed then
self.actions[action_id] = true
-- ADD THIS:
if action_id == self.key.up or action_id == self.key.down or action_id == self.key.left or action_id == self.key.right then
self.last_pressed = action_id
end
--
elseif action.released then
self.actions[action_id] = false
end
end
end