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(); if (characterController == null) characterController = gameObject.AddComponent(); if (healthSystem == null) healthSystem = GetComponent(); } private void Start() { if (weapon) { var weaponGo = Instantiate(weapon.gameObject, weaponPoint); weapon = weaponGo.GetComponent(); weapon._firePoint = firePoint.transform; weapon.Reload(); attackCooldown = weapon.FireRate + 0.01f; } if (healthSystem != null) { healthSystem.OnDied += HandleDeath; } if (target != null) return; var player = FindFirstObjectByType(); 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("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; } }