145 lines
4.3 KiB
C#
145 lines
4.3 KiB
C#
using Code.Gameplay.Character.Core;
|
|
using UnityEngine;
|
|
using Code.Gameplay.Core;
|
|
using Code.Gameplay.Character.Stats;
|
|
using Code.Gameplay.Weapons;
|
|
|
|
namespace Code.Gameplay.Enemy
|
|
{
|
|
public class SimpleEnemy : MonoBehaviour, IDamageable
|
|
{
|
|
[SerializeField] private HealthSystem healthSystem;
|
|
[SerializeField] private WeaponBase weapon;
|
|
[SerializeField] private Transform firePoint;
|
|
[SerializeField] private Transform target;
|
|
|
|
[SerializeField] private float moveSpeed = 3f;
|
|
[SerializeField] private float rotationSpeed = 5f;
|
|
[SerializeField] private float detectionRange = 20f;
|
|
[SerializeField] private float attackRange = 15f;
|
|
[SerializeField] private float stopDistance = 5f;
|
|
|
|
[SerializeField] private float attackCooldown = 1f;
|
|
[SerializeField] private LayerMask obstacleMask;
|
|
|
|
private float lastAttackTime;
|
|
private bool isAttacking;
|
|
private CharacterController characterController;
|
|
|
|
public bool IsAlive => healthSystem != null && healthSystem.IsAlive;
|
|
|
|
private void Awake()
|
|
{
|
|
characterController = GetComponent<CharacterController>();
|
|
if (characterController == null)
|
|
characterController = gameObject.AddComponent<CharacterController>();
|
|
|
|
if (healthSystem == null)
|
|
healthSystem = GetComponent<HealthSystem>();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
if (healthSystem != null)
|
|
{
|
|
healthSystem.OnDied += HandleDeath;
|
|
}
|
|
|
|
if (target != null) return;
|
|
|
|
var player = FindFirstObjectByType<CharacterProvider>();
|
|
if (player != null)
|
|
target = player.transform;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!IsAlive || target == null) return;
|
|
|
|
var distanceToTarget = Vector3.Distance(transform.position, target.position);
|
|
|
|
if (!(distanceToTarget <= detectionRange)) return;
|
|
|
|
RotateTowardsTarget();
|
|
|
|
if (distanceToTarget <= attackRange)
|
|
{
|
|
Attack();
|
|
|
|
if (distanceToTarget < stopDistance)
|
|
{
|
|
MoveAway();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MoveTowardsTarget();
|
|
}
|
|
}
|
|
|
|
private void RotateTowardsTarget()
|
|
{
|
|
var direction = (target.position - transform.position).normalized;
|
|
direction.y = 0;
|
|
|
|
var lookRotation = Quaternion.LookRotation(direction);
|
|
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * rotationSpeed);
|
|
}
|
|
|
|
private void MoveTowardsTarget()
|
|
{
|
|
var direction = (target.position - transform.position).normalized;
|
|
direction.y = 0;
|
|
|
|
characterController.Move(direction * (moveSpeed * Time.deltaTime));
|
|
}
|
|
|
|
private void MoveAway()
|
|
{
|
|
var direction = (transform.position - target.position).normalized;
|
|
direction.y = 0;
|
|
|
|
characterController.Move(direction * (moveSpeed * Time.deltaTime));
|
|
}
|
|
|
|
private void Attack()
|
|
{
|
|
if (Time.time - lastAttackTime < attackCooldown) return;
|
|
if (weapon == null) return;
|
|
|
|
if (!HasLineOfSight()) return;
|
|
|
|
lastAttackTime = Time.time;
|
|
weapon.Shoot();
|
|
}
|
|
|
|
private bool HasLineOfSight()
|
|
{
|
|
if (target == null) return false;
|
|
|
|
var direction = (target.position - firePoint.position).normalized;
|
|
var distance = Vector3.Distance(firePoint.position, target.position);
|
|
|
|
if (Physics.Raycast(firePoint.position, direction, out var hit, distance, obstacleMask))
|
|
{
|
|
return hit.collider.transform == target;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void HandleDeath()
|
|
{
|
|
enabled = false;
|
|
|
|
Destroy(gameObject, 2f);
|
|
}
|
|
|
|
public void TakeDamage(float damage)
|
|
{
|
|
healthSystem?.TakeDamage(damage);
|
|
}
|
|
|
|
public Transform GetTransform() => transform;
|
|
}
|
|
} |