темп
This commit is contained in:
1 parent
020934e07f
commit
7024e1daf0
10 files changed
+1754
-49
No files matched your search
@@ -0,0 +1,156 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Gameplay.Enemies
|
||||
{
|
||||
public class Cockroach : BaseEnemy
|
||||
{
|
||||
[Header("Cockroach-Specific")]
|
||||
public float wallCheckDistance = 0.5f;
|
||||
public float moveForce = 10f;
|
||||
public float maxSpeed = 5f;
|
||||
public LayerMask climbableLayers; // ← ← ← ТОЛЬКО для стен/пола (где ползать), НЕ для игрока!
|
||||
|
||||
[SerializeField] private Rigidbody rb;
|
||||
[SerializeField] private Transform model; // модель таракана (дочерний объект для поворота)
|
||||
|
||||
private Vector3 surfaceNormal = Vector3.up;
|
||||
private bool isPlayerDetected = false;
|
||||
private Collider[] _overlapResults = new Collider[4]; // для переиспользования
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
// Убираем NavMeshAgent — он не нужен для лазания
|
||||
if (agent != null)
|
||||
{
|
||||
agent.enabled = false;
|
||||
Destroy(agent);
|
||||
agent = null;
|
||||
}
|
||||
|
||||
if (rb == null)
|
||||
rb = GetComponent<Rigidbody>();
|
||||
|
||||
rb.useGravity = false;
|
||||
rb.isKinematic = false;
|
||||
rb.freezeRotation = true;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
if (!Player) return;
|
||||
|
||||
HandleStun();
|
||||
HandleAttackCooldown();
|
||||
|
||||
if (IsStunned) return;
|
||||
|
||||
DetectPlayer();
|
||||
HandleMovement();
|
||||
HandleAttack();
|
||||
}
|
||||
|
||||
private void DetectPlayer()
|
||||
{
|
||||
// Ищем игрока по тегу через OverlapSphere — без LayerMask
|
||||
int hits = Physics.OverlapSphereNonAlloc(transform.position, detectionRange, _overlapResults);
|
||||
isPlayerDetected = false;
|
||||
|
||||
for (int i = 0; i < hits; i++)
|
||||
{
|
||||
if (_overlapResults[i].CompareTag("Player"))
|
||||
{
|
||||
isPlayerDetected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void HandleMovement()
|
||||
{
|
||||
if (!isPlayerDetected)
|
||||
{
|
||||
rb.linearVelocity = Vector3.zero;
|
||||
return;
|
||||
}
|
||||
|
||||
// Направление к игроку (проекция на горизонталь, чтобы не лез вверх/вниз резко)
|
||||
Vector3 toPlayer = Player.transform.position - transform.position;
|
||||
toPlayer = Vector3.ProjectOnPlane(toPlayer, surfaceNormal).normalized;
|
||||
|
||||
// Raycast вниз и вперёд-вниз, чтобы найти поверхность
|
||||
Vector3 rayOrigin = transform.position + transform.up * 0.1f;
|
||||
bool foundSurface = false;
|
||||
|
||||
// Основной луч вниз (относительно текущей ориентации)
|
||||
if (Physics.Raycast(rayOrigin, -transform.up, out RaycastHit hit, wallCheckDistance * 2, climbableLayers))
|
||||
{
|
||||
surfaceNormal = hit.normal;
|
||||
foundSurface = true;
|
||||
}
|
||||
// Запасной — в мировой вниз (на случай, если "повернулся вверх ногами")
|
||||
else if (Physics.Raycast(rayOrigin, -Vector3.up, out hit, wallCheckDistance * 2, climbableLayers))
|
||||
{
|
||||
surfaceNormal = hit.normal;
|
||||
foundSurface = true;
|
||||
}
|
||||
|
||||
// Если поверхность не найдена — не двигаемся (падаем или стоим)
|
||||
if (!foundSurface)
|
||||
return;
|
||||
|
||||
// Поворачиваем модель так, чтобы "спина" смотрела от поверхности
|
||||
if (model != null)
|
||||
{
|
||||
// Смотрим в сторону игрока, но "встаём" на поверхность
|
||||
Quaternion targetRot = Quaternion.FromToRotation(Vector3.up, surfaceNormal);
|
||||
Quaternion lookRot = Quaternion.LookRotation(toPlayer, surfaceNormal);
|
||||
model.rotation = Quaternion.Slerp(model.rotation, targetRot * lookRot, Time.deltaTime * 12f);
|
||||
}
|
||||
|
||||
// Движение — в плоскости поверхности
|
||||
Vector3 moveDir = Vector3.ProjectOnPlane(toPlayer, surfaceNormal).normalized;
|
||||
Vector3 force = moveDir * moveForce;
|
||||
rb.AddForce(force, ForceMode.Force);
|
||||
rb.linearVelocity = Vector3.ClampMagnitude(rb.linearVelocity, maxSpeed);
|
||||
}
|
||||
|
||||
protected override void HandleAttack()
|
||||
{
|
||||
if (!Player || !isPlayerDetected) return;
|
||||
|
||||
float distance = Vector3.Distance(transform.position, Player.transform.position);
|
||||
if (distance <= attackRange && CanAttack)
|
||||
{
|
||||
DealDamage();
|
||||
}
|
||||
}
|
||||
|
||||
// Столкновение = -1 HP (по ТЗ)
|
||||
private void OnCollisionEnter(Collision col)
|
||||
{
|
||||
if (col.gameObject.CompareTag("Player"))
|
||||
{
|
||||
PlayerHealth?.GetDamage(collisionDamage);
|
||||
ApplyEffectsToPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawWireSphere(transform.position, detectionRange);
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawWireSphere(transform.position, attackRange);
|
||||
|
||||
// Покажем направление поверхности в эдиторе (если запущено)
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Gizmos.color = Color.cyan;
|
||||
Gizmos.DrawLine(transform.position, transform.position + surfaceNormal * 0.4f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user