2026-03-20 12:07:44 -04:00
|
|
|
|
using System.Collections.Generic;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
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;
|
|
|
|
|
|
|
2025-12-08 05:27:53 -05:00
|
|
|
|
namespace Cielonos.MainGame.Characters.AI
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2026-03-20 12:07:44 -04:00
|
|
|
|
public enum PlayLoopReturnMode
|
|
|
|
|
|
{
|
|
|
|
|
|
ReturnImmediately,
|
|
|
|
|
|
WaitForDuration
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Description("播放一个循环类型的功能动画,并可选择是立刻返回成功,还是等待规定时间后再返回成功。")]
|
2025-11-25 08:19:33 -05:00
|
|
|
|
[NodeIcon("Assets/Sprites/Icon/Play.png")]
|
|
|
|
|
|
[Category("Cielonos")]
|
2026-03-20 12:07:44 -04:00
|
|
|
|
public class PlayLoopFuncAnim : AutomataActionBase
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2025-12-08 05:27:53 -05:00
|
|
|
|
protected CharacterBase target;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
[Tooltip("是否选择其他目标,默认目标为玩家。")]
|
|
|
|
|
|
public bool isOtherTarget = false;
|
|
|
|
|
|
[Tooltip("如果选择了其他目标,则需要指定目标对象。")]
|
|
|
|
|
|
public SharedVariable<GameObject> targetGameObject;
|
|
|
|
|
|
|
2025-12-08 05:27:53 -05:00
|
|
|
|
private AnimationSubcontrollerBase animationSc => self.animationSc;
|
|
|
|
|
|
private FunctionalAnimationSubmodule funcAnimSm;
|
|
|
|
|
|
private RuntimeFuncAnim funcAnim;
|
|
|
|
|
|
|
2025-11-25 08:19:33 -05:00
|
|
|
|
[Header("Animation Settings")]
|
2026-03-20 12:07:44 -04:00
|
|
|
|
[Tooltip("要播放的功能动画名称。必须是循环动画。")]
|
2025-11-25 08:19:33 -05:00
|
|
|
|
public string animationName;
|
|
|
|
|
|
[Tooltip("是否选择其他功能动画子模块,默认子模块为全身动作子模块。")]
|
|
|
|
|
|
public bool isOtherFuncAnimSm = false;
|
|
|
|
|
|
[Tooltip("如果选择了其他功能动画子模块,则需要指定子模块名称。")]
|
|
|
|
|
|
public string funcAnimSmName = "";
|
2026-03-20 12:07:44 -04:00
|
|
|
|
|
|
|
|
|
|
[Header("Return Mode")]
|
|
|
|
|
|
[Tooltip("节点返回模式:\nReturnImmediately: 播放动画后立即结束节点并返回 Success。\nWaitForDuration: 播放动画并在指定时间段内返回 Running,时间结束后返回 Success。")]
|
|
|
|
|
|
public PlayLoopReturnMode returnMode = PlayLoopReturnMode.ReturnImmediately;
|
|
|
|
|
|
[Tooltip("播放持续时间(秒)。仅在 WaitForDuration 模式下有效。")]
|
|
|
|
|
|
public float playDuration = 2f;
|
|
|
|
|
|
|
|
|
|
|
|
[Header("Behaviors")]
|
2025-11-25 08:19:33 -05:00
|
|
|
|
[Tooltip("是否在播放动画时转向目标。")]
|
|
|
|
|
|
public bool willTurnToTarget = true;
|
|
|
|
|
|
[Tooltip("是否调整根吸附以贴近目标。")]
|
|
|
|
|
|
public bool willAdjustAdsorption = true;
|
|
|
|
|
|
[Tooltip("根吸附调整的最小距离。")]
|
|
|
|
|
|
public float adsorptionMinDistance = 2;
|
2025-12-08 05:27:53 -05:00
|
|
|
|
|
|
|
|
|
|
[Header("Other Settings")]
|
|
|
|
|
|
[Tooltip("是否记录此动作到动作记录子模块中。")]
|
|
|
|
|
|
public bool willRecordAction = true;
|
2026-03-20 12:07:44 -04:00
|
|
|
|
[Tooltip("如果动画在外力干预下被打断,是否当作执行成功。")]
|
|
|
|
|
|
public bool disruptionReturnSuccess = true;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
|
|
|
|
|
|
private bool successPlayed = false;
|
2026-03-20 12:07:44 -04:00
|
|
|
|
private bool frameBuffer;
|
|
|
|
|
|
private float startTime;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
|
|
|
|
|
|
public override void OnAwake()
|
|
|
|
|
|
{
|
2025-12-08 05:27:53 -05:00
|
|
|
|
base.OnAwake();
|
2025-11-25 08:19:33 -05:00
|
|
|
|
funcAnimSm = isOtherFuncAnimSm ? null : animationSc.fullBodyFuncAnimSm;
|
|
|
|
|
|
target = isOtherTarget ? targetGameObject.Value.GetComponent<CharacterBase>() : MainGameManager.Player;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void OnStart()
|
|
|
|
|
|
{
|
|
|
|
|
|
successPlayed = funcAnimSm.Play(animationName);
|
2026-03-20 12:07:44 -04:00
|
|
|
|
frameBuffer = false;
|
|
|
|
|
|
startTime = Time.time;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
|
|
|
|
|
|
if (successPlayed)
|
|
|
|
|
|
{
|
2026-03-20 12:07:44 -04:00
|
|
|
|
funcAnim = funcAnimSm.currentRuntimeFuncAnim;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
|
|
|
|
|
|
if (willTurnToTarget)
|
|
|
|
|
|
{
|
|
|
|
|
|
self.movementSc.TurnToTarget(target);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (willAdjustAdsorption)
|
|
|
|
|
|
{
|
2026-02-13 09:22:11 -05:00
|
|
|
|
funcAnim.AddUpdateUntilEvent(new SetRootAdsorptionAdjustment.Once(target, adsorptionMinDistance));
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
2025-12-08 05:27:53 -05:00
|
|
|
|
|
|
|
|
|
|
if (willRecordAction)
|
|
|
|
|
|
{
|
|
|
|
|
|
self.actionRecordSm.AddRecord(animationName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override TaskStatus OnUpdate()
|
|
|
|
|
|
{
|
2026-03-20 12:07:44 -04:00
|
|
|
|
// 播放失败时的 1 帧缓冲返回
|
2025-11-25 08:19:33 -05:00
|
|
|
|
if (!successPlayed)
|
|
|
|
|
|
{
|
2026-03-20 12:07:44 -04:00
|
|
|
|
if (!frameBuffer)
|
2025-12-08 05:27:53 -05:00
|
|
|
|
{
|
2026-03-20 12:07:44 -04:00
|
|
|
|
frameBuffer = true;
|
2025-12-08 05:27:53 -05:00
|
|
|
|
return TaskStatus.Running;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return TaskStatus.Failure;
|
|
|
|
|
|
}
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
2026-03-20 12:07:44 -04:00
|
|
|
|
|
|
|
|
|
|
// 被外部干预打断或覆盖时的 1 帧缓冲返回
|
|
|
|
|
|
if (funcAnim.isDisrupted || funcAnimSm.currentRuntimeFuncAnim != funcAnim)
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2026-03-20 12:07:44 -04:00
|
|
|
|
if (!frameBuffer)
|
|
|
|
|
|
{
|
|
|
|
|
|
frameBuffer = true;
|
|
|
|
|
|
return TaskStatus.Running;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return disruptionReturnSuccess ? TaskStatus.Success : TaskStatus.Failure;
|
|
|
|
|
|
}
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-20 12:07:44 -04:00
|
|
|
|
// 根据返回模式判定
|
|
|
|
|
|
if (returnMode == PlayLoopReturnMode.ReturnImmediately)
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2026-03-20 12:07:44 -04:00
|
|
|
|
if (!frameBuffer)
|
|
|
|
|
|
{
|
|
|
|
|
|
frameBuffer = true;
|
|
|
|
|
|
return TaskStatus.Running;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
|
|
|
|
|
return TaskStatus.Success;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-20 12:07:44 -04:00
|
|
|
|
else if (returnMode == PlayLoopReturnMode.WaitForDuration)
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2026-03-20 12:07:44 -04:00
|
|
|
|
if (Time.time - startTime >= playDuration)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!frameBuffer)
|
|
|
|
|
|
{
|
|
|
|
|
|
frameBuffer = true;
|
|
|
|
|
|
return TaskStatus.Running;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return TaskStatus.Success;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return TaskStatus.Running;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-20 12:07:44 -04:00
|
|
|
|
}
|