150 lines
4.8 KiB
C#
150 lines
4.8 KiB
C#
using UnityEngine;
|
|
using RR.Game2D.Core;
|
|
|
|
namespace RR.Game2D.Behaviour
|
|
{
|
|
[RequireComponent(typeof(Rigidbody2D),
|
|
typeof(Collider2D),
|
|
typeof(Animator))]
|
|
public class EnemyController : MonoBehaviour
|
|
{
|
|
[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;
|
|
|
|
private Animator animator;
|
|
private Rigidbody2D rb;
|
|
private Collider2D col;
|
|
|
|
private GameObject playerObj;
|
|
|
|
void Start()
|
|
{
|
|
rb = GetComponent<Rigidbody2D>();
|
|
col = GetComponent<Collider2D>();
|
|
animator = GetComponent<Animator>();
|
|
|
|
playerObj = GameManager.Instance.PlayerObj;
|
|
if (playerObj == null)
|
|
{
|
|
playerObj = GameObject.FindGameObjectWithTag("Player");
|
|
}
|
|
}
|
|
|
|
void FixedUpdate()
|
|
{
|
|
if (!playerObj) return;
|
|
|
|
Vector2 playerCenter = (Vector2)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<Rigidbody2D>();
|
|
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);
|
|
Die();
|
|
}
|
|
else
|
|
{
|
|
playerController.Die();
|
|
}
|
|
}
|
|
else if (collision.collider.CompareTag("Projectile")) Die();
|
|
}
|
|
|
|
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 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 = (Vector2)(Quaternion.Euler(0, 0, +half) * (Vector3)forward);
|
|
Vector2 edgeB = (Vector2)(Quaternion.Euler(0, 0, -half) * (Vector3)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
|
|
}
|
|
} |