avuthless
avuthless

Reputation: 996

Unity3D OffNavMesh jump issue

I have set up Unity navigation meshes (four planes), navigation agent (sphere) and set up automatic and manual off mesh links. It should now jump between meshes. It does jump between meshes, but it does that in straight lines.

In other words, when agent comes to an edge, instead of actually jumping up (like off mesh link is drawn) it just moves straight in line but a bit faster. I tried moving one plane higher than others, but sphere still was jumping in straight line.

Is it supposed to be like this? Is it possible to set up navigation to jump by some curve? Or should I try to implement that myself?

Upvotes: 3

Views: 12338

Answers (4)

Andre Oliveira
Andre Oliveira

Reputation: 29

Fix position in update()

if (agent.isOnOffMeshLink)
 {
    transform.position =  new Vector3(transform.position.x, 0f, transform.position.z);       
 }

Upvotes: 0

user2502703
user2502703

Reputation: 1

Not sure what version of unity you are using but you could also try this, I know it works just fine in 4:

string linkType = GetComponent<NavMeshAgent>().currentOffMeshLinkData.linkType.ToString();

if(linkType == "LinkTypeJumpAcross"){

        Debug.Log ("Yeah im in the jump already ;)");
}

also just some extra bumf for you, its best to use a proxy and follow the a navAgent game object:

Something like:

AIMan = this.transform.position; AI_Proxy.transform.position = AIMan;

And also be sure to use:

AI_Proxy.animation["ProxyJump"].blendMode = AnimationBlendMode.Additive;

If you are using the in built unity animation!

K, that's my good deed for this week.

Upvotes: 0

Matt Bond
Matt Bond

Reputation: 1422

I came by this question, and had to dig through the Unity sample. I just hope to make it easier for people by extracting the important bits.

To apply your own animation/transition across a navmesh link, you need to tell Unity that you will handle all offmesh link traversal, then add code that regularly checks to see if the agent is on an offmesh link. Finally, when the transition is complete, you need to tell Unity you've moved the agent, and resume normal navmesh behaviour.

The way you handle link logic is up to you. You can just go in a straight line, have a spinning wormhole, whatever. For jump, unity traverses the link using animation progress as the lerp argument, this works pretty nicely. (if you're doing looping or more complex animations, this doesn't work so well)

The important unity bits are:

_navAgent.autoTraverseOffMeshLink = false; //in Start()
_navAgent.currentOffMeshLinkData; //the link data - this contains start and end points, etc
_navAgent.CompleteOffMeshLink(); //Tell unity we have traversed the link (do this when you've moved the transform to the end point)
_navAgent.Resume(); //Resume normal navmesh behaviour

Now a simple jump sample...

using UnityEngine;

[RequireComponent(typeof(NavMeshAgent))]
public class NavMeshAnimator : MonoBehaviour
{
    private NavMeshAgent _navAgent;
    private bool _traversingLink;
    private OffMeshLinkData _currLink;

    void Start()
    {
        // Cache the nav agent and tell unity we will handle link traversal
        _navAgent = GetComponent<NavMeshAgent>();
        _navAgent.autoTraverseOffMeshLink = false;
    }

    void Update()
    {
        //don't do anything if the navagent is disabled
        if (!_navAgent.enabled) return;

        if (_navAgent.isOnOffMeshLink)
        {
            if (!_traversingLink)
            {
                //This is done only once. The animation's progress will determine link traversal.
                animation.CrossFade("Jump", 0.1f, PlayMode.StopAll);
                //cache current link
                _currLink = _navAgent.currentOffMeshLinkData;
                //start traversing
                _traversingLink = true;
            }

            //lerp from link start to link end in time to animation
            var tlerp = animation["Jump"].normalizedTime;
            //straight line from startlink to endlink
            var newPos = Vector3.Lerp(_currLink.startPos, _currLink.endPos, tlerp);
            //add the 'hop'
            newPos.y += 2f * Mathf.Sin(Mathf.PI * tlerp);
            //Update transform position
            transform.position = newPos;

            // when the animation is stopped, we've reached the other side. Don't use looping animations with this control setup
            if (!animation.isPlaying)
            {
                //make sure the player is right on the end link
                transform.position = _currLink.endPos;
                //internal logic reset
                _traversingLink = false;
                //Tell unity we have traversed the link
                _navAgent.CompleteOffMeshLink();
                //Resume normal navmesh behaviour
                _navAgent.Resume();
            }
        }
        else
        {
            //...update walk/idle animations appropriately ...etc

Upvotes: 13

TJHeuvel
TJHeuvel

Reputation: 12618

Its recommended to solve your problems via animation. Just create a Jump animation for your object, and play it at the correct time. The position is relative, so if you increase the Y-position in your animation it will look like the object is jumping.

This is also how the Unity sample is working, with the soldiers running around.

Upvotes: 2

Related Questions