- Home /
Root motion handled by script. How to still use root motion with disabled navmesh agent?
I have this script from one of Unity's tutorials with locomotion for mecanim. Everything works fine and Mecanim is working with NavMeshAgent. The thing is I would like to disable NavMeshAgent from time to time and still use root motion (for example when a character want to sit down on a chair that is an obstacle or it's baked into navmesh).
At this moment, when I disable NavMeshAgent component my animations are played without root motion. Root motion is automatically set to "handled by script" and it just won't use root motion when the NavMeshAgent is disabled.
Do you have an idea how to modify this script so I will still get the root motion from animations even if the NavMeshAgent is disabled?
using UnityEngine;
using System.Collections;
public class Agent : MonoBehaviour {
public GameObject particle;
protected NavMeshAgent agent;
protected Animator animator;
protected Locomotion locomotion;
protected Object particleClone;
// Use this for initialization
void Start () {
agent = GetComponent<NavMeshAgent>();
agent.updateRotation = false;
animator = GetComponent<Animator>();
locomotion = new Locomotion(animator);
particleClone = null;
}
protected void SetDestination()
{
// Construct a ray from the current mouse coordinates
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit = new RaycastHit();
if (Physics.Raycast(ray, out hit))
{
if (particleClone != null)
{
GameObject.Destroy(particleClone);
particleClone = null;
}
// Create a particle if hit
Quaternion q = new Quaternion();
q.SetLookRotation(hit.normal, Vector3.forward);
particleClone = Instantiate(particle, hit.point, q);
agent.destination = hit.point;
}
}
protected void SetupAgentLocomotion()
{
if (AgentDone())
{
locomotion.Do(0, 0);
if (particleClone != null)
{
GameObject.Destroy(particleClone);
particleClone = null;
}
}
else
{
float speed = agent.desiredVelocity.magnitude;
Vector3 velocity = Quaternion.Inverse(transform.rotation) * agent.desiredVelocity;
float angle = Mathf.Atan2(velocity.x, velocity.z) * 180.0f / 3.14159f;
locomotion.Do(speed, angle);
}
}
void OnAnimatorMove()
{
agent.velocity = animator.deltaPosition / Time.deltaTime;
transform.rotation = animator.rootRotation;
}
protected bool AgentDone()
{
return !agent.pathPending && AgentStopping();
}
protected bool AgentStopping()
{
return agent.remainingDistance <= agent.stoppingDistance;
}
// Update is called once per frame
void Update ()
{
if (Input.GetButtonDown ("Fire1"))
SetDestination();
SetupAgentLocomotion();
}
}
I've used some temporary workaround (but I don't know if I would be using it in the future) by adding 'offline' bool to the script and not doing some things in the script when this bool is true. When I need to disable Nav$$anonymous$$eshAgent and use root motion from animator I set this bool to true and disable Nav$$anonymous$$eshAgent. I don't know if its clean way of doing that anyway. I'm using different script than the one provided in the question btw.
Did you found any other solution?
using UnityEngine;
using System.Collections;
public class Agent2 : $$anonymous$$onoBehaviour {
protected Nav$$anonymous$$eshAgent agent;
protected Animator animator;
public bool offline = false;
protected Locomotion locomotion;
// Use this for initialization
void Start () {
agent = GetComponent<Nav$$anonymous$$eshAgent>();
agent.updateRotation = false;
agent.updatePosition = true;
animator = GetComponent<Animator>();
locomotion = new Locomotion(animator);
}
protected void SetupAgentLocomotion()
{
if (AgentDone())
{
locomotion.Do(0, 0);
}
else
{
float speed = agent.desiredVelocity.magnitude;
Vector3 velocity = Quaternion.Inverse(transform.rotation) * agent.desiredVelocity;
float angle = $$anonymous$$athf.Atan2(velocity.x, velocity.z) * 180.0f / 3.14159f;
locomotion.Do(speed, angle);
}
}
void OnAnimator$$anonymous$$ove()
{
agent.velocity = animator.deltaPosition / Time.deltaTime;
transform.rotation = animator.rootRotation;
if (offline == true){
transform.position = animator.rootPosition;
}
}
public bool AgentDone()
{
if (offline == false){
return !agent.pathPending && AgentStopping();
}
else {
return true;
}
}
public bool AgentStopping()
{
if (offline == false){
return agent.remainingDistance <= agent.stoppingDistance;
}
else {
return false;
}
}
// Update is called once per frame
void Update ()
{
if (offline == false){
SetupAgentLocomotion();
}
}
public void SetOffline()
{
offline = true;
}
public void SetOnline()
{
offline = false;
}
}