using UnityEngine;
/// <summary>
/// GAME 1303 Tier 2 — Walks back and forth. Turns at walls, ledges, or waypoints.
///
/// SETUP
/// 1. Enemy root: Sprite + Rigidbody2D (Freeze Rotation Z) + Collider2D + Health +
/// this script. Tag "Enemy". Add a Hurtbox child (Team = Enemy) so the player can hit it,
/// and either a Hitbox child (always on, Target Team = Player, Repeat Delay 1) or a
/// DamageOnContact so it hurts the player on touch.
/// 2. Turn mode:
/// Sensors – flips when the Wall Check hits Ground Layer or the Ledge Check finds
/// no ground ahead. Create two empty children: "WallCheck" (in front, at
/// knee height) and "LedgeCheck" (in front, below the feet).
/// Waypoints – walks between two Transforms (drag them out of the enemy so they
/// don't move with it).
/// 3. Optional: drag in a PlayerAnimatorBridge on the same object and it drives Speed.
///
/// EnemyChase can sit on the same object and take over when the player is near;
/// it pauses this script while chasing.
/// </summary>
[RequireComponent(typeof(Rigidbody2D))]
public class EnemyPatrol : MonoBehaviour
{
public enum TurnMode { Sensors, Waypoints }
public float speed = 2f;
public TurnMode turnMode = TurnMode.Sensors;
[Tooltip("Pause at each turn.")]
public float pauseAtTurn = 0.3f;
[Tooltip("Sprite faces right by default? Untick if your art faces left.")]
public bool artFacesRight = true;
[Header("Sensors mode")]
public Transform wallCheck;
public Transform ledgeCheck;
public float checkDistance = 0.15f;
public LayerMask groundLayer;
[Header("Waypoints mode")]
public Transform pointA;
public Transform pointB;
public bool FacingRight { get; private set; } = true;
/// <summary>EnemyChase sets this false while chasing.</summary>
public bool Active { get; set; } = true;
private Rigidbody2D rb;
private Knockback knockback;
private PlayerAnimatorBridge animBridge;
private Transform currentTarget;
private float pauseTimer;
void Awake()
{
rb = GetComponent<Rigidbody2D>();
knockback = GetComponent<Knockback>();
animBridge = GetComponent<PlayerAnimatorBridge>();
currentTarget = pointB;
FacingRight = artFacesRight ? transform.localScale.x > 0 : transform.localScale.x < 0;
}
void FixedUpdate()
{
if (!Active || (knockback != null && knockback.IsStunned))
{
animBridge?.SetSpeed(0f);
return;
}
if (pauseTimer > 0f)
{
pauseTimer -= Time.fixedDeltaTime;
rb.linearVelocity = new Vector2(0f, rb.linearVelocity.y);
animBridge?.SetSpeed(0f);
return;
}
if (turnMode == TurnMode.Sensors) SensorPatrol();
else WaypointPatrol();
animBridge?.SetSpeed(rb.linearVelocity.x);
}
void SensorPatrol()
{
float dir = FacingRight ? 1f : -1f;
bool wallAhead = wallCheck != null &&
Physics2D.Raycast(wallCheck.position, Vector2.right * dir, checkDistance, groundLayer);
bool groundAhead = ledgeCheck == null ||
Physics2D.Raycast(ledgeCheck.position, Vector2.down, checkDistance * 3f, groundLayer);
if (wallAhead || !groundAhead) { Flip(); return; }
rb.linearVelocity = new Vector2(dir * speed, rb.linearVelocity.y);
}
void WaypointPatrol()
{
if (pointA == null || pointB == null) return;
float dx = currentTarget.position.x - transform.position.x;
if (Mathf.Abs(dx) < 0.1f)
{
currentTarget = currentTarget == pointA ? pointB : pointA;
pauseTimer = pauseAtTurn;
return;
}
float dir = Mathf.Sign(dx);
if ((dir > 0) != FacingRight) Flip();
rb.linearVelocity = new Vector2(dir * speed, rb.linearVelocity.y);
}
public void Flip()
{
FacingRight = !FacingRight;
Vector3 s = transform.localScale;
s.x *= -1f;
transform.localScale = s;
pauseTimer = pauseAtTurn;
}
/// <summary>Face a world position (EnemyChase uses this).</summary>
public void FaceToward(float worldX)
{
bool shouldFaceRight = worldX > transform.position.x;
if (shouldFaceRight != FacingRight) { Flip(); pauseTimer = 0f; }
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
float dir = Application.isPlaying ? (FacingRight ? 1 : -1) : 1;
if (wallCheck) Gizmos.DrawLine(wallCheck.position, wallCheck.position + Vector3.right * dir * checkDistance);
if (ledgeCheck) Gizmos.DrawLine(ledgeCheck.position, ledgeCheck.position + Vector3.down * checkDistance * 3f);
if (pointA && pointB) { Gizmos.color = Color.yellow; Gizmos.DrawLine(pointA.position, pointB.position); }
}
}