Start AI COntroller

This commit is contained in:
Caleb Sandford deQuincey
2025-10-28 17:26:07 +00:00
parent bc21e94bc1
commit 1972134c81
724 changed files with 579740 additions and 2918 deletions

View File

@@ -1,8 +1,11 @@
using UnityEngine;
using RPG.Combat;
public class CombatTarget : MonoBehaviour
namespace RPG.Combat
{
// This class is intentionally left empty.
// It serves as a marker to identify combat targets in the game.
[RequireComponent(typeof(Health))]
public class CombatTarget : MonoBehaviour
{
// This class is intentionally left empty.
// It serves as a marker to identify combat targets in the game.
}
}

View File

@@ -1,39 +1,85 @@
using UnityEngine;
using RPG.Movement;
using UnityEngine.Rendering;
using RPG.Core;
namespace RPG.Combat
{
public class Fighter : MonoBehaviour
public class Fighter : MonoBehaviour, IAction
{
[SerializeField]
private float weaponRange = 2f;
Transform target;
private void Update()
[SerializeField] private float timeBetweenAttacks = 1f;
[SerializeField] private float weaponRange = 2f;
[SerializeField] private float weaponDamage = 5f;
Health target;
private float timeSinceLastAttack = 0;
void Update()
{
timeSinceLastAttack += Time.deltaTime;
if (target == null) return;
if (target.IsDead()) return;
if (!GetIsInRange())
{
GetComponent<Mover>().MoveTo(target.position);
GetComponent<Mover>().MoveTo(target.transform.position);
}
else
{
GetComponent<Mover>().Stop();
GetComponent<Mover>().Cancel();
AttackBehaviour();
}
}
private void AttackBehaviour()
{
transform.LookAt(target.transform);
if (timeSinceLastAttack > timeBetweenAttacks)
{
//This will trigger the Hit() event.
TriggerAttack();
timeSinceLastAttack = 0;
}
else return;
}
private void TriggerAttack()
{
GetComponent<Animator>().ResetTrigger("stopAttack");
GetComponent<Animator>().SetTrigger("attack");
}
//Animation event
void Hit()
{
if (target == null) return;
target.TakeDamage(weaponDamage);
}
private bool GetIsInRange()
{
return Vector3.Distance(transform.position, target.position) <= weaponRange;
return Vector3.Distance(transform.position, target.transform.position) <= weaponRange;
}
public void Attack(CombatTarget combatTarget)
public bool CanAttack(GameObject combatTarget)
{
target = combatTarget.transform;
if (combatTarget == null) return false;
Health targetToTest = combatTarget.GetComponent<Health>();
return targetToTest != null && !targetToTest.IsDead();
}
public void Attack(GameObject combatTarget)
{
GetComponent<ActionScheduler>().StartAction(this);
target = combatTarget.GetComponent<Health>();
}
public void Cancel()
{
target = null;
StopAttack();
target = null;
}
private void StopAttack()
{
GetComponent<Animator>().ResetTrigger("attack");
GetComponent<Animator>().SetTrigger("stopAttack");
}
}
}

View File

@@ -0,0 +1,32 @@
using Unity.VisualScripting;
using UnityEngine;
namespace RPG.Combat
{
public class Health : MonoBehaviour
{
[SerializeField] float health = 100f;
bool isDead = false;
public bool IsDead()
{
return isDead;
}
public void TakeDamage(float damage)
{
health = Mathf.Max(health - damage, 0);
if(health == 0)
{
Die();
}
}
private void Die()
{
if (isDead) return;
isDead = true;
GetComponent<Animator>().SetTrigger("die");
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8fc6fa8368af1d9b8a0ecc2745f48ebe

View File

@@ -0,0 +1,39 @@
using RPG.Combat;
using RPG.Core;
using UnityEngine;
using UnityEngine.AI;
namespace RPG.Control
{
public class AIController : MonoBehaviour,IAction
{
[SerializeField] float chaseDistance = 5f;
Fighter fighter;
GameObject player;
void Start()
{
fighter = GetComponent<Fighter>();
player = GameObject.FindWithTag("Player");
}
void Update()
{
if (InAttackRangeOfPlayer() && fighter.CanAttack(player))
fighter.Attack(player);
else
{
fighter.Cancel();
}
}
private bool InAttackRangeOfPlayer()
{
float distanceToPlayer = Vector3.Distance(player.transform.position, transform.position);
return distanceToPlayer < chaseDistance;
}
public void Cancel()
{
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c781eee3ca72ca7a1b692987335cedc1

View File

@@ -43,11 +43,14 @@ namespace RPG.Control
foreach (RaycastHit hit in hits)
{
CombatTarget target = hit.transform.GetComponent<CombatTarget>();
if (target == null) continue;
if (target == null) continue;
if (!GetComponent<Fighter>().CanAttack(target.gameObject))
continue;
if (interactAction.WasPressedThisFrame())
{
//MoveToCursor();
GetComponent<Fighter>().Attack(target);
GetComponent<Fighter>().Attack(target.gameObject);
}
return true;
}

View File

@@ -0,0 +1,18 @@
using UnityEngine;
namespace RPG.Core
{
public class ActionScheduler : MonoBehaviour
{
IAction currentAction;
public void StartAction(IAction action)
{
if (currentAction == action) return;
if (currentAction != null)
{
currentAction.Cancel();
}
currentAction = action;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4ff1a795ab12b59d88076953d397a6d5

View File

@@ -0,0 +1,7 @@
namespace RPG.Core
{
public interface IAction
{
void Cancel();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4b307fcbc3bbf912cbad01e283421bba

View File

@@ -1,11 +1,11 @@
using RPG.Combat;
using RPG.Core;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
namespace RPG.Movement
{
public class Mover : MonoBehaviour
public class Mover : MonoBehaviour, IAction
{
[SerializeField] private Transform target;
@@ -26,7 +26,7 @@ namespace RPG.Movement
}
public void StartMoveAction(Vector3 destination)
{
GetComponent<Fighter>().Cancel();
GetComponent<ActionScheduler>().StartAction(this);
MoveTo(destination);
}
@@ -35,7 +35,7 @@ namespace RPG.Movement
navMeshAgent.destination = destination;
navMeshAgent.isStopped = false;
}
public void Stop()
public void Cancel()
{
navMeshAgent.isStopped = true;
}