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

107 lines
4.5 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 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();
}
}
}
}