107 lines
4.5 KiB
C#
107 lines
4.5 KiB
C#
|
|
using Opsive.BehaviorDesigner.Runtime.Tasks;
|
|||
|
|
using Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals;
|
|||
|
|
using Opsive.GraphDesigner.Runtime;
|
|||
|
|
using Opsive.GraphDesigner.Runtime.Variables;
|
|||
|
|
using Opsive.Shared.Utility;
|
|||
|
|
using SLSUtilities.General;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
namespace Cielonos.MainGame.Characters.AI
|
|||
|
|
{
|
|||
|
|
[Description("使用伪随机分布(PRD/稳定概率)进行掷骰判定。连续判定失败会提升下次触发几率,判定成功后重置。用于防脸黑与连爆,制造更为平滑均匀的“伪随机”发生感。")]
|
|||
|
|
[NodeIcon("69bf50f8923f54c4c8bb8e258883a411", "6c5770241610a4c4aae4ac3af0ac8bf8")]
|
|||
|
|
[Category("Cielonos")]
|
|||
|
|
public class StableRandomProbability : Conditional
|
|||
|
|
{
|
|||
|
|
[Tooltip("当前节点期望判定的成功概率(0~1)。")]
|
|||
|
|
public SharedVariable<float> successProbability = 0.25f;
|
|||
|
|
|
|||
|
|
[Tooltip("是否启用跨节点共享概率机制。启用后,多个绑定了同一 SharedStableProbability 变量的 StableRandomProbability 节点将共享同一个 N 计数(但可独立设定各自的目标概率 P)。如果不启用,则每个节点独立追踪自己的 N 计数。")]
|
|||
|
|
public bool useSharedProbability = false;
|
|||
|
|
|
|||
|
|
[Tooltip("【可选】跨节点共享状态槽。如果需要多个不同的判定节点(如:连续3次不同的普攻)共享同一个失败累计次数 N,请绑定同一个 SharedStableProbability 变量")]
|
|||
|
|
public SharedVariable<StableProbability> sharedStableProbability;
|
|||
|
|
|
|||
|
|
[Tooltip("冷却时间(秒)。在此期间内如果节点被每帧重复求值(由于条件打断 Lower Priority/Both),将直接返回上一次的判定结果,不会进行新的掷骰。配置为 0 则不使用冷却。")]
|
|||
|
|
public SharedVariable<float> rollCooldown = 0.5f;
|
|||
|
|
|
|||
|
|
private float _lastRollTime = -999f;
|
|||
|
|
private bool _lastResult = false;
|
|||
|
|
|
|||
|
|
private StableProbability _internalProbability;
|
|||
|
|
|
|||
|
|
public override void OnAwake()
|
|||
|
|
{
|
|||
|
|
// 如果用户没有绑定共享变量,或者绑定了但由于某种原因无法引用
|
|||
|
|
if (!useSharedProbability)
|
|||
|
|
{
|
|||
|
|
// 创建此节点私有的稳定概率对象
|
|||
|
|
_internalProbability = new StableProbability(successProbability.Value);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// 如果绑定了共享变量,但在整棵树第一次唤醒时尚未初始化其值实例,则由此节点代为创建
|
|||
|
|
if (sharedStableProbability.Value == null)
|
|||
|
|
{
|
|||
|
|
sharedStableProbability.Value = new StableProbability(successProbability.Value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override TaskStatus OnUpdate()
|
|||
|
|
{
|
|||
|
|
if (rollCooldown != null && rollCooldown.Value > 0f)
|
|||
|
|
{
|
|||
|
|
if (Time.time - _lastRollTime < rollCooldown.Value)
|
|||
|
|
{
|
|||
|
|
return _lastResult ? TaskStatus.Success : TaskStatus.Failure;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
StableProbability prdInstance = null;
|
|||
|
|
|
|||
|
|
if (useSharedProbability && sharedStableProbability.Value != null)
|
|||
|
|
{
|
|||
|
|
prdInstance = sharedStableProbability.Value;
|
|||
|
|
// 实时更新外接共享实例的期望概率 (防止外部在游戏运行中用其他 Action 更改了目标百分比)
|
|||
|
|
prdInstance.Probability = successProbability.Value;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
prdInstance = _internalProbability;
|
|||
|
|
if (prdInstance != null)
|
|||
|
|
{
|
|||
|
|
prdInstance.Probability = successProbability.Value;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (prdInstance == null)
|
|||
|
|
{
|
|||
|
|
return TaskStatus.Failure;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 执行 Roll 判定并自动增加 N 计数 / 重置 N 计数
|
|||
|
|
Debug.Log($"当前实际概率: {prdInstance.C * prdInstance.N:F2}");
|
|||
|
|
bool isSuccess = prdInstance.Roll();
|
|||
|
|
_lastResult = isSuccess;
|
|||
|
|
_lastRollTime = Time.time;
|
|||
|
|
return isSuccess ? TaskStatus.Success : TaskStatus.Failure;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override void Reset()
|
|||
|
|
{
|
|||
|
|
base.Reset();
|
|||
|
|
successProbability = 0.25f;
|
|||
|
|
rollCooldown = 0.5f;
|
|||
|
|
_lastRollTime = -999f;
|
|||
|
|
_lastResult = false;
|
|||
|
|
useSharedProbability = false;
|
|||
|
|
sharedStableProbability = null;
|
|||
|
|
if (_internalProbability != null)
|
|||
|
|
{
|
|||
|
|
_internalProbability.Reset();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|