256 lines
7.6 KiB
C#
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);
|
|
}
|
|
}
|