started building out level
Signed-off-by: sdqhome\caleb <caleb@sdqhome.co.uk>
This commit is contained in:
110
Assets/Scripts/CombatController.cs
Normal file
110
Assets/Scripts/CombatController.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Quests;
|
||||
|
||||
[RequireComponent(typeof(CharacterStats))]
|
||||
public class CombatController : MonoBehaviour
|
||||
{
|
||||
[Header("Combat Feedback Prefabs (Optional)")]
|
||||
[SerializeField] private GameObject attackEffectPrefab;
|
||||
[SerializeField] private GameObject hitEffectPrefab;
|
||||
|
||||
public CharacterStats Stats { get; private set; }
|
||||
public CharacterStats CurrentTarget { get; private set; }
|
||||
|
||||
public event Action<CharacterStats> OnAttackExecuted;
|
||||
|
||||
private float lastAttackTime = 0f;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Stats = GetComponent<CharacterStats>();
|
||||
Stats.onDeath.AddListener(OnSelfDeath);
|
||||
}
|
||||
|
||||
public void SetTarget(CharacterStats target)
|
||||
{
|
||||
if (target == this.Stats || (target != null && target.IsDead))
|
||||
{
|
||||
ClearTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentTarget = target;
|
||||
}
|
||||
|
||||
public void ClearTarget()
|
||||
{
|
||||
CurrentTarget = null;
|
||||
}
|
||||
|
||||
public bool IsInAttackRange(CharacterStats target)
|
||||
{
|
||||
if (target == null) return false;
|
||||
|
||||
Vector3 flatSelf = new Vector3(transform.position.x, 0, transform.position.z);
|
||||
Vector3 flatTarget = new Vector3(target.transform.position.x, 0, target.transform.position.z);
|
||||
|
||||
float distance = Vector3.Distance(flatSelf, flatTarget);
|
||||
return distance <= Stats.AttackRange;
|
||||
}
|
||||
|
||||
public bool CanAttack()
|
||||
{
|
||||
if (Stats.IsDead || CurrentTarget == null || CurrentTarget.IsDead) return false;
|
||||
if (!IsInAttackRange(CurrentTarget)) return false;
|
||||
|
||||
float attackCooldown = 1.0f / Mathf.Max(Stats.AttackSpeed, 0.1f);
|
||||
return Time.time >= lastAttackTime + attackCooldown;
|
||||
}
|
||||
|
||||
public bool TryExecuteAttack()
|
||||
{
|
||||
if (!CanAttack()) return false;
|
||||
|
||||
lastAttackTime = Time.time;
|
||||
|
||||
// Face target
|
||||
Vector3 dir = (CurrentTarget.transform.position - transform.position);
|
||||
dir.y = 0;
|
||||
if (dir != Vector3.zero)
|
||||
{
|
||||
transform.rotation = Quaternion.LookRotation(dir);
|
||||
}
|
||||
|
||||
// Deal Damage
|
||||
float damage = Stats.BaseDamage;
|
||||
CurrentTarget.TakeDamage(damage, gameObject);
|
||||
|
||||
// Visual effects
|
||||
if (attackEffectPrefab != null)
|
||||
{
|
||||
Instantiate(attackEffectPrefab, transform.position + transform.forward * 0.5f + Vector3.up, transform.rotation);
|
||||
}
|
||||
if (hitEffectPrefab != null && CurrentTarget != null)
|
||||
{
|
||||
Instantiate(hitEffectPrefab, CurrentTarget.transform.position + Vector3.up, Quaternion.identity);
|
||||
}
|
||||
|
||||
OnAttackExecuted?.Invoke(CurrentTarget);
|
||||
|
||||
// If target died from this attack
|
||||
if (CurrentTarget.IsDead)
|
||||
{
|
||||
// Report kill to Quest System if attacker is player
|
||||
if (gameObject.CompareTag("Player") && QuestManager.Instance != null)
|
||||
{
|
||||
QuestManager.Instance.ReportKill(CurrentTarget.CharacterName);
|
||||
}
|
||||
|
||||
ClearTarget();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnSelfDeath(GameObject killer)
|
||||
{
|
||||
ClearTarget();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user