Search Unity

Question OffMeshLinks and Path Recalculation on link cost change for multiple agent

Discussion in 'Navigation' started by Pierre-Marie, Jan 4, 2024.

  1. Pierre-Marie

    Pierre-Marie

    Joined:
    Aug 3, 2015
    Posts:
    52
    Hi,

    I wanted to share an issue I encountered while working with Unity's NavMesh and OffMeshLinks and propose a solution that I found. I hope you could provide me a better solution.

    I have a game where agents are using OffMeshLinks to teleport. Each OffMeshLink can be used by only one agent at a time. So I add several offmeshlink for each teleporter. Every time en Entity us a link, I change the value off the link hopping that Unity will recalculate the path of the other unit that were planning to use this link.

    This doesn't seem to work and other unit were still trying to use the same link.
    I don't know if it's suppose to work that way, or if it's a bug.

    Every agent are autoRepath and auto Traverse offMeshLink.
    So I came with that solution :


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.AI;
    5.  
    6. /// <summary>
    7. /// Quand un agent utilise un teleporter, il utilise un navmeshlink, pendant toute al durée du trajet.
    8. /// Les autres qui voulaient utiliser ce link doivent alors attendre, en augmentant significativement le poids du lien
    9. /// quand il est utilisé, on change le poids du chemin et on force le recalcul d'un chemin qui va préférer des liens moins chère/// </summary>
    10. public class OffMeshLinkEntityUse : MonoBehaviour
    11. {
    12.    
    13.     private NavMeshAgent agent;
    14.     private OffMeshLink link;
    15.     private float oldLinkCost;
    16.  
    17.     private OffMeshLink currentOffMeshLink; // Variable pour suivre le OffMeshLink actuel
    18.     private bool hasStartedOffMeshLink; // Variable pour indiquer si l'agent a déjà commencé à utiliser un OffMeshLink
    19.     private OffMeshLinkData previousOffMeshLinkData;
    20.  
    21.     float lastLinkCost = 0f;
    22.     void Start()
    23.     {
    24.         agent = GetComponent<NavMeshAgent>();
    25.         if (agent != null) agent.updatePosition = true; // Assurez-vous que l'agent met à jour sa position.
    26.         link = null;
    27.         previousOffMeshLinkData = agent.nextOffMeshLinkData;
    28.     }
    29.  
    30.  
    31.     void AcquireOffmeshLink()
    32.     {
    33.         if (link == null)
    34.         {
    35.             link = agent.currentOffMeshLinkData.offMeshLink;
    36.             oldLinkCost = link.costOverride;
    37.             link.costOverride = 1000.0f;
    38.             Debug.Log(link.gameObject.name + " new cost : " + agent.currentOffMeshLinkData.offMeshLink.costOverride);
    39.             //          link.activated = false;
    40.  
    41.             Debug.Log(this.gameObject.name + "Acquire off mesh link :" + link.gameObject.name);
    42.         }
    43.     }
    44.  
    45.     void ReleaseOffmeshLink()
    46.     {
    47.         if (link != null)
    48.         {
    49.             link.costOverride = oldLinkCost;
    50.            
    51.             //          link.activated = true;
    52.             Debug.Log(this.gameObject.name + "Release off mesh link :" + link.gameObject.name);
    53.             link = null;
    54.         }
    55.     }
    56.  
    57.     void OnDestroy()
    58.     {
    59.         // Remember to release the link when the agent is killed/etc.
    60.         ReleaseOffmeshLink();
    61.     }
    62.  
    63.     void Update()
    64.     {
    65.         if (agent.nextOffMeshLinkData.offMeshLink != previousOffMeshLinkData.offMeshLink)
    66.         {
    67.             // agent.nextOffMeshLinkData a changé, l'agent est sur le point de passer à un nouveau OffMeshLink
    68.             Debug.Log("L'agent" + this.gameObject.name + " a un nouveau OffMeshLink dans son chemin. : (" + previousOffMeshLinkData.offMeshLink + ") ==> (" + agent.nextOffMeshLinkData.offMeshLink + ")");
    69.         }
    70.        
    71.  
    72.         if (agent.currentOffMeshLinkData.valid)
    73.         {
    74.             AcquireOffmeshLink();
    75.         }
    76.         else
    77.         {
    78.             ReleaseOffmeshLink();
    79.             float nextLinkCost = 0f;
    80.            
    81.             if (agent.nextOffMeshLinkData.valid) nextLinkCost = agent.nextOffMeshLinkData.offMeshLink.costOverride;
    82.            
    83.             if (nextLinkCost != lastLinkCost)
    84.             {
    85.                 agent.SetDestination(agent.destination);
    86.                 Debug.Log(this.gameObject.name + " recalculating path due to link cost change");
    87.             }
    88.         }
    89.         previousOffMeshLinkData = agent.nextOffMeshLinkData; // Mettez à jour la valeur précédente
    90.         if (agent.nextOffMeshLinkData.valid) lastLinkCost = agent.nextOffMeshLinkData.offMeshLink.costOverride;
    91.     }
    92.  
    93. }
    94.  
    this script is attached to every unit that can use a teleporter.

    I hope this helps anyone facing a similar challenge. If you have any questions or suggestions for improvement, please feel free to share them.

    Thanks for your time.