MiniGames/Assets/Scripts/CubeClash/CubeClash_ZibuAI.cs

181 lines
5.7 KiB
C#
Raw Normal View History

2025-09-01 05:03:00 +05:00
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[RequireComponent(typeof(CubeClash_ZibuController))]
public class CubeClash_ZibuAI : MonoBehaviour
{
[Header("AI Settings")]
[Tooltip("Each NPC rolls a speed in this range so they don't mirror each other.")]
public Vector2 moveSpeedRange = new Vector2(2.5f, 4.5f);
[Tooltip("Small extra randomization applied when retargeting to keep desynced.")]
public float retargetSpeedJitter = 0.3f;
[HideInInspector] public float moveSpeed; // current per-agent speed (rolled at runtime)
2025-09-01 05:03:00 +05:00
public float decisionInterval = 2f;
public float bumpRange = 2.5f;
public float roamRadius = 5f;
[Header("Arena Bounds")]
public Transform arenaCube;
private Bounds arenaBounds;
private CubeClash_ZibuController zibuController;
private Rigidbody rb;
private CubeClash_ZibuController target;
private Vector3 roamTarget;
private float decisionTimer;
private bool isBumpCooling = false;
private CubeClash_ZibuController lastTarget;
void Awake()
{
zibuController = GetComponent<CubeClash_ZibuController>();
rb = GetComponent<Rigidbody>();
zibuController.isPlayerControlled = false;
if (arenaCube != null)
arenaBounds = new Bounds(arenaCube.position, arenaCube.localScale);
// Roll an initial per-agent speed
moveSpeed = Random.Range(moveSpeedRange.x, moveSpeedRange.y);
// Randomize starting decision timer so AIs don<6F>t sync up
decisionTimer = Random.Range(0f, decisionInterval);
2025-09-01 05:03:00 +05:00
PickRoamTarget();
}
void Update()
{
if (zibuController.ControlLocked) return; // don't fight pushes
2025-09-01 05:03:00 +05:00
decisionTimer += Time.deltaTime;
if (decisionTimer >= decisionInterval)
{
decisionTimer = 0f;
PickTargetOrRoam();
}
if (target != null)
{
MoveTowards(target.transform.position);
TryBumpTarget();
}
else
{
MoveTowards(roamTarget);
if (Vector3.Distance(transform.position, roamTarget) < 1f)
PickRoamTarget();
}
}
void PickTargetOrRoam()
{
List<CubeClash_ZibuController> allZibus = CubeClash_ZibuController.AllZibus;
if (allZibus.Count > 1)
{
List<CubeClash_ZibuController> candidates = new List<CubeClash_ZibuController>();
foreach (var z in allZibus)
if (z != zibuController)
2025-09-01 05:03:00 +05:00
candidates.Add(z);
if (candidates.Count > 0)
{
if (candidates.Count > 1 && lastTarget != null)
candidates.Remove(lastTarget);
2025-09-01 05:03:00 +05:00
int index = Random.Range(0, candidates.Count);
target = candidates[index];
// Tiny re-roll of speed to avoid symmetric face-offs
ReRollSpeedSlightly();
2025-09-01 05:03:00 +05:00
return;
}
}
target = null;
PickRoamTarget();
}
2025-09-01 05:03:00 +05:00
void MoveTowards(Vector3 destination)
{
if (zibuController.ControlLocked) return; // skip if stunned
2025-09-01 05:03:00 +05:00
Vector3 dir = (destination - transform.position).normalized;
Vector3 move = new Vector3(dir.x, 0, dir.z) * moveSpeed;
rb.velocity = new Vector3(move.x, rb.velocity.y, move.z);
if (dir.magnitude > 0.1f)
{
dir.y = 0;
Quaternion targetRot = Quaternion.LookRotation(dir, Vector3.up);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * 5f);
}
}
void PickRoamTarget()
{
// Pick anywhere in arena to spread agents out
2025-09-01 05:03:00 +05:00
if (arenaCube != null)
{
arenaBounds = new Bounds(arenaCube.position, arenaCube.localScale);
float x = Random.Range(arenaBounds.min.x + 1f, arenaBounds.max.x - 1f);
float z = Random.Range(arenaBounds.min.z + 1f, arenaBounds.max.z - 1f);
roamTarget = new Vector3(x, transform.position.y, z);
}
else
{
// Fallback: local random offset if no arena assigned
Vector3 randomOffset = new Vector3(Random.Range(-roamRadius, roamRadius), 0, Random.Range(-roamRadius, roamRadius));
roamTarget = transform.position + randomOffset;
2025-09-01 05:03:00 +05:00
}
// Slight re-roll on roam choose too
ReRollSpeedSlightly();
2025-09-01 05:03:00 +05:00
}
void TryBumpTarget()
{
if (isBumpCooling || target == null) return;
float dist = Vector3.Distance(transform.position, target.transform.position);
if (dist <= bumpRange)
{
Vector3 toTarget = (target.transform.position - transform.position).normalized;
float dot = Vector3.Dot(transform.forward, toTarget);
if (dot > 0.7f)
StartCoroutine(BumpWithDelay());
}
}
IEnumerator BumpWithDelay()
{
isBumpCooling = true;
// Extra jitter before bump to desync
yield return new WaitForSeconds(Random.Range(0.15f, 0.6f));
2025-09-01 05:03:00 +05:00
if (!zibuController.ControlLocked)
zibuController.PerformBump(transform.forward);
2025-09-01 05:03:00 +05:00
lastTarget = target;
target = null;
PickRoamTarget();
// Randomized cooldown so they don't re-sync
yield return new WaitForSeconds(Random.Range(1.2f, 2.5f));
2025-09-01 05:03:00 +05:00
isBumpCooling = false;
}
// --- Helpers ---
void ReRollSpeedSlightly()
{
float baseRoll = Random.Range(moveSpeedRange.x, moveSpeedRange.y);
float jitter = Random.Range(-retargetSpeedJitter, retargetSpeedJitter);
moveSpeed = Mathf.Clamp(baseRoll + jitter, moveSpeedRange.x, moveSpeedRange.y);
}
2025-09-01 05:03:00 +05:00
}