Stuck in animation, changing state breaks at random. on_message problem?

Hi,

I know this is probably and hopefully just a basic programming question but it seems like it should work as intented. I tried changing multiple things but my animation states break at random.

Further explanation: in my game the player can “idle”, “dig” and get an “emerald”. These are the possible states. I want to switch from the “dig” state back to “idle” in case the player does not find an emerald.

This is done by a simple on_message when the animation is finished. But at random times I get stuck in the dig state on the last frame (because the animation is played once only). I can’t seem the figure out why. It would make sense if it would be stuck all the time but it is just random. I have the feeling that clicking more often (“touch” == click input) is more likely to break it.

Here is the whole player script. There is no other script within the game that could interfer with it.

function init(self)
	msg.post(".", "acquire_input_focus")

	math.randomseed(os.time())
	

	self.anim = "idle"
	self.states = {"idle", "dig", "emerald"}
	self.state = self.states[1] -- Starting in idle state
	self.emeraldProb = 0.10
	self.money = 0
	
end

local function animate(self, dt)
	local currentAnim = go.get("#sprite", "animation") --hashed!
	self.anim = self.state
	if currentAnim ~= hash(self.anim) then
		msg.post("#sprite", "play_animation", {id = hash(self.anim)})
	end
end

local function dig(self)
	local checkProb = math.random()
	if checkProb < self.emeraldProb then
		self.state = self.states[3]
		self.money = self.money + math.random(100, 300)
		print(self.money)
	else
		return
	end
end


function final(self)
	
end

function update(self, dt)

	animate(self, dt)
	print(self.state)
end

function fixed_update(self, dt)
	
end

function on_message(self, message_id, message, sender)
	if message_id == hash("animation_done") then
		self.state = self.states[1]
	end
end

function on_input(self, action_id, action)
	if action_id == hash("touch") and self.state == self.states[1] and action.pressed then
		self.state = self.states[2]
		dig(self)
	end

	if action_id == hash("right") and self.state == self.states[3] and action.pressed then
		self.state = self.states[1]
	end
end

function on_reload(self)
	
end

I would greatly appreciate looking into my problem because I have the feeling it is system related. And I would really like to know that it is just my missing programming skills :grinning_face_with_smiling_eyes: .

Thanks in advance for reading!

Somehows I see your animate function sending msg.post alot.
You can use this code to see if your issue fixed?

local function animate(self, dt)
	if self.anim ~= self.state then
        self.anim = self.state
		msg.post("#sprite", "play_animation", {id = hash(self.anim)})
	end
end

Thanks for reading and trying helping me out! But this does not fix my issue. I still have random breaks of the state machine change and I get stuck on the “dig” state.

In on_message you immediately change the state and call dig(). And in update() you call animate() every frame. This feels a bit strange to me. I would keep track of one state and don’t mix current animation and state. Something like this:

local STATE_IDLE = hash("idle")
local STATE_DIG = hash("dig")
local STATE_EMERALD = hash("emerald")

local function animate(self, anim)
	if self.anim ~= anim then
		self.anim = anim
		msg.post("#sprite", "play_animation", {id = anim})
	end
end

local function dig(self)
	local checkProb = math.random()
	if checkProb < self.emeraldProb then
		animate(self, STATE_EMERALD)
		self.money = self.money + math.random(100, 300)
		print(self.money)
	else
		animate(self, STATE_DIG)
	end
end

local function idle(self)
	animate(self, STATE_IDLE)
end

function init(self)
	msg.post(".", "acquire_input_focus")

	math.randomseed(os.time())

	self.anim = STATE_IDLE
	self.emeraldProb = 0.10
	self.money = 0
end

function on_message(self, message_id, message, sender)
	if message_id == hash("animation_done") then
		idle(self)
	end
end

function on_input(self, action_id, action)
	if action_id == hash("touch") and self.anim == STATE_IDLE and action.pressed then
		dig(self)
	end

	if action_id == hash("right") and self.anim == STATE_EMERALD and action.pressed then
		idle(self)
	end
end
3 Likes