MiniGames/Assets/Scripts/CubeClash/CubeClash_ZibuAI.cs

181 lines
5.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
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 dont sync up
decisionTimer = Random.Range(0f, decisionInterval);
PickRoamTarget();
}
void Update()
{
if (zibuController.ControlLocked) return; // don't fight pushes
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)
candidates.Add(z);
if (candidates.Count > 0)
{
if (candidates.Count > 1 && lastTarget != null)
candidates.Remove(lastTarget);
int index = Random.Range(0, candidates.Count);
target = candidates[index];
// Tiny re-roll of speed to avoid symmetric face-offs
ReRollSpeedSlightly();
return;
}
}
target = null;
PickRoamTarget();
}
void MoveTowards(Vector3 destination)
{
if (zibuController.ControlLocked) return; // skip if stunned
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
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;
}
// Slight re-roll on roam choose too
ReRollSpeedSlightly();
}
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));
if (!zibuController.ControlLocked)
zibuController.PerformBump(transform.forward);
lastTarget = target;
target = null;
PickRoamTarget();
// Randomized cooldown so they don't re-sync
yield return new WaitForSeconds(Random.Range(1.2f, 2.5f));
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);
}
}