0
\$\begingroup\$

I have been looking everywhere for a patrolling/wandering code/system for my slender-esque game. However, I am having trouble finding anything or even implementing anything and haven't been able to find answers anywhere (potentially due to not asking the right questions online).

I did originally find one script that somewhat worked but it kind of broke on me (it would not switch out of the "wandering" state after a few edits that I made to it).

My question is what would be the recommended code to input?

here is my code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class StalkerAI : MonoBehaviour
{

   public playerinventory Playerinventory; //for difficulty scaling

public NavMeshAgent agent;
public Transform Player;

public float walk; //speed for enemy to go
public float run;

void Start()
{
    agent = GetComponent<NavMeshAgent>();

    walk = 3 + Playerinventory.NumbOfClues;
    run = 5 + Playerinventory.NumbOfClues;
}
// Update is called once per frame
void Update()
{
    float distValC = 5.0f;
    float dist = Vector3.Distance(agent.transform.position, Player.position);

    if (dist <= distValC)
    {
        agent.speed = run;
        agent.SetDestination(Player.position);
    }
    else
    {
        agent.speed = walk;
        agent.SetDestination(agent.transform.position);

    }
}

}

\$\endgroup\$
2
  • \$\begingroup\$ Is your agent in the current script even moving when the player is far away? Do you want to have it patrol between different waypoints? To me your code reads like: Chase player when close enough else do nothing. \$\endgroup\$
    – Zibelas
    Commented Nov 28, 2022 at 8:12
  • \$\begingroup\$ Well, that "else don't move" code is a placeholder for what I want to do, which is "wander throughout the maze that is my scene". I don't want a patrol per-say more of a wander, but if there is a way of randomizing which waypoint they start to head toward it would definitely work for the vibe I want to implement (discount slender man minus the teleportation). \$\endgroup\$
    – mg_pheonix
    Commented Nov 28, 2022 at 19:33

1 Answer 1

0
\$\begingroup\$

It depends a lot on what you want the wandering to look like. You could start with a simple wandering AI and than iterate to make it feel more natural and improve gameplay. There are many ways to do this. You could start with following approach.

Define States

There are two states, Wandering and Hunting. For Wandering state, which is the default state:

  • Define an array of waypoint marker objects (which are just transforms)
  • Set the agent's destination to the first marker
  • When the agent has reached it's destination, wait for a random amount of seconds, before setting the destination to the next waypoint
  • Once the last marker was reached, start over with the first (for a circle) or go backwards the same way you came

If the player is in sight switch to Hunting state, as long as the player is within a certain radius (should be bigger than distValC, because now the enemy is already focused on the player). For the Hunting state the code in your if-branch seems fine, unless you also want to add attacks etc.

The code could look something like this:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class Enemy : MonoBehaviour
{
    public int numbOfClues; //for difficulty scaling

    [HideInInspector]
    public NavMeshAgent agent;

    public Transform Player;

    public float walk; //speed for enemy to go
    public float run;

    public Transform[] waypointMarkers;

    int waypointIndex = 0;
    float waypointWaitTime = 0.0f;
    bool isHunting = false;
    public float gainSightDistance = 12.0f;
    public float loseSightDistance = 18.0f;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();

        walk = 3 + numbOfClues;
        run = 5 + numbOfClues;
    }

    void Update()
    {
        if (isHunting)
        {
            Hunt();
        }
        else
        {
            Wander();
        }
    }

    void Hunt()
    {
        float dist = Vector3.Distance(agent.transform.position, Player.position);

        // hunting state's exit condition
        if (dist > loseSightDistance)
        {
            // If player is out too far, enter wandering state ...
            isHunting = false;
            // ... but first wait a few seconds before
            waypointWaitTime = Random.Range(2.0f, 4.0f);
            agent.speed = 0.0f;
            return;
        }

        agent.speed = run;
        agent.SetDestination(Player.position);

    }

    void Wander()
    {
        float dist = Vector3.Distance(agent.transform.position, Player.position);

        // wandering state's exit condition
        if (dist <= gainSightDistance)
        {
            // enter hunting state
            isHunting = true;
            return;
        }

        if (agent.remainingDistance < agent.stoppingDistance)
        {
            // When destination is reached,
            waypointIndex = (waypointIndex + 1) % waypointMarkers.Length;
            agent.SetDestination(waypointMarkers[waypointIndex].position);
            // Set a random wait time from 3 to 7 seconds and stop agent movement
            waypointWaitTime = Random.Range(2.0f, 4.0f);
            agent.speed = 0.0f;
        }
        else
        {
            if (waypointWaitTime > 0.0f)
            {
                // Reduce countdoun until 0 ...
                waypointWaitTime -= Time.deltaTime;
            }
            else
            {
                // ... then walk towards the next waypoint marker
                agent.speed = walk;
                agent.SetDestination(waypointMarkers[waypointIndex].position);
            }
        }
    }
}

Note: numbOfClues is here just a simple int that doesn't change. You will need to replace it with the actual value. I also changed some of your variable's names, to make clearer what they are. Also, make sure that the waypoints are actually reachable. This might not be the case, if the height difference between your agent and the marker is too big. So the marker and the agent should be on the same height and your agent's stopping distance should be slightly above 0.

Line of Sight

Additionally you could check, whether the player is actually being seen by the enemy by using a raycast to check whether the line of sight is blocked and limiting the angle of the enemy's view (i.e. set a max angle between the direction the enemy is facing and the direction from enemy to player). Then only go into Hunting state, if the enemy sees the player.

Further ideas

You could define a set of markers and then, once the current destination is reached, choose the next destination randomly from this set. You could also completely randomize the destination, so that a random position on the map ist picked. But this will give you less control. Alternatively you could pick a random position within a certain radius of the enemy's current position.

\$\endgroup\$
1
  • \$\begingroup\$ I edited my answer and fixed all errors. I also tested it and it is working. The problem was, that after reaching a waypoint I forgot to set the agent's destination to the new waypoint (I only changed the waypointIndex variable). I also rearranged the code to make it easier to read. \$\endgroup\$ Commented Dec 2, 2022 at 18:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .