This would be a long post with question in the end.
Hi I need to rotate object via player input (mouse for now) and count rotation turns (or spins). Object could be rotated in any direction - clockwise (cw) or counterclockwise (ccw).
For base for movement I’ve taken this example - britzl/defold-orthographic. Shout out to author, his examples always helps me a lot =)
In update() function of the hitman/player script I add something like this to count rotation turns when player hold “mouse button 1”:
-- [hitman.script](https://github.com/britzl/defold-orthographic/blob/master/example/shared/objects/hitman.script)
local function process_spin(self, angle)
-- transform angle from rad to degree and normilize to 0 - 360
angle = angle * 180/3.14159
if angle < 0 then
angle = 360 + angle
end
-- set initial values on grab - when the player click mouse button 1
if not self.grab then
self.grab = true
self.initial_angle = angle
end
-- get the current angle of the object
local current_angle = angle
-- calculate the difference between the current and initial angles
local angle_diff = current_angle - self.initial_angle
angle_diff = math.floor(angle_diff)
-- normalize the angle difference to be between -180 and 180 degrees
if angle_diff > 180 then
angle_diff = angle_diff - 360
elseif angle_diff < -180 then
angle_diff = angle_diff + 360
end
-- check and set rotation direction: cw or ccw
if self.rotation_direction == 0 then
if angle_diff < 0 then
self.rotation_direction = 1
elseif angle_diff > 0 then
self.rotation_direction = -1
end
end
-- normilize rotation to 0 - 360 degree
if angle_diff < 0 then
angle_diff = 360 + angle_diff
end
-- count turns
if (self.rotation_direction == 1 and angle_diff <= 5 and angle_diff > 0)
or (self.rotation_direction == -1 and angle_diff >= 355) then
self.turn_count = self.turn_count + 1
self.initial_angle = angle
end
end
function update(self, dt)
...
-- line 27
if self.input[hash('touch')] then
process_spin(self, angle)
elseif self.grab then
self.grab = false
self.last_diff = 0
self.rotation_direction = 0
end
...
end
And this code works at first. The bug is when player change rotation direction while holding “mouse button 1”. So I add check for rotation direction in process_spin function (don’t like how it looks, need to be cleared):
-- check change in dirrection
-- this if statement changed a lot, but always has some bugs...
if self.last_diff ~= 0 and (self.last_diff - angle_diff) ~=0
and ((angle_diff ~= 0 and self.rotation_direction == -1) or (self.rotation_direction == 1)) then
local new_direction = 0
if (self.last_diff - angle_diff) > 0 then
new_direction = 1
elseif (self.last_diff - angle_diff) < 0 then
new_direction = -1
end
if new_direction ~= self.rotation_direction then
self.grab = false
self.rotation_direction = 0
self.initial_angle = angle
self.last_diff = 0
end
if self.last_diff ~= angle_diff then
self.last_diff = angle_diff
end
And this part gave me a lot of issues, when player change direction on early start around 0 degree. When one start rotate in one direction from angle_diff
= 0 to angle_diff
= 1 degree and drastically changes the direction to, say, angle_diff
= 358 degree. Code go crazy on this 1 - 358 degree change, because it looks like very quick full circle =)
After some playing with if statement I thought that I’m going a wrong way and I need to deep dive into quaternion topic (never used them before). Long story short I came up with this code:
-- [hitman.script](https://github.com/britzl/defold-orthographic/blob/master/example/shared/objects/hitman.script)
-- line 24
local rotation = vmath.quat_rotation_z(angle)
local rot_diff = vmath.conj(go.get_rotation()) * rotation
local direction = math.floor(rot_diff.z * 100)
-- direction < 0 - clockwise; direction > 0 - counterclockwise.
go.set_rotation(rotation)
This code seems to be working, but I’m not sure that it is optimal for such a task. Quat conjugate and multiply could be heavy to calculate… Have not done performance testing yet.
Maybe I could get rotation direction in more easy or efficient way? In fact when I set new rotation go.set_rotation(rotation)
object rotate in right direction, “closest direction”. So engine already know it would be cw or ccw. Maybe I can get this info without additional calculations?