Files
PIM_Laba5/Assets/Scripts/EnemyVision.cs
T
2026-05-26 01:16:57 +03:00

120 lines
3.6 KiB
C#

using UnityEngine;
public class EnemyVision : MonoBehaviour
{
[Header("References")]
public EnemyStateMachine stateMachine;
public Transform player;
[Header("Vision")]
public float viewRadius = 14f;
[Range(1f, 180f)]
public float viewAngle = 65f;
public LayerMask obstacleMask;
public LayerMask targetMask;
public float eyeHeight = 1.4f;
public float standingDetectionDelay = 0.12f;
public float crouchDetectionDelay = 0.35f;
private bool hadLineOfSight;
private float visibleTimer;
private void Awake()
{
stateMachine = stateMachine != null ? stateMachine : GetComponent<EnemyStateMachine>();
}
private void Update()
{
AcquirePlayer();
if (player == null || stateMachine == null)
{
return;
}
bool canSeePlayer = CanSeePlayer(out Vector3 eyePosition, out Vector3 targetPosition, out Color debugColor);
Debug.DrawRay(eyePosition, targetPosition - eyePosition, debugColor);
if (canSeePlayer)
{
PlayerStealth stealth = player.GetComponent<PlayerStealth>();
float requiredTime = stealth != null && stealth.IsCrouching ? crouchDetectionDelay : standingDetectionDelay;
visibleTimer += Time.deltaTime;
if (visibleTimer >= requiredTime)
{
hadLineOfSight = true;
stateMachine.OnPlayerDetected(player.position);
}
}
else
{
visibleTimer = 0f;
if (hadLineOfSight)
{
hadLineOfSight = false;
stateMachine.OnPlayerLost();
}
}
}
public float GetViewRadiusForCurrentTarget()
{
if (player == null)
{
return viewRadius;
}
PlayerStealth stealth = player.GetComponent<PlayerStealth>();
return viewRadius * (stealth != null ? stealth.VisibilityMultiplier : 1f);
}
private bool CanSeePlayer(out Vector3 eyePosition, out Vector3 targetPosition, out Color debugColor)
{
eyePosition = transform.position + Vector3.up * eyeHeight;
targetPosition = player.position + Vector3.up * 0.9f;
debugColor = Color.gray;
float effectiveRadius = GetViewRadiusForCurrentTarget();
Vector3 directionToPlayer = targetPosition - eyePosition;
float distanceToPlayer = directionToPlayer.magnitude;
if (distanceToPlayer > effectiveRadius)
{
return false;
}
float angleToPlayer = Vector3.Angle(transform.forward, directionToPlayer);
if (angleToPlayer > viewAngle * 0.5f)
{
return false;
}
int combinedMask = obstacleMask | targetMask;
if (Physics.Raycast(eyePosition, directionToPlayer.normalized, out RaycastHit hit, distanceToPlayer, combinedMask, QueryTriggerInteraction.Ignore))
{
// Если первым попался не игрок, значит между врагом и игроком есть укрытие или стена.
bool isPlayerHit = hit.transform == player || hit.transform.IsChildOf(player);
debugColor = isPlayerHit ? Color.green : Color.red;
return isPlayerHit;
}
debugColor = Color.red;
return false;
}
private void AcquirePlayer()
{
if (player != null)
{
return;
}
GameObject playerObject = GameObject.FindGameObjectWithTag("Player");
if (playerObject != null)
{
player = playerObject.transform;
}
}
}