Files
Ultimate-Fishing-Simulator-…/Assets/Scripts/Assembly-CSharp/FishAI.cs
2026-03-04 09:37:33 +08:00

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;
}
}