232 lines
6.0 KiB
C#
232 lines
6.0 KiB
C#
using System;
|
|
using Obvious.Soap;
|
|
using UnityEngine;
|
|
|
|
public class FishAI : MonoBehaviour
|
|
{
|
|
public Transform anchor;
|
|
|
|
public Action<Rigidbody> OnLureTargetReached;
|
|
|
|
[SerializeField]
|
|
private LayerMask lureCheckLayerMask;
|
|
|
|
[SerializeField]
|
|
private LayerMask obstacleLayerMask;
|
|
|
|
public ScriptableEventNoParam onLureIsTooLargeForFish;
|
|
|
|
[SerializeField]
|
|
private FishZoneObject fishZone;
|
|
|
|
public float WaitTime = 1f;
|
|
|
|
public FishData fishData;
|
|
|
|
public float length;
|
|
|
|
private bool isLure;
|
|
|
|
private Rigidbody _rbody;
|
|
|
|
private WaterBody _waterBody;
|
|
|
|
private int _terrainLayerMaskId;
|
|
|
|
private int _fishLayerMaskId;
|
|
|
|
private int _lureLayerMaskId;
|
|
|
|
private LayerMask _layerCollisionMask;
|
|
|
|
private Vector3 _moveDirection;
|
|
|
|
private Vector3 _moveTargetPosition;
|
|
|
|
private Vector3 _velocity;
|
|
|
|
public Lure lure;
|
|
|
|
private float distanceToTarget;
|
|
|
|
private RaycastHit[] rayHits = new RaycastHit[1];
|
|
|
|
private float _CheckLureCooldown = 2.5f;
|
|
|
|
private float _CheckLureTime;
|
|
|
|
public FishZoneObject FishZone
|
|
{
|
|
set
|
|
{
|
|
fishZone = value;
|
|
}
|
|
}
|
|
|
|
public bool isTargetReached { get; private set; }
|
|
|
|
private float _getAreaDistance => UnityEngine.Random.Range(fishData.areaDistance * 0.2f, fishData.areaDistance);
|
|
|
|
public event Action OnDestinationReached = delegate
|
|
{
|
|
};
|
|
|
|
private void Awake()
|
|
{
|
|
_rbody = GetComponent<Rigidbody>();
|
|
_waterBody = GetComponent<WaterBody>();
|
|
_terrainLayerMaskId = LayerMask.NameToLayer("Terrain");
|
|
_fishLayerMaskId = LayerMask.NameToLayer("Fish");
|
|
_lureLayerMaskId = LayerMask.NameToLayer("Lure");
|
|
_layerCollisionMask = LayerMask.GetMask("Terrain", "Fish", "Lure");
|
|
}
|
|
|
|
public void SetMovePosition(Vector3 position)
|
|
{
|
|
_moveTargetPosition = position;
|
|
}
|
|
|
|
public void SetMoveToTargetPosition(Vector3 position)
|
|
{
|
|
isTargetReached = false;
|
|
_moveTargetPosition = position;
|
|
}
|
|
|
|
public void SetLure(Lure lure)
|
|
{
|
|
this.lure = lure;
|
|
}
|
|
|
|
public void SetRandomizedMoveToTargetPosition(Vector3 originPosition)
|
|
{
|
|
isTargetReached = false;
|
|
_moveTargetPosition = originPosition + UnityEngine.Random.onUnitSphere * _getAreaDistance;
|
|
float value = Mathf.Clamp(_moveTargetPosition.y, base.transform.position.y - 2f, base.transform.position.y + 2f);
|
|
_moveTargetPosition.y = Mathf.Clamp(value, float.NegativeInfinity, -0.5f);
|
|
}
|
|
|
|
public void SeekUpdateHandler(float multiply = 1f)
|
|
{
|
|
_rbody.AddForce(_velocity, ForceMode.Acceleration);
|
|
TargetReachUpdate(lure ? 0.15f : 0.1f);
|
|
CalculateFishMovement(multiply);
|
|
CheckRaycastForAction();
|
|
LureDetectHandler();
|
|
}
|
|
|
|
public void LureEatUpdateHandler(float multiply = 1f)
|
|
{
|
|
_rbody.AddForce(_velocity, ForceMode.Acceleration);
|
|
TargetReachUpdate();
|
|
CalculateFishMovement(multiply);
|
|
CheckRaycastForAction();
|
|
}
|
|
|
|
public void FightUpdateHandler(float multiply = 1f)
|
|
{
|
|
_rbody.AddForce(_velocity, ForceMode.Acceleration);
|
|
TargetReachUpdate();
|
|
CalculateFishMovement(multiply);
|
|
}
|
|
|
|
private void TargetReachUpdate(float treshold = 0.1f)
|
|
{
|
|
distanceToTarget = Vector3.Distance(anchor.position, _moveTargetPosition);
|
|
isTargetReached = distanceToTarget < treshold;
|
|
if (isTargetReached)
|
|
{
|
|
_velocity = Vector3.zero;
|
|
}
|
|
}
|
|
|
|
private void CalculateFishMovement(float speedMultiplier = 1f)
|
|
{
|
|
_moveDirection = _moveTargetPosition - anchor.position;
|
|
if (_rbody.linearVelocity != Vector3.zero)
|
|
{
|
|
Quaternion b = Quaternion.LookRotation(_rbody.linearVelocity, Vector3.up);
|
|
base.transform.rotation = Quaternion.Slerp(base.transform.rotation, b, Time.deltaTime * Mathf.Clamp(5f * speedMultiplier, 5f, 10f));
|
|
}
|
|
Vector3 vector = _moveDirection.normalized * Mathf.Clamp(fishData.Speed, 0f, float.PositiveInfinity);
|
|
vector *= speedMultiplier;
|
|
_velocity = ((_velocity.sqrMagnitude > vector.sqrMagnitude) ? Vector3.Slerp(_velocity, vector, Time.deltaTime * 1f) : vector);
|
|
}
|
|
|
|
private void CheckRaycastForAction()
|
|
{
|
|
if (Physics.Raycast(anchor.position, _moveDirection, out var hitInfo, fishData.Speed, _layerCollisionMask))
|
|
{
|
|
int layer = hitInfo.collider.gameObject.layer;
|
|
if (layer == _terrainLayerMaskId)
|
|
{
|
|
_velocity = Vector3.zero;
|
|
isTargetReached = true;
|
|
lure = null;
|
|
SetCheckLureCooldown();
|
|
}
|
|
else if (layer == _fishLayerMaskId && hitInfo.transform.localScale.x > base.transform.localScale.x)
|
|
{
|
|
_velocity = _moveDirection.normalized * (fishData.Speed * 10f);
|
|
_moveTargetPosition = hitInfo.point + hitInfo.normal * _getAreaDistance;
|
|
_moveTargetPosition.y = base.transform.position.y;
|
|
lure = null;
|
|
SetCheckLureCooldown();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ResetBehaviour()
|
|
{
|
|
lure = null;
|
|
isTargetReached = false;
|
|
}
|
|
|
|
private void OnCollisionStay(Collision collision)
|
|
{
|
|
if (collision.gameObject.layer == _terrainLayerMaskId)
|
|
{
|
|
_moveTargetPosition += collision.contacts[0].normal.normalized;
|
|
}
|
|
if (!_waterBody.InWater && collision.gameObject.layer == _terrainLayerMaskId)
|
|
{
|
|
_rbody.AddForce(Vector3.up * 1f, ForceMode.Impulse);
|
|
}
|
|
}
|
|
|
|
private void LureDetectHandler()
|
|
{
|
|
if (!(Time.time < _CheckLureTime) && !lure && Physics.RaycastNonAlloc(base.transform.position, base.transform.forward, rayHits, fishData.EyeDetectionDistance, lureCheckLayerMask) > 0 && rayHits[0].transform.TryGetComponent<Lure>(out var component) && !component.IsFishConnected)
|
|
{
|
|
bool flag = false;
|
|
float num = length * 0.4f;
|
|
float num2 = length * 0.01f;
|
|
if (component.IsLure)
|
|
{
|
|
flag = fishData.CheckLure(component.LureData.ID);
|
|
}
|
|
if (component.IsBait)
|
|
{
|
|
flag = fishData.CheckBait(component.BaitData.ID);
|
|
}
|
|
if (component.lureSize < num && component.lureSize > num2 && flag)
|
|
{
|
|
lure = component;
|
|
isTargetReached = false;
|
|
_moveTargetPosition = component.transform.position;
|
|
Debug.Log($"Lure {component.name} size: {component.lureSize} detected by fish and accepted {base.gameObject.name} l: {length}");
|
|
}
|
|
else
|
|
{
|
|
onLureIsTooLargeForFish.Raise();
|
|
string text = ((component.lureSize >= num) ? "large" : "small");
|
|
Debug.Log($"Lure {component.name} is too {text} size: {component.lureSize} for fish: {base.gameObject.name} l: {length}");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SetCheckLureCooldown()
|
|
{
|
|
_CheckLureTime = Time.time + _CheckLureCooldown;
|
|
}
|
|
}
|