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 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() : MainGameManager.Player; } public override void OnStart() { successPlayed = funcAnimSm.Play(animationName); frameBuffer = false; startTime = Time.time; if (successPlayed) { funcAnim = funcAnimSm.currentRuntimeFuncAnim; if (willTurnToTarget) { self.movementSc.SmartTurnToTarget(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; } } }