I’ve a sport through which 2D sprites (on planes) are positioned right into a 3D atmosphere. The aircraft GameObjects displaying every sprite billboard towards the digital camera always. The sprites can rotate in 8 instructions alongside the X,Y axes (or X,Z within the case of Unity). Which course they rotate is set by one among two issues: their velocity and the digital camera’s place relative to them. The latter is necessary as a result of within the sport the digital camera can orbit the world and sprites dynamically. I replace the sprites by using animation BlendTrees, and map a normalized vector to every cardinal course accessible to the sprite.
Here is an illustration (not mine) of what I am doing if that is arduous to visualise:
Here is my code to this point (it is just a little messy, sorry about that):
public class SpriteAnimator : MonoBehaviour
{
float rotationX;
Animator animator;
Vector3 prevPos, velocity, relativeCamPos;
// Begin known as earlier than the primary body replace
void Begin()
{
animator = GetComponent<Animator>();
prevPos = remodel.place;
}
// Replace known as as soon as per body
void Replace()
{
remodel.ahead = Digital camera.essential.remodel.ahead; //Billboarding
rotationX = Mathf.Clamp(remodel.eulerAngles.x, 20f, 25f);
remodel.rotation = Quaternion.Euler(rotationX, remodel.eulerAngles.y, remodel.eulerAngles.z); //Clamp X axis rotation
Vector3 normalizedVelocity = GetVelocity();
relativeCamPos = Vector3.Normalize(remodel.place - Digital camera.essential.remodel.place); //Digital camera place relative to sprite
if (velocity != Vector3.zero)
{
animator.SetBool("IsMoving", true);
animator.SetFloat("Horizontal", normalizedVelocity.x);
animator.SetFloat("Vertical", normalizedVelocity.y);
}
else
{
animator.SetBool("IsMoving", false);
animator.SetFloat("Horizontal", -relativeCamPos.x);
animator.SetFloat("Vertical", relativeCamPos.z);
}
}
non-public Vector3 GetVelocity()
{
velocity = (remodel.place - prevPos) / Time.deltaTime;
prevPos = remodel.place;
var forwardDot = Vector3.Dot(remodel.ahead, velocity);
var rightDot = Vector3.Dot(remodel.proper, velocity);
Vector3 velocityVector = new Vector3(rightDot, forwardDot); //Calculate velocity of object, then pack into new Vector3
Vector3 normalizedVelocity = Vector3.Normalize(velocityVector);
return normalizedVelocity;
}
}
This works… 90% accurately.
Whereas the sprites are transferring, the animator makes use of their velocity to find out which “dealing with” they’re purported to have and shows the suitable animation.
Whereas the sprites are idling, the digital camera can orbit them and their rotation updates relying on the digital camera’s relative, normalized place such that the 2D sprites are all the time dealing with the identical course. Here is an illustration of how that is taking place within the BlendTree (mine this time): https://i.imgur.com/nNRTyGJ.png
The issue is that when the sprites have completed transferring, their dealing with resets to their “idle” dealing with, as a result of that is based mostly solely on the digital camera (relativeCamPos). What I would like is for his or her dealing with to be captured and maintained from the course they simply moved in, and for any additional actions from the digital camera to replace the sprite based mostly on that. For instance, if the sprite strikes west, the animator wants to grasp that that’s the new course I need the sprite to maintain dealing with when the digital camera rotates round it. At present, it would reset to a north course, as a result of that is my default.
I have been scratching my head at this for some time, as a result of the answer feels prefer it ought to be quite simple. Alas, I can not seem to get it working fairly proper. If anybody is aware of how I ought to go about this, or is aware of a greater resolution for doing this sort of factor totally, I am all ears! And naturally, I might be glad to supply any extra data if one thing is unclear.