I'm messing around in Unity trying to create a script for a physics based arrow.
I have it arcing properly, but it's still straight up throughout it's flight.
I'm trying to use Quaternion.LookRotation
to change it's rotation based on the velocity (R = 0 at V = Vinitial, R = 90 at V = 0, and R = 180 at V = -Vinitial)
but I haven't been able to puzzle out what formula I would use.
Any help would be appreciated.
EDIT
With help from the responses, I was able to get it working as I intended. Incase anyone stumbles across this looking for help, my end code looked like this:
private void Update()
{
if (ForceSet)
{
ForceSet = false;
initialVelocity = rb.velocity;
EndAngleOffset = .33f * rb.velocity.y;
}
if (stuckTarget == null)
{
Vector3 Forward;
Vector3 Upward;
if (rb.velocity.y > 0)
{
Forward = new Vector3(rb.velocity.x, -((-initialVelocity.y + rb.velocity.y - EndAngleOffset) * (-initialVelocity.y + rb.velocity.y - EndAngleOffset)), rb.velocity.z);
Upward = new Vector3(0, 1, 0);
}
else
{
Forward = new Vector3(rb.velocity.x, ((initialVelocity.y + rb.velocity.y + EndAngleOffset) * (initialVelocity.y + rb.velocity.y + EndAngleOffset)), rb.velocity.z);
Upward = new Vector3(0, -1, 0);
}
rb.rotation = Quaternion.LookRotation(Forward, Upward);
}
(ForceSet is set equal to true the when applying the launching force to the 'Arrow')
If you have access to the arrows Rigidbody
component, you can access it's velocity
property and set its rotation
to be equal to its velocity
.
I recommend when making modifications to a Rigidbody
's transform that you use the Rigidbody
methods. This ensures that values are properly updated with Unity's physics system.
using UnityEngine;
public class ArrowBehaviour : MonoBehaviour
{
private Rigidbody rigidbody;
private void Awake()
{
rigidbody = GetComponent<Rigidbody>();
}
private void Update()
{
rigidbody.rotation = Quaternion.LookRotation(rigidbody.velocity, Vector3.up);
}
}
Depending on the circumstances, you might want to change Update
to FixedUpdate
.
EDIT:
There was a bug in the above code I fixed; that's what you get when you write it at 2am. I'd give it another go and see if that works for you.
In an ideal world, you would pre-compute the path of the arrow so that you could perform any procedural animation to the arrow you would like.
You could also calculate an X rotation to use instead, which will fake the effect.
using UnityEngine;
public class ArrowBehaviour : MonoBehaviour
{
[SerializeField] private float lookMagnitude = 45.0f;
[SerializeField] private float velocitySensitivity;
private Rigidbody rigidbody;
private void Awake()
{
rigidbody = GetComponent<Rigidbody>();
}
private void Update()
{
// Determine how much we want to fake the rotation by.
var lookStrength = Mathf.InverseLerp(-velocitySensitivity, velocitySensitivity, rigidbody.velocity)
var targetEulerAngles = new Vector3(
Mathf.Lerp(-lookMagnitude, lookMagnitude, lookStrength),
transform.localEulerAngles.y,
transform.localEulerAngles.z
);
// Rotate the transform
transform.localEulerAngles = targetEulerAngles;
// Alternatively, interpolate to the target angle.
/* transform.localEulerAngles = Vector3.Lerp(
* transform.localEulerAngles,
* targetEulerAngles,
* Time.deltaTime * rotationSpeed
* );
*/
}
}