Cheapest way to find cover?

  • A* version: 5.3.8
  • Unity version: 22.3.62

What’s a better way to find cover on a recast navmesh?
I have this and it seems sub optimal.

	bool SetDestination_Cover()
	{
		// Search for a cover where the enemy has no line of sight.
		var   possibleCovers = new List<Vector3>();
		float searchRadius   = 3.0f;
		int   n              = 20; // Maxiumum number of candidate cover points.
		int   s              = 10; // Number of sample per circle
		bool  isSet          = false;
		var   attacker       = self.shotBy!=null ? self.shotBy : self.target;
		if(attacker) {
			// Sample random cover points on an increasing circle.
			var src              = attacker.HeadPosition; //transform.position;
			var pos              = transform.position;
			var ignoredColliders = attacker.colliders.Union(self.colliders);
			while (possibleCovers.Count<n) {
				for (int i = 0;i<s;i++) {
					float a   = Random.value*Mathf.PI*2.0f;
					var   dst = pos+new Vector3(Mathf.Cos(a),0.0f,Mathf.Sin(a))*searchRadius;
					// check LOS from attacker to random position
					if(!self.HasLOS(src,dst,ignoredColliders)) possibleCovers.Add(dst);
				}
				searchRadius += 3.0f;
			}
			// Search the closest cover point
			UnityEngine.AI.NavMeshPath selfPath     = new UnityEngine.AI.NavMeshPath();
			UnityEngine.AI.NavMeshPath attackerPath = new UnityEngine.AI.NavMeshPath();
			Vector3                    closest      = pos;
			float                      minD         = float.PositiveInfinity;
			foreach (var p in possibleCovers) {
				if(UnityEngine.AI.NavMesh.CalculatePath(agent.transform.position,p,new NavMeshQueryFilter() { agentTypeID = agent.agentTypeID,areaMask = agent.areaMask }
						,selfPath)
					&& selfPath.status==UnityEngine.AI.NavMeshPathStatus.PathComplete) {
					// if ( agent.CalculatePath(p, selfPath) && selfPath.status == NavMeshPathStatus.PathComplete) {
					float attackerDistance = 0.0f;
					if(attacker!=null && attacker.TryGetComponent<UnityEngine.AI.NavMeshAgent>(out var attackerAgent) && attackerAgent.CalculatePath(p,attackerPath))
						attackerDistance = PathLength(attackerPath);
					float d = PathLength(selfPath)-attackerDistance*0.1f;
					if(d<minD) {
						minD = d;
						closest = p;
					}
				}
			}
			SetDestination(closest);
			isSet = true;
		}
		return isSet;
	}

so I turned it into that but it doesn’t seem super efficient either (pasting breaks formatting so here is a screencap).

Per my opinion, this is a tricky task in general. I think if what you have works and isn’t causing performance issues visible in the Profiler, I’d leave it as is. However I will drop this related reading, as I was browsing the documentation for more ideas on this and was figuring this could be useful, but honestly only if the agent can’t be seen at all in a stealth-like situation.

There’s also this thread with a suggestion from Aron:

And

These may give some ideas?

1 Like

I batched the LOS tests in a raycastcommand and the thing disappeared from the profiler.