using Opsive.BehaviorDesigner.Runtime.Tasks; using Opsive.GraphDesigner.Runtime.Variables; using Opsive.Shared.Utility; using UnityEngine; namespace Cielonos.MainGame.Characters.AI { public enum WeightCalculationMode { None, Coefficient, Curve } [Category("Cielonos")] [Description("检查能量是否足够。在开启权重计算后,可通过公式或曲线动态得出权重值,输出到共享变量用于自定义 Selector。")] public class CheckEnergy : AutomataConditionalBase { private AttributeSubmodule attributeSm; [Tooltip("需要消耗的目标能量值")] public SharedVariable energyCost; [Tooltip("除了当前消耗外,还需要额外保留的最低能量。若扣除消耗后能量小于保留值,则判定失败。")] public SharedVariable reserveEnergy; [Space(10)] [Tooltip("权重计算模式:无、系数线性计算、曲线非线性计算")] public WeightCalculationMode weightMode = WeightCalculationMode.None; [Tooltip("权重公式的放大系数。公式: 1 + (系数 * (当前能量/消耗能量 - 1))")] public SharedVariable weightCoefficient = 1.0f; [Tooltip("权重计算曲线。X轴为 当前能量/消耗能量 的比例(1及以上),Y轴为输出权重。")] public AnimationCurve weightCurve = new AnimationCurve(new Keyframe(1, 1), new Keyframe(5, 5)); [Tooltip("将计算得到的权重输出到该变量中,供其他自定义机制使用")] public SharedVariable outputWeight; public override void OnAwake() { base.OnAwake(); attributeSm = self.attributeSm; } public override TaskStatus OnUpdate() { if (!attributeSm.Has("Energy")) return TaskStatus.Failure; float currentEnergy = attributeSm["Energy"]; float cost = energyCost.Value; float reserve = reserveEnergy != null ? reserveEnergy.Value : 0f; // 检查能量是否足够,并且满足保留最低能量的阈值 if (currentEnergy >= cost && (currentEnergy - cost) >= reserve) { if (weightMode != WeightCalculationMode.None && outputWeight != null) { outputWeight.Value = CalculateWeight(currentEnergy, cost); } return TaskStatus.Success; } return TaskStatus.Failure; } private float CalculateWeight(float currentEnergy, float cost) { if (cost <= 0) return 1.0f; // 避免除以0,直接返回基础权重 float ratio = currentEnergy / cost; if (weightMode == WeightCalculationMode.Curve) { if (weightCurve != null) { return weightCurve.Evaluate(ratio); } return 1.0f; } else // Coefficient { return 1.0f + (weightCoefficient.Value * (ratio - 1.0f)); } } } }