I’ve a sport wherein 2D sprites (on planes) are positioned right into a 3D setting. The aircraft GameObjects displaying every sprite billboard towards the digicam 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 considered one of two issues: their velocity and the digicam’s place relative to them. The latter is essential as a result of within the sport the digicam 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.
This is an illustration (not mine) of what I am doing if that is arduous to visualise:
This is my code to date (it is a little bit 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 = rework.place;
}
// Replace known as as soon as per body
void Replace()
{
rework.ahead = Digicam.most important.rework.ahead; //Billboarding
rotationX = Mathf.Clamp(rework.eulerAngles.x, 20f, 25f);
rework.rotation = Quaternion.Euler(rotationX, rework.eulerAngles.y, rework.eulerAngles.z); //Clamp X axis rotation
Vector3 normalizedVelocity = GetVelocity();
relativeCamPos = Vector3.Normalize(rework.place - Digicam.most important.rework.place); //Digicam 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);
}
}
personal Vector3 GetVelocity()
{
velocity = (rework.place - prevPos) / Time.deltaTime;
prevPos = rework.place;
var forwardDot = Vector3.Dot(rework.ahead, velocity);
var rightDot = Vector3.Dot(rework.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 shifting, the animator makes use of their velocity to find out which “dealing with” they’re speculated to have and shows the suitable animation.
Whereas the sprites are idling, the digicam can orbit them and their rotation updates relying on the digicam’s relative, normalized place such that the 2D sprites are at all times dealing with the identical course. This 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 after the sprites have completed shifting, their dealing with resets to their “idle” dealing with, as a result of that is primarily based solely on the digicam (relativeCamPos). What I want 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 digicam to replace the sprite primarily based 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 digicam rotates round it. At present, it is going to 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 needs 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 type of factor totally, I am all ears! And naturally, I would be glad to supply any extra info if one thing is unclear.