161 lines
5.1 KiB
C#
161 lines
5.1 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 weaponPoint;
|
|
[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 (weapon)
|
|
{
|
|
var weaponGo = Instantiate(weapon.gameObject, weaponPoint);
|
|
weapon = weaponGo.GetComponent<WeaponBase>();
|
|
weapon._firePoint = firePoint.transform;
|
|
weapon.Reload();
|
|
attackCooldown = weapon.FireRate + 0.01f;
|
|
}
|
|
|
|
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) 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) return;
|
|
|
|
if (!HasLineOfSight()) return;
|
|
|
|
lastAttackTime = Time.time;
|
|
if (weapon.CurrentAmmo <= 0)
|
|
weapon.Reload();
|
|
else
|
|
weapon.StartShooting();
|
|
}
|
|
|
|
private bool HasLineOfSight()
|
|
{
|
|
if (!target) return false;
|
|
|
|
var direction = (target.position - weaponPoint.position).normalized;
|
|
var distance = Vector3.Distance(weaponPoint.position, target.position);
|
|
|
|
if (Physics.Raycast(weaponPoint.position, direction, out var hit, distance, obstacleMask))
|
|
{
|
|
return hit.collider.transform == target;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void HandleDeath()
|
|
{
|
|
enabled = false;
|
|
|
|
var healthGo = Instantiate(Resources.Load<GameObject>("Prefabs/HealthBuff").gameObject);
|
|
healthGo.transform.position = new Vector3(transform.position.x, transform.position.y - 1, transform.position.z);
|
|
|
|
Destroy(gameObject, 1);
|
|
}
|
|
|
|
public void TakeDamage(float damage)
|
|
{
|
|
healthSystem?.TakeDamage(damage);
|
|
}
|
|
|
|
public Transform GetTransform() => transform;
|
|
}
|
|
} |