I have been trying to figure out a neat way of animating the transitional change of position for my character, but got stuck in trying to make the character turn towards the position… either I hit a gimbal-lock using “rotation” or a faulty quaternions using “rotation.z” resulting in a scaled object. (I can add gifs showing the visual issues later on request).
My last resort is to animate a different property representing the z rotation and setting this every update based on the self.crap value, but that’s an ugly hack so I would prefer not to. Appreciate any possible hint at a better solution
go.property("move_speed", 10)
go.property("turn_speed", 0.1)
function on_message(self, message_id, message, sender)
if message_id == hash("move_to") then
local direction = go.get_world_position() - message.position
-- Rotate to face target position
local forward = vmath.normalize(direction)
local rotation_z = math.atan2(forward.y, forward.x)
local target_rotation = vmath.quat_rotation_z(rotation_z)
go.animate(".", "rotation", go.PLAYBACK_ONCE_FORWARD, target_rotation, go.EASING_OUTCUBIC, self.turn_speed, 0)
go.cancel_animations(".", "position")
-- Move to target position
local distance = vmath.length(direction)
local duration = distance / self.move_speed
go.animate(".", "position", go.PLAYBACK_ONCE_FORWARD, message.position, go.EASING_LINEAR, duration, self.turn_speed, function()
msg.post(".", "stop")
end)
end
end
Easiest is probably to use the often forgotten property euler.
EDIT: The scale issue you see comes from the quaternion not being normalised when you only set the z. The squish-effect you see when animating the entire quaternion in some instances comes from something similar, a non-normalised lerp performed by the go.animate-system.
I’ve decided that currently it’s not possible to do this using only go.animate, since euler animations are limited to the 360 degrees available and Slerp isn’t an option. So for now I’ll resolve to this system.
go.property("move_speed", 10)
go.property("turn_speed", 0.1)
function update(self, dt)
if self.target_rotation then
local rot = vmath.slerp(dt*self.turn_speed, go.get_rotation(), self.target_rotation)
go.set_rotation(rot)
end
end
function on_message(self, message_id, message, sender)
if message_id == hash("move_to") then
local direction = go.get_world_position() - message.position
if vmath.length_sqr(direction) == 0 then
-- avoid repeated navigation and NAN values from 0 distance.
return
end
-- Rotate to face target position
local forward = vmath.normalize(direction)
local rotation_z = math.atan2(forward.y, forward.x)
self.target_rotation = vmath.quat_rotation_z(rotation_z)
-- Move to target position
local distance = vmath.length(direction)
local duration = distance / self.move_speed
local turn_delay = 1 / self.turn_speed
go.cancel_animations(".", "position")
go.animate(".", "position", go.PLAYBACK_ONCE_FORWARD, message.position, go.EASING_LINEAR, duration, turn_delay, function()
msg.post(".", "stop")
end)
end
end
If the underlying system could support Slerp for the “rotation” property that would be amazing
Animating eular.z it would make a reverse spin when trying to go from 359 to 1 degrees instead of changing the two degrees only, so animating that isn’t an option unless there’s Slerp, if using 360+ degrees I could subtract the current rotation before turning to the other as an option.
I’ve played around a bit more on euler.z and it seems to be a tad bit broken… when running this piece of code you will notice that it get stuck at either -80 or +80 degrees.
function update(self, dt)
local rot = go.get(".", "euler.z")
rot = rot - dt*10
print(rot)
go.set(".", "euler.z", rot)
end
EDIT: I tried to animate with negative and 360+ degrees but I notice that working in the field outside of the -80 and 80 degrees it starts flipping back and forth.
Euler rotation is broken as you can’t use it twice when going over 90 degrees…
I’ve have been using nested dummy game object that nevers rotate more than 90 degree in any direction, and yes, you can barf now.
I’ll try to gather some of the engine team members tomorrow (Monday) and discuss a solution and see if we can prioritise any issues related to rotation.