Files
CartoonFPS/Assets/Scripts/AIBehaviour.cs
2025-08-06 23:18:38 +01:00

192 lines
6.7 KiB
C#

using Akila.FPSFramework;
using RaycastPro.Detectors;
using UnityEngine;
public class AIBehaviour : MonoBehaviour
{
public enum AIType
{
None,
Enemy,
Ally,
Neutral
}
[SerializeField]
private AIType aiType = AIType.None;
[SerializeField]
private float detectionRange, attackRange, contactRange, pointWaitTimer, moveSpeed, attackDamage, currentHealth, maxHealth; // Example ranges for detecting and attacking targets
private float waitCounter; // Timer for waiting at patrol points
[SerializeField]
private Animator animator; // Animator for handling animations
[SerializeField]
private Transform[] patrolPoints;
[SerializeField]
private Transform pointsHolder; // Optional holder for patrol points
private int currentPatrolPoint = 0;
private bool isEngaged = false; // Flag to control patrolling
[SerializeField]
private Rigidbody theRB; // Rigidbody for movement control
[SerializeField]
private SightDetector sightDetector; // Sight detector for detecting targets
private void Start()
{
// Start patrolling
Patrol();
if (pointsHolder != null)
{
pointsHolder.SetParent(null);
}
if (patrolPoints.Length == 0)
{
Debug.LogWarning("No patrol points assigned. AI will not patrol.");
}
if (animator == null)
{
Debug.LogError("Animator not assigned. AI will not animate.");
}
if (theRB == null)
{
Debug.LogError("Rigidbody not assigned. AI will not move.");
}
currentPatrolPoint = 0; // Start at the first patrol point
waitCounter = Random.Range(0.75f, 1.25f) * pointWaitTimer;
currentHealth = maxHealth; // Initialize current health
detectionRange = sightDetector.Radius; // Set detection range based on sight detector radius
attackRange = detectionRange - 10f; // Set attack range based on detection range minus 10
contactRange = sightDetector.fullAwareness; // Set contact range based on sight detector full awareness
}
private void Update()
{
if (!isEngaged && patrolPoints.Length > 0)
{
Patrol();
}
else if (patrolPoints.Length == 0)
{
Debug.LogWarning("No patrol points assigned. AI will not patrol.");
}
}
public void TargetDetected(Collider detectedCollider)
{
if (detectedCollider == null) return;
float distance = Vector3.Distance(transform.position, detectedCollider.transform.position);
if (detectedCollider.gameObject.CompareTag("Player") && this.aiType == AIType.Ally)
{
// Player logic remains unchanged
if (distance <= attackRange)
{
Debug.Log("Keep moving civilian, don't get too close!");
// Add logic to attack the player
}
else if (distance <= detectionRange)
{
Debug.Log("Stay safe civilian...");
// Add logic to engage with the player
}
else
{
Debug.Log("Player out of detection range.");
}
}
else if (detectedCollider.CompareTag("Enemy") && this.aiType == AIType.Ally)
{
if (distance <= attackRange)
{
isEngaged = true;
StopMovement();
Debug.Log("Open fire!");
animator.SetBool("shooting", true); // Start attacking animation
AttackTarget(detectedCollider); // Call the attack method
}
else if (distance <= detectionRange)
{
isEngaged = true;
StopMovement();
Debug.Log("Zombie sighted!");
transform.LookAt(detectedCollider.transform);
animator.SetBool("aiming", true); // Start aiming animation
}
else
{
isEngaged = false;
Debug.Log("Enemy out of detection range.");
animator.SetBool("shooting", false); // Stop shooting animation
animator.SetBool("aiming", false); // Stop aiming animation
currentPatrolPoint = (currentPatrolPoint + 1) % patrolPoints.Length;
Patrol();
}
}
// You can add more logic here, such as engaging with the target or updating AI state
}
public void Patrol()
{
animator.SetFloat("speed", 0.5f); // Slow down the patrol animation for better visibility
if (patrolPoints.Length == 0) return;
Transform targetPoint = patrolPoints[currentPatrolPoint];
transform.LookAt(targetPoint);
transform.position = Vector3.MoveTowards(transform.position, targetPoint.position, moveSpeed * Time.deltaTime);
if (Vector3.Distance(transform.position, targetPoint.position) < 0.1f)
{
currentPatrolPoint = (currentPatrolPoint + 1) % patrolPoints.Length;
waitCounter -= Time.deltaTime;
if (waitCounter <= 0)
{
currentPatrolPoint++;
if (currentPatrolPoint >= patrolPoints.Length)
{
currentPatrolPoint = 0;
}
waitCounter = Random.Range(0.75f, 1.25f) * pointWaitTimer;
}
}
}
private void StopMovement()
{
if (theRB != null)
{
theRB.linearVelocity = Vector3.zero; // Stop the Rigidbody movement
}
animator.SetFloat("speed", 0f); // Set animation speed to idle
}
private void AttackTarget(Collider collider)
{
if (theRB != null)
{
theRB.linearVelocity = Vector3.zero; // Stop the Rigidbody movement
}
animator.SetFloat("speed", 0f); // Set animation speed to idle
animator.SetBool("shooting", true); // Start attacking animation
collider.GetComponent<EnemyController>().TakeDamage(attackDamage); // Example damage value
Debug.Log("Attacked target: " + collider.name + " for " + attackDamage + " damage.");
}
public void TakeDamage(float damageToTake)
{
// Handle taking damage logic here
Debug.Log("AI took " + damageToTake + " damage.");
currentHealth -= damageToTake;
if (currentHealth <= 0)
{
Die();
}
}
private void Die()
{
Debug.Log("AI has died.");
animator.SetTrigger("die"); // Trigger death animation
isEngaged = false; // Stop any engagement
StopMovement(); // Stop movement
// Additional logic for AI death, such as disabling components or destroying the object
}
}