# Orientation align

TLDR: How would you implement an algorithm that makes an entity rotate until it gets close to a target orientation at which point it slows down the rotation and completely stops the rotation when it hits the matching orientation? Also, what is the simplest way in PlayCanvas to get an entity’s orientation around the Y axis in a scale of (-180 to 180)?

I’m working with objects only moving on a 2D plane. I found this nice algorithm to smoothly match a game object’s orientation with that of another target game object. Here it is in pseudo-code:

``````1 class Align:
2 # Holds the kinematic data for the character and target
3 character
4 target
5
6 # Holds the max angular acceleration and rotation
7 # of the character
8 maxAngularAcceleration
9 maxRotation
10
11 # Holds the radius for arriving at the target
13 speed
14 # Holds the radius for beginning to slow down
16
17 # Holds the time over which to achieve target speed
18 timeToTarget = 0.1
19
20 def getSteering(target):
21
22 # Create the structure to hold our output
23 steering = new SteeringOutput()
24
25 # Get the naive direction to the target
26 rotation = target.orientation -
27 character.orientation
28
29 # Map the result to the (-pi, pi) interval
30 rotation = mapToRange(rotation)
31 rotationSize = abs(rotation)
32
33 # Check if we are there, return no steering
35 return None
36
37 # If we are outside the slowRadius, then use
38 # maximum rotation
40 targetRotation = maxRotation
41
42 # Otherwise calculate a scaled rotation
43 else:
44 targetRotation =
45 maxRotation * rotationSize / slowRadius
46
47 # The final target rotation combines
48 # speed (already in the variable) and direction
49 targetRotation *= rotation / rotationSize
50
51 # Acceleration tries to get to the target rotation
52 steering.angular =
53 targetRotation - character.rotation
54 steering.angular /= timeToTarget
55
56 # Check if the acceleration is too great
57 angularAcceleration = abs(steering.angular)
58 if angularAcceleration > maxAngularAcceleration:
59 steering.angular /= angularAcceleration
60 steering.angular *= maxAngularAcceleration
61
62 # Output the steering
63 steering.linear = 0
64 return steering
``````

The algorithm requires that I be able to calculate the angle around the Y axis for both objects in order to determine the shortest ‘distance’ and direction between both orientations. It is implemented in radians but can easily be done with degrees. I have written a function that takes in a start angle and stop angle and returns the shortest distance between them in positive or negative degrees indicating the direction. The function takes in any positive or negative numbers, and outputs degrees between -180 and 180.

I have been trying to get the entities’ Y axis orientation by doing entity.getRotation().y but I quickly realized that this output is not on a -180 to 180 scale but rather a -90 to 90 scale and is dependant on the rotation value of x (0 or 180) to know the correct half of the circle. This is starting to get complicated.

The algorithm is pretty simple, it basically makes the entity rotate until it gets close to the target orientation at which point it slows down the rotation and stops rotation when it hits the matching orientation. How would you implement this in PlayCanvas? Is there a simpler way, or one that fits more naturally with PlayCanvas, that the one in the proposed algorithm. If not, what is the simplest way to get an entity’s orientation around the Y axis in a scale of (-180 to 180) ?

How to get an entity’s Y rotation in radians using pc.Entity#forward and Math.atan2:

``````// Let's assume the entity's forward axis (negative Z) is not
// pointing straight up/down (Y axis)
var forward = this.entity.forward;
``````

To ease a Y rotation from one number to another, you could just use pc.math.lerpAngle.

2 Likes

To use lerpAngle, I’ll have to set the rotation with pc.Entity.setRotation, won’t I? Will that still work on a dynamic rigidbody? I was under the impression that the Entity setPosition and setRotation methods were not to be used on a dynamic rigidbody.

You can use pc.Entity#setEulerAngles (or preferably pc.Entity#setLocalEulerAngles which is faster to execute). Just set the y parameter to the angle around the Y axis.

Correct. To set the position/rotation of an entity with a rigid body, instead use pc.RigidBodyComponent#teleport.

1 Like

But the teleport method sets the position and the rotation and I only want to set the rotation, since I’m using forces and impulses for position changes. Should I just do something like this:

``````this.entity.rigidbody.teleport(this.entity.getPosition(), myNewRotation)
``````

Yes, that’s correct.

Actually, I get weird stuttering behavior when I do that. It looks like the best option is still to implement the algorithm I found that sets angularVelocity instead. I’ll try it again, this time with your suggestion of using entity.forward and atan2.

You should not used teleport every frame. It’s to instantly move a rigid body from one place to another. By calling it, you are ‘interfering’ with the physics simulation. So, a good use case is when your level resets.

Dynamic bodies should just be controlled via forces/impulses or by setting linear/angular velocities.

1 Like

Ok, this confirms what I thought. Lerp and slerp are great for static or kinematic entities, but in practice, you can’t really use them to set a dynamic rigidbody’s rotation.

1 Like