using System.Collections; using System.Collections.Generic; using UnityEngine; public class Unit : MonoBehaviour { public enum Team { Player, Enemy } public Team team; public bool isTaggedOut; public bool hasFlag; List route = new(); int routeIndex; bool isMoving; SpriteRenderer spriteRenderer; CircleCollider2D circleCollider; void Awake() { spriteRenderer = GetComponent(); circleCollider = GetComponent(); } void Update() { if (isTaggedOut || !isMoving || route.Count == 0) return; FollowRoute(); } void FollowRoute() { if (routeIndex >= route.Count) { isMoving = false; return; } Vector2 target = route[routeIndex]; Vector2 current = transform.position; Vector2 direction = (target - current).normalized; float distance = Vector2.Distance(current, target); // Check for obstacles ahead if (IsObstacleAhead(direction)) { isMoving = false; return; } float moveDistance = Game.UnitSpeed * Time.deltaTime; if (moveDistance >= distance) { // Reached waypoint transform.position = new Vector3(target.x, target.y, 0); routeIndex++; if (routeIndex >= route.Count) { isMoving = false; } } else { // Move toward waypoint Vector2 newPos = current + direction * moveDistance; transform.position = new Vector3(newPos.x, newPos.y, 0); } } bool IsObstacleAhead(Vector2 direction) { // Raycast to check for obstacles (non-trigger colliders) var hits = Physics2D.RaycastAll(transform.position, direction, 0.6f); foreach (var hit in hits) { if (hit.collider != null && hit.collider.gameObject != gameObject && !hit.collider.isTrigger) { return true; } } return false; } public void SetRoute(List waypoints) { if (isTaggedOut) return; route = new List(waypoints); routeIndex = 0; isMoving = route.Count > 0; } public void ClearRoute() { route.Clear(); routeIndex = 0; isMoving = false; } void OnTriggerEnter2D(Collider2D other) { if (isTaggedOut) return; // Check for enemy unit collision (tagging) var otherUnit = other.GetComponent(); if (otherUnit != null && otherUnit.team != team && !otherUnit.isTaggedOut) { HandleTagCollision(otherUnit); return; } // Check for flag pickup var flag = other.GetComponent(); if (flag != null && flag.team != team && flag.carriedBy == null) { flag.Pickup(this); return; } // Check for scoring (reaching own base with enemy flag) var baseZone = other.GetComponent(); if (baseZone != null && baseZone.team == team && hasFlag) { // Get the flag we're carrying var carriedFlag = team == Team.Player ? Game.Instance.enemyFlag : Game.Instance.playerFlag; if (carriedFlag != null && carriedFlag.carriedBy == this) { carriedFlag.Drop(); Game.Instance.Score(team); } } } void HandleTagCollision(Unit other) { // Only process collision once - lower instance ID handles it if (GetInstanceID() > other.GetInstanceID()) return; // Determine who gets tagged: farther from their own base loses // The instigator (closer to their base) is NOT captured Transform myBase = Game.Instance.GetBase(team); Transform theirBase = Game.Instance.GetBase(other.team); float myDistance = Vector2.Distance(transform.position, myBase.position); float theirDistance = Vector2.Distance(other.transform.position, theirBase.position); // Only the one farther from their base gets tagged if (myDistance > theirDistance) { TagOut(); } else { // They are farther or equal - they get tagged other.TagOut(); } } public void TagOut() { if (isTaggedOut) return; isTaggedOut = true; isMoving = false; route.Clear(); // Drop flag if carrying if (hasFlag) { var flag = team == Team.Player ? Game.Instance.enemyFlag : Game.Instance.playerFlag; if (flag != null && flag.carriedBy == this) { flag.Drop(); } } // Visual feedback - fade out if (spriteRenderer != null) { var color = spriteRenderer.color; color.a = 0.3f; spriteRenderer.color = color; } StartCoroutine(RespawnCoroutine()); } IEnumerator RespawnCoroutine() { yield return new WaitForSeconds(Game.RespawnDelay); // Respawn at base (landscape - horizontal offset toward center) Transform baseTransform = Game.Instance.GetBase(team); float xOffset = team == Team.Player ? 2f : -2f; Vector3 offset = new Vector3(xOffset, Random.Range(-2f, 2f), 0); transform.position = baseTransform.position + offset; isTaggedOut = false; // Restore visual if (spriteRenderer != null) { var color = spriteRenderer.color; color.a = 1f; spriteRenderer.color = color; } } public void ForceRespawn(Vector3 position) { StopAllCoroutines(); transform.position = position; isTaggedOut = false; isMoving = false; route.Clear(); hasFlag = false; if (spriteRenderer != null) { var color = spriteRenderer.color; color.a = 1f; spriteRenderer.color = color; } } public bool IsMoving => isMoving; public List CurrentRoute => route; }