sea-battle/Assets/Scripts/Pirate/PirateLoader.cs
2026-01-09 08:45:22 +03:00

256 lines
7.6 KiB
C#

using UnityEngine;
using UnityEngine.AI;
using System.Collections;
public class PirateLoader : PirateBehavior
{
public enum State { GoToCrate, PickUp, GoToCannon, LoadCannon }
public State currentState;
public State lastState;
[Header("Ññûëêè")]
public Transform ammoCrate;
public Cannon cannon;
[Header("ßäðî")]
public GameObject cannonBallPrefab;
public Transform handSocket;
private GameObject carriedBall;
[Header("Îãðàíè÷åíèå âðåìåíè")]
[Tooltip("Ìàêñèìàëüíàÿ äëèòåëüíîñòü çàäà÷è (ñåê). Ïî èñòå÷åíèè — ôîðñ-çàðÿäêà è âûêëþ÷åíèå.")]
public float maxTaskTime = 35f;
private float _deadline = float.PositiveInfinity;
private Vector3 currentTargetPosition;
private Vector3 lastPos;
private float stuckTimer;
public void ActivateWithTarget(Cannon targetCannon, Transform crate)
{
cannon = targetCannon;
ammoCrate = crate;
Activate(); // çàïóñê FSM
}
public override void Activate()
{
enabled = true;
if (pirate.agent != null)
pirate.agent.isStopped = false;
_deadline = maxTaskTime > 0f ? Time.time + maxTaskTime : float.PositiveInfinity;
currentState = State.GoToCrate;
lastState = State.GoToCrate - 1; // ÷òîáû ñðàáîòàë OnStateEnter
}
public override void Deactivate(bool interrupted = false)
{
StopAllCoroutines();
enabled = false;
if (pirate.agent != null)
pirate.agent.isStopped = true;
if (Animator != null)
{
Animator.SetBool("isWalking", false);
Animator.SetBool("isCarrying", false);
}
if (carriedBall != null)
{
Destroy(carriedBall);
carriedBall = null;
}
pirate?.ClearCurrentBehavior(this, interrupted);
}
void Update()
{
// --- Òàéìàóò çàäà÷è ---
if (Time.time >= _deadline)
{
Debug.LogWarning($"{name}: èñò¸ê ëèìèò {maxTaskTime:F0}s — ôîðñèðóåì ïåðåçàðÿäêó è âûêëþ÷àåìñÿ.");
_deadline = float.PositiveInfinity;
if(carriedBall != null) currentState = State.LoadCannon;
else
{
cannon?.OnReloadComplete();
Deactivate();
}
return; // Deactivate óæå âûçâàí
}
if (currentState != lastState)
{
OnStateEnter(currentState);
lastState = currentState;
}
// Ïðîâåðêà çàñòðåâàíèÿ (áûñòðûé ðåïàô)
if ((transform.position - lastPos).sqrMagnitude < 0.001f)
{
stuckTimer += Time.deltaTime;
if (stuckTimer > 2f && pirate.agent != null)
{
Debug.LogWarning($"{name} çàñòðÿë, ïåðåñ÷èòûâàåì ïóòü");
pirate.agent.ResetPath();
pirate.agent.SetDestination(currentTargetPosition);
stuckTimer = 0f;
}
}
else
{
stuckTimer = 0f;
}
lastPos = transform.position;
// Ïðîâåðêà äîñòèæåíèÿ öåëè
switch (currentState)
{
case State.GoToCrate:
if (!pirate.agent.pathPending && pirate.agent.remainingDistance <= pirate.agent.stoppingDistance)
currentState = State.PickUp;
break;
case State.GoToCannon:
if (!pirate.agent.pathPending && pirate.agent.remainingDistance <= pirate.agent.stoppingDistance)
currentState = State.LoadCannon;
break;
}
// Ïðîâåðêà âàëèäíîñòè ïóòè
if (pirate.agent != null &&
(pirate.agent.pathStatus == NavMeshPathStatus.PathInvalid || pirate.agent.pathStatus == NavMeshPathStatus.PathPartial))
{
Debug.LogWarning($"{name} èìååò íåâàëèäíûé ïóòü, èùåì áëèæàéøóþ òî÷êó íà NavMesh");
if (NavMesh.SamplePosition(currentTargetPosition, out NavMeshHit hit, 2f, NavMesh.AllAreas))
{
pirate.agent.SetDestination(hit.position);
}
else
{
Debug.LogWarning($"{name} íå ìîæåò äîñòè÷ü öåëè, ïðåðûâàåì çàäà÷ó");
FailAndStop();
}
}
}
void OnStateEnter(State state)
{
switch (state)
{
case State.GoToCrate:
if (ammoCrate == null) { FailAndStop(); return; }
Animator.SetBool("isWalking", true);
Animator.SetBool("isCarrying", false);
currentTargetPosition = ammoCrate.position;
pirate.agent.SetDestination(currentTargetPosition);
break;
case State.PickUp:
Animator.SetBool("isWalking", false);
Animator.SetTrigger("PickUpTrigger");
break;
case State.GoToCannon:
if (cannon == null) { FailAndStop(); return; }
Animator.SetBool("isWalking", true);
Animator.SetBool("isCarrying", true);
Transform targetPoint = cannon.GetNearestReloadPoint(transform.position);
currentTargetPosition = targetPoint != null ? targetPoint.position : cannon.transform.position;
pirate.agent.SetDestination(currentTargetPosition);
break;
case State.LoadCannon:
Animator.SetBool("isWalking", false);
Animator.SetTrigger("LoadCannonTrigger");
break;
}
}
// --- Animation Events ---
public void OnGrabBall()
{
if (!enabled || !gameObject.activeInHierarchy) return;
if (carriedBall == null && cannonBallPrefab != null && handSocket != null)
{
carriedBall = Instantiate(cannonBallPrefab, handSocket);
carriedBall.transform.localPosition = new Vector3(-0.307f, -0.423f, 0.008f);
carriedBall.transform.localRotation = Quaternion.identity;
}
currentState = State.GoToCannon;
// Åñëè íóæíî ñ÷èòàòü òàéìåð ñ ìîìåíòà âçÿòèÿ ÿäðà, ðàñêîììåíòèðóé:
// _deadline = Time.time + maxTaskTime;
}
public void OnLoadCannon()
{
if (!isActiveAndEnabled) return;
if (carriedBall != null)
{
Transform target = cannon != null ? cannon.reloadTarget : null;
if (target != null)
StartCoroutine(MoveCannonBallToTarget(carriedBall, target.position, 0.5f, cannon));
else
{
Destroy(carriedBall);
carriedBall = null;
cannon?.OnReloadComplete();
Deactivate(false);
}
}
else
{
Deactivate(false);
}
}
private IEnumerator MoveCannonBallToTarget(GameObject ball, Vector3 targetPos, float duration, Cannon targetCannon)
{
if (ball == null) yield break;
Vector3 startPos = ball.transform.position;
float elapsed = 0f;
float height = 1.5f;
while (elapsed < duration)
{
float t = elapsed / duration;
Vector3 currentPos = Vector3.Lerp(startPos, targetPos, t);
currentPos.y += 4 * height * t * (1 - t);
ball.transform.position = currentPos;
elapsed += Time.deltaTime;
yield return null;
}
ball.transform.position = targetPos;
Destroy(ball);
targetCannon?.OnReloadComplete();
Deactivate(false);
}
// === Ôîðñ-çàâåðøåíèå ïî òàéìàóòó ===
private void FailAndStop()
{
Debug.LogWarning($"{name} íå ñìîã âûïîëíèòü çàäà÷ó çàãðóçêè.");
Deactivate(true);
}
}