using UnityEngine; using RR.Game2D.Core; using RR.Common.Interfaces; namespace RR.Game2D.Behaviour { [RequireComponent(typeof(Rigidbody2D), typeof(Collider2D), typeof(Animator))] public class EnemyController : MonoBehaviour, IDamageable { [Header("Обзор")] [SerializeField] private float viewDistance = 5f; [SerializeField] private float viewAngle = 60f; [Header("Движение")] [SerializeField] private float moveSpeed = 4f; [SerializeField] private float acceleration = 10f; [Header("Препятствия")] [SerializeField] private LayerMask obstacleMask; [Header("Здоровье")] [SerializeField] private int maxHealth = 1; private Health health; public int CurrentHealth => health?.CurrentHealth ?? 0; public int MaxHealth => health?.MaxHealth ?? 0; private Animator animator; private Rigidbody2D rb; private Collider2D col; private GameObject playerObj; // Аниматор private static readonly int Speed = Animator.StringToHash("Speed"); void Start() { rb = GetComponent(); col = GetComponent(); animator = GetComponent(); playerObj = GameManager.Instance.PlayerObj; if (playerObj == null) { playerObj = GameObject.FindGameObjectWithTag("Player"); } health = GetComponent(); if (health == null) { health = gameObject.AddComponent(); } health.ResetHealth(); health.SetOwner(this); health.SetMaxHealth(maxHealth); } void FixedUpdate() { if (!playerObj) return; Vector2 playerCenter = playerObj.transform.position; if (PlayerInSight()) { Vector2 toPlayer = playerCenter - (Vector2)transform.position; float dist = toPlayer.magnitude; if (dist > 0.01f) rb.linearVelocity = toPlayer / dist * moveSpeed; else rb.linearVelocity = Vector2.zero; } else { rb.linearVelocity = Vector2.MoveTowards( rb.linearVelocity, Vector2.zero, acceleration * Time.fixedDeltaTime); } animator.SetFloat(Speed, Mathf.Abs(rb.linearVelocity.magnitude)); } void OnCollisionEnter2D(Collision2D collision) { if (collision.collider.CompareTag("Player")) { Rigidbody2D playerRb = collision.collider.GetComponent(); playerObj.TryGetComponent(out PlayerController playerController); if (playerRb == null) return; Vector2 contactNormal = collision.GetContact(0).normal; if (contactNormal.y < -0.5f) { playerRb.linearVelocity = new Vector2(playerRb.linearVelocity.x, 35f); TakeDamage(MaxHealth); } else { playerController.TakeDamage(1); } } else if (collision.collider.CompareTag("Projectile")) { TakeDamage(1); } } private bool PlayerInSight() { if (!playerObj) return false; Transform player = playerObj.transform; Vector2 eyePos = new(rb.position.x, col.bounds.center.y); Vector2 toPlayer = (Vector2)player.position - eyePos; float dist = toPlayer.magnitude; if (dist > viewDistance) return false; Vector2 forward = transform.localEulerAngles.y >= 180f ? Vector2.right : Vector2.left; float cosHalf = Mathf.Cos(0.5f * viewAngle * Mathf.Deg2Rad); float dot = Vector2.Dot(forward.normalized, toPlayer / Mathf.Max(dist, 1e-6f)); if (dot < cosHalf) return false; int mask = obstacleMask; mask &= ~(1 << gameObject.layer); mask &= ~(1 << playerObj.layer); Vector2 origin = eyePos + forward.normalized * 0.05f; RaycastHit2D hit = Physics2D.Raycast(origin, toPlayer.normalized, dist, mask); if (hit.collider != null) return false; return true; } public void TakeDamage(int amount) { health.TakeDamage(amount); } public void Heal(int amount) { health.Heal(amount); } public void Die() { Destroy(gameObject); } #if UNITY_EDITOR private void OnDrawGizmos() { if (!playerObj) return; Vector2 origin = new(rb.position.x, rb.position.y + 1.45f); Vector2 forward = transform.localEulerAngles.y >= 180f ? Vector2.right : Vector2.left; float half = viewAngle * 0.5f; Vector2 edgeA = (Quaternion.Euler(0, 0, +half) * forward); Vector2 edgeB = (Quaternion.Euler(0, 0, -half) * forward); Gizmos.color = Color.yellow; Gizmos.DrawLine(origin, origin + edgeA * viewDistance); Gizmos.DrawLine(origin, origin + edgeB * viewDistance); Gizmos.DrawWireSphere(origin, viewDistance); Vector2 toPlayer = (Vector2)playerObj.transform.position - origin; if (toPlayer.magnitude <= viewDistance) { Gizmos.color = Color.red; Gizmos.DrawLine(origin, playerObj.transform.position); } } #endif } }