120 lines
3.6 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|