Problems with movement animation sync (Solved)

Hello Guys,

I’m trying to make my hero walk through scenario but I can’t make a natural movement. See sample bellow

There are some ‘breaks’ while the pos.x it is increased or decreased.

How can i fix this?

Here is my animations:

Here is my hero.code:

local anim_to_right = hash("to_right")
local anim_idle_right = hash("idle_right")
local anim_to_left = hash("to_left")
local anim_idle_left = hash("idle_left")

function init(self)
	 msg.post(".", "acquire_input_focus")
    self.speed = 20
    self.right = true;
    self.left  = false;
    self.lastAnimation = anim_idle_right
end

local function toRight(self)
	self.right = true;
    self.left  = false;
	local p = go.get_position()
    p.x = p.x + self.speed 
    go.set_position(p)
end

local function toLeft(self)
	self.right = false;
    self.left  = true;
	local p = go.get_position()
    p.x = p.x - self.speed 
    go.set_position(p)
end

local function managerAnimation(self,newAnimation)
	if self.lastAnimation ~= newAnimation then
    	msg.post(".", "play_animation", {id = newAnimation})
      	self.lastAnimation = newAnimation
    end
end

function update(self, dt) end
function on_message(self, message_id, message, sender) end

function on_input(self, action_id, action)
    
    if action_id == hash("key_right") and action.repeated then 
      	toRight(self) 
      	managerAnimation(self,anim_to_right)
    elseif action_id == hash("key_left") and action.repeated  then 
    	toLeft(self) 
    	managerAnimation(self,anim_to_left)
    end
    
    if action_id == hash("key_right") and action.released then 
		managerAnimation(self,anim_idle_right)
	elseif action_id == hash("key_left") and action.released  then
		managerAnimation(self,anim_idle_left)
	end
    
end
1 Like

I think you are going about the movement logic in a little bit of an “odd” way, you see since I am not sure but I do not think that the action.repeated is called every single frame, and therefore the best way to do movement would be something along the lines of this:

function init(self)
    self.right = false
    self.left = false
end
function update(self, dt)
    local pos = go.get_position()
    if self.left then
        pos.x = pos.x - (speed * dt)
    elseif self.right then
        pos.x = pos.x + (speed * dt)
    end 
end

function on_input(self, action_id, action)
    self.right = false
    self.left = false
    if action_id == hash("key_right") then
        self.right = true
    elseif action_id == hash("key_left") then
        self.left = true
    end
end

So what is happening here is that you update the movement every frame, you have 2 variables, one for left and one for right. I might have made a small mistake or 2, but the idea is use booleans that you update in the input, and that you check every frame in the update method.

Also use dt, which converts the speed variable from pixels per frame to pixels per second, this compensates for lag, or slower computers and faster computers that don’t run exactly 60 fps.

1 Like

This has a delay game.project under “Input”, the values are “Repeat Delay” and “Repeat Interval”

2 Likes

Correct. By default action.repeated isn’t called every frame. You can set Repeat Interval in game.project so that you get an action.repeated call every frame, but I think it’s better to set a flags when actions are pressed and clear the flags when released and update animations and movement based on these flags, just like @dawo2002 suggested.

2 Likes

Hahaha this is a good definition for my code style!

Nice hint! really useful to solve this situation thank you!

Thanks man! it is a good alternative option but i prefer update the code to use the @dawo2002 solution and avoid change any default configuration. Probably when i learn more about defold i will start to change this configuration.

A really important information!!! Thanks a lot!

Problem Solved!
Guys now it is everything working! With yours hints I made the refactoring the code and fix this logic error in my game.
See the Result:

Thanks for all!
Thanks for your time!.

2 Likes

Excellent! Good to hear that we were able to help you! As a bonus: The solution where you keep track of the different input states using booleans can be encapsulated into a Lua module so that it is easy for you to reuse. I’ve done it in this Lua module that you’re free to use if you like, or you can do it yourself as well. It is used like this:

local input = require "ludobits.m.input"

function init(self)
	input.acquire()
end

function final(self)
	input.release()
end

function update(self, dt)
	if input.is_pressed(hash("left")) then
		go.set_position(go.get_position() - vmath.vector3(50, 0, 0) * dt)
	elseif input.is_pressed(hash("right")) then
		go.set_position(go.get_position() + vmath.vector3(50, 0, 0) * dt)
	end
end

function on_input(self, action_id, action)
	input.on_input(action_id, action)
end
3 Likes

hmmm! nice utility file. Thank you! So, if we are checking the pressed action inside the update function we don’t need a action.repeated because update function it is executed every frame/cicle. is this correct?

Yes, that is correct.

1 Like

Aren’t the get and set positions the wrong way round, logically in my head anyhoo? Is this a Lua quirk?

2 Likes

hmmm make sense @Davej, but at github it is equal. I’m not using this file yet, so lets waiting for @britzl answer.

1 Like

Lol, you’re right. My example was incorrect. Sorry about that and thank you for letting me know!!!

2 Likes