Search Unity

Nav Mesh Agent move to a random point closer to the player or zig zag towards player

Discussion in 'Scripting' started by Thrazamund, Aug 9, 2020.

  1. Thrazamund

    Thrazamund

    Joined:
    Apr 14, 2017
    Posts:
    36
    Hello all,

    I've been stuck on this and am hoping someone can point me in the right direction. I have a Nav Mesh Agent enemy and the player. Ideally I'd like to have the enemy zig or zag at random towards the player and occasionally take potshots while doing that. Like the zombie men from original Doom. I have the enemy attacking at random intervals and moving towards the player but the zig or zag movement is difficult as the player will constantly be moving and the enemy has to find a valid point on the Nav Mesh closer to the player.

    I've done some very dirty solutions like putting empty gameobjects on all 4 sides of the player and trying to calculate which are currently on either side of the player relative to the approaching enemy and then move towards one. This is a bad solution though besides being messy if the point is too close to the player the enemy barely moves off the straight path and if it's too far it can be off the Nav Mesh entirely as my game has tight hallways.

    If the zig or zag can't be done is there at least a way to have the enemy find a random point in the Nav Mesh that is closer to the player than the previous point? Any insight would be appreciated.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    I have used this approach for other reasons, but here is one idea:

    Instead of having the actual baddie run at the player, make a new GameObject (invisible) that has the NavMeshAgent on it, and make that agent charge the player.

    Then your actual baddie would once a second or so choose a new destination near the moving / charging invisible GameObject as his location to run towards, all the while continuing to aggro on the player.

    If you also prevent the invisible guy from getting too far ahead of the actual guy (set his speed to zero if his distance to player is too much less than the other guy's distance to player), this will probably result in a rather interesting zig-and-zag duck and dodge kinda movement.
     
  3. Thrazamund

    Thrazamund

    Joined:
    Apr 14, 2017
    Posts:
    36
    That's a very interesting idea. I will try it out because it's hard for me to visualize the result.

    I've managed to get something that moves towards the player randomly but it is isn't pretty. This creates an almost spider like randomness to the movement. I'd like something closer to the pursuing zig zag. I measure the distance to the player, find a position in a random radius, if the new position is closer to the player than my current position then go to that position. If not find another one.
    Code (CSharp):
    1.     private void MoveToNewDestination()
    2.     {
    3.         float distanceToPlayer = Vector3.Distance(transform.position, PlayerController.instance.transform.position);
    4.  
    5.         float randRadius = UnityEngine.Random.Range(moveRadiusMin, moveRadiusMax);
    6.  
    7.         Vector3 randDir = UnityEngine.Random.insideUnitSphere * randRadius;
    8.         randDir += transform.position;
    9.  
    10.         NavMeshHit navHit;
    11.         NavMesh.SamplePosition(randDir, out navHit, randRadius, -1);
    12.  
    13.         while (Vector3.Distance(navHit.position, PlayerController.instance.transform.position) > distanceToPlayer)
    14.         {
    15.             distanceToPlayer = Vector3.Distance(transform.position, PlayerController.instance.transform.position);
    16.  
    17.             randRadius = UnityEngine.Random.Range(moveRadiusMin, moveRadiusMax);
    18.  
    19.             randDir = UnityEngine.Random.insideUnitSphere * randRadius;
    20.             randDir += transform.position;
    21.  
    22.             NavMesh.SamplePosition(randDir, out navHit, randRadius, -1);
    23.         }
    24.         positionToMoveTo = navHit.position;
    25.         navAgent.SetDestination(navHit.position);
    26.     }
    I've also thought about using the enemy's transform.forward and NavMeshAgent.Move. If the enemy turns to face the player then I use something like move transform.forward * transform.right * speed maybe that could work. I wish I had paid more attention in math class. Any other thoughts are appreciated.
     
  4. Thrazamund

    Thrazamund

    Joined:
    Apr 14, 2017
    Posts:
    36
    Working on this at the moment. How do you handle Nav Mesh Agents colliding with their invisible brother? I've looked into setting the invisible one's collider radius to very small but that will still cause the real Nav Mesh Agent to avoid getting to that destination it will also cause problems if I want them on top of another. Is there a way to make my real Nav Mesh Agent ignore collisions with the invisble counterpart specifically and not all other Nav Mesh Agents?
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Interesting... I did not encounter this because my specific use case was for a minion to be near-ish me and yet aggro-ish march towards enemies a ways, so I didn't mind him not hitting me or not hitting his inviso-brother.

    One way might be to disable the inviso-brother when he arrives at his destination, then wake him up again when you want a new spot to jink over to... it does get a bit fiddly, doesn't it?? :)