Files
Cielonos/Assets/Scripts/MainGame/Characters/Automata/AI/Actions/PlayLoopFuncAnim.cs
SoulliesOfficial f26f9fd374 爆更
2026-03-20 12:07:44 -04:00

164 lines
5.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using Cielonos.MainGame.Characters;
using Cielonos.MainGame.FunctionalAnimation;
using Opsive.BehaviorDesigner.Runtime.Tasks;
using Opsive.BehaviorDesigner.Runtime.Tasks.Actions;
using Opsive.GraphDesigner.Runtime;
using Opsive.GraphDesigner.Runtime.Variables;
using Opsive.Shared.Utility;
using SLSUtilities.FunctionalAnimation;
using UnityEngine;
namespace Cielonos.MainGame.Characters.AI
{
public enum PlayLoopReturnMode
{
ReturnImmediately,
WaitForDuration
}
[Description("播放一个循环类型的功能动画,并可选择是立刻返回成功,还是等待规定时间后再返回成功。")]
[NodeIcon("Assets/Sprites/Icon/Play.png")]
[Category("Cielonos")]
public class PlayLoopFuncAnim : AutomataActionBase
{
protected CharacterBase target;
[Tooltip("是否选择其他目标,默认目标为玩家。")]
public bool isOtherTarget = false;
[Tooltip("如果选择了其他目标,则需要指定目标对象。")]
public SharedVariable<GameObject> targetGameObject;
private AnimationSubcontrollerBase animationSc => self.animationSc;
private FunctionalAnimationSubmodule funcAnimSm;
private RuntimeFuncAnim funcAnim;
[Header("Animation Settings")]
[Tooltip("要播放的功能动画名称。必须是循环动画。")]
public string animationName;
[Tooltip("是否选择其他功能动画子模块,默认子模块为全身动作子模块。")]
public bool isOtherFuncAnimSm = false;
[Tooltip("如果选择了其他功能动画子模块,则需要指定子模块名称。")]
public string funcAnimSmName = "";
[Header("Return Mode")]
[Tooltip("节点返回模式:\nReturnImmediately: 播放动画后立即结束节点并返回 Success。\nWaitForDuration: 播放动画并在指定时间段内返回 Running时间结束后返回 Success。")]
public PlayLoopReturnMode returnMode = PlayLoopReturnMode.ReturnImmediately;
[Tooltip("播放持续时间(秒)。仅在 WaitForDuration 模式下有效。")]
public float playDuration = 2f;
[Header("Behaviors")]
[Tooltip("是否在播放动画时转向目标。")]
public bool willTurnToTarget = true;
[Tooltip("是否调整根吸附以贴近目标。")]
public bool willAdjustAdsorption = true;
[Tooltip("根吸附调整的最小距离。")]
public float adsorptionMinDistance = 2;
[Header("Other Settings")]
[Tooltip("是否记录此动作到动作记录子模块中。")]
public bool willRecordAction = true;
[Tooltip("如果动画在外力干预下被打断,是否当作执行成功。")]
public bool disruptionReturnSuccess = true;
private bool successPlayed = false;
private bool frameBuffer;
private float startTime;
public override void OnAwake()
{
base.OnAwake();
funcAnimSm = isOtherFuncAnimSm ? null : animationSc.fullBodyFuncAnimSm;
target = isOtherTarget ? targetGameObject.Value.GetComponent<CharacterBase>() : MainGameManager.Player;
}
public override void OnStart()
{
successPlayed = funcAnimSm.Play(animationName);
frameBuffer = false;
startTime = Time.time;
if (successPlayed)
{
funcAnim = funcAnimSm.currentRuntimeFuncAnim;
if (willTurnToTarget)
{
self.movementSc.TurnToTarget(target);
}
if (willAdjustAdsorption)
{
funcAnim.AddUpdateUntilEvent(new SetRootAdsorptionAdjustment.Once(target, adsorptionMinDistance));
}
if (willRecordAction)
{
self.actionRecordSm.AddRecord(animationName);
}
}
}
public override TaskStatus OnUpdate()
{
// 播放失败时的 1 帧缓冲返回
if (!successPlayed)
{
if (!frameBuffer)
{
frameBuffer = true;
return TaskStatus.Running;
}
else
{
return TaskStatus.Failure;
}
}
// 被外部干预打断或覆盖时的 1 帧缓冲返回
if (funcAnim.isDisrupted || funcAnimSm.currentRuntimeFuncAnim != funcAnim)
{
if (!frameBuffer)
{
frameBuffer = true;
return TaskStatus.Running;
}
else
{
return disruptionReturnSuccess ? TaskStatus.Success : TaskStatus.Failure;
}
}
// 根据返回模式判定
if (returnMode == PlayLoopReturnMode.ReturnImmediately)
{
if (!frameBuffer)
{
frameBuffer = true;
return TaskStatus.Running;
}
else
{
return TaskStatus.Success;
}
}
else if (returnMode == PlayLoopReturnMode.WaitForDuration)
{
if (Time.time - startTime >= playDuration)
{
if (!frameBuffer)
{
frameBuffer = true;
return TaskStatus.Running;
}
else
{
return TaskStatus.Success;
}
}
}
return TaskStatus.Running;
}
}
}