 # Count object rotation turns

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?

3 Likes

Sorry, I was not clear of my goal.
Game Object will be moved and rotated by player input. Now it is WASD + mouse, but I want to add controller (gamepad) support in future. Think of it like: you are rotating object around it’s axis using mouse. Here is GIF of how it looks for now: Well, the example logic of @britzl’s code still appplies imho.
Keeping a separate value with the accumulated angle is the way I would go too.
Yes, you would have to modify it to handle the case of rotating it both ways.

1 Like

Yeah, in my example I rotated on any action press but that can easily be changed:

``````function on_input(self, action_id, action)
if action_id == hash("right") then
if action.pressed then
self.accumulated_rotation = 0
self.rotation_direction = 1
elseif action.released then
self.rotation_direction = 0
end
elseif action_id == hash("left") then
if action.pressed then
self.accumulated_rotation = 0
self.rotation_direction = -1
elseif action.released then
self.rotation_direction = 0
end
end
end
``````

I’m rotating not by click, but by the mouse move, as in https://github.com/britzl/defold-orthographic/blob/master/example/shared/objects/hitman.script example.
I’m going to rework my script. I’ll post here the result.

1 Like

If you want the rotation of a GO1 to be controlled by the location of another GO2 (which might be controlled by an input action) then you could attach a collision object to GO1, and on_message it. This will do rotation:

``````local p = message.other_position
local t = go.get_position()
local angle = math.atan2(p.y- t.y, p.x - t.x)
local rot = vmath.quat_rotation_z(angle)
go.set_rotation(rot)
``````

Just needs some tweaking to do the counting.
Edit: Argg, just looked at the soln below, clearly I don’t know what I am talking about!

If you want the rotation of a GO1 to be controlled

I’ve already done it, via example that I mentioned in first post. My initial question was exactly about rotation counting I haven’t managed to perform rotation+count as were advised in previous posts. And come up with something that I don’t like, and has bugs )
I’ve prepared my demo here:

Use Mouse to rotate Game Object around it’s axis. Use Left mouse button to start rotation count.

BUT code breaks down to count rotations when you start to use WASD to move object and Mouse to rotate simultaneously. I need another way of finding rotation direction.

1 Like

I’ve reworked it Demo in github repo.
Use Mouse to rotate Game Object around it’s axis. Use Left mouse button to start rotation count. Use WASD to move object.
Thanks everyone for tips Would appreciate if someone has advises how to improve my code.

1 Like