Unity Enemy Patrol 3D Tutorial | Unity Tutorial
In this Unity tutorial, we’ll walk you through creating a 3D enemy patrol system from scratch. Learn how to set up an enemy that follows waypoints, waits at specific points, and handles ground detection. We'll cover scripting with C# to control enemy movement, implement ground checks using LayerMasks, and refine patrol behavior to avoid common issues like jittering.
WATCH FULL TUTORIAL ON YOUTUBE
=========================================================
Unity Projects - ON SALE!!!
1. Water Sort Puzzle 9000 Levels
2. Ball Sort Puzzle 9000 Levels
3. Sling Shot
=========================================================
Scripts:
EnemyPatrol.cs
using UnityEngine;
using System.Collections;
public class EnemyPatrol : MonoBehaviour
{
public Transform[] waypoints; // Array of waypoints
public float speed = 2f; // Patrol speed
public float waitTime = 2f; // Time to wait at each waypoint
public float groundCheckDistance = 0.2f; // Distance to check for ground
public LayerMask groundLayer; // Layer mask to specify ground layers
private int currentWaypointIndex = 0;
private Rigidbody rb;
private bool isWaiting = false;
private bool isGrounded;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true; // Prevent rotation
rb.useGravity = true; // Enable gravity
if (waypoints.Length > 0)
{
StartCoroutine(Patrol());
}
}
void FixedUpdate()
{
// Check if the enemy is grounded using the LayerMask
isGrounded = Physics.Raycast(transform.position, Vector3.down, groundCheckDistance, groundLayer);
// Apply manual adjustment to prevent unrealistic behavior
if (!isGrounded)
{
Vector3 adjustedVelocity = rb.velocity;
adjustedVelocity.y = 0; // Prevent vertical movement
rb.velocity = adjustedVelocity;
}
}
private IEnumerator Patrol()
{
while (true) // Infinite loop for continuous patrolling
{
if (waypoints.Length == 0) yield break;
Transform targetWaypoint = waypoints[currentWaypointIndex];
Vector3 direction = (targetWaypoint.position - transform.position).normalized;
// Move the enemy manually
Vector3 movement = direction * speed * Time.fixedDeltaTime;
rb.velocity = Vector3.zero; // Reset velocity before applying movement
rb.MovePosition(rb.position + movement);
// Check if we've reached the waypoint
if (Vector3.Distance(transform.position, targetWaypoint.position) < 0.1f)
{
if (!isWaiting)
{
StartCoroutine(WaitAtWaypoint());
}
}
yield return new WaitForFixedUpdate(); // Wait until the next FixedUpdate
}
}
private IEnumerator WaitAtWaypoint()
{
isWaiting = true;
yield return new WaitForSeconds(waitTime); // Wait for the specified time
isWaiting = false;
// Move to the next waypoint
currentWaypointIndex = (currentWaypointIndex + 1) % waypoints.Length;
}
}