117 lines
3.6 KiB
C#
117 lines
3.6 KiB
C#
|
|
using System.Collections.Generic;
|
|||
|
|
using Sirenix.OdinInspector;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
namespace SLSUtilities.General
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 一个复合布尔值类,支持多来源修改和优先级系统。
|
|||
|
|
/// 可以将多个来源对布尔值的修改综合起来,由高优先级的修改决定最终结果。
|
|||
|
|
/// </summary>
|
|||
|
|
[InlineProperty]
|
|||
|
|
[HideReferenceObjectPicker]
|
|||
|
|
public class CompoundBool
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 返回当前生效优先级层级的计数。
|
|||
|
|
/// </summary>
|
|||
|
|
[ShowInInspector]
|
|||
|
|
[LabelText("True Count"), LabelWidth(70)]
|
|||
|
|
[HorizontalGroup("Stats", Width = 100)]
|
|||
|
|
public int TrueCount => GetEffectiveCount();
|
|||
|
|
|
|||
|
|
private SortedList<int, int> counts = new SortedList<int, int>();
|
|||
|
|
private bool isDirty = true;
|
|||
|
|
private bool cachedValue;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取最终计算出的布尔值。
|
|||
|
|
/// </summary>
|
|||
|
|
[ShowInInspector]
|
|||
|
|
[LabelText("Value"), LabelWidth(50)]
|
|||
|
|
[HorizontalGroup("Stats", Width = 100)]
|
|||
|
|
public bool Value
|
|||
|
|
{
|
|||
|
|
get
|
|||
|
|
{
|
|||
|
|
if (isDirty) RecalculateValue();
|
|||
|
|
return cachedValue;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 初始化 CompoundBool。
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="initialValue">初始值。如果为 true,将在优先级 0 初始化计数为 1。</param>
|
|||
|
|
public CompoundBool(bool initialValue = false)
|
|||
|
|
{
|
|||
|
|
if (initialValue) Modify(true, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 在指定的优先级层级修改布尔值。
|
|||
|
|
/// 高优先级的值会覆盖低优先级的值。
|
|||
|
|
/// 如果某个非零优先级的计数变为零,将自动移除该优先级层级。
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="marker">修改意图(true 增加计数,false 减少计数)。</param>
|
|||
|
|
/// <param name="priority">优先级,默认为 0。数字越大优先级越高。</param>
|
|||
|
|
public void Modify(bool marker, int priority = 0)
|
|||
|
|
{
|
|||
|
|
if (counts.TryGetValue(priority, out int currentCount))
|
|||
|
|
{
|
|||
|
|
counts[priority] = marker ? currentCount + 1 : currentCount - 1;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
counts.Add(priority, marker ? 1 : -1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(priority != 0 && counts[priority] == 0)
|
|||
|
|
{
|
|||
|
|
counts.Remove(priority);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
isDirty = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 重置所有修改,恢复到默认状态(false)。
|
|||
|
|
/// </summary>
|
|||
|
|
public void Reset()
|
|||
|
|
{
|
|||
|
|
counts.Clear();
|
|||
|
|
isDirty = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void RecalculateValue()
|
|||
|
|
{
|
|||
|
|
// 从最高优先级(列表末尾)向最低优先级迭代
|
|||
|
|
for (int i = counts.Count - 1; i >= 0; i--)
|
|||
|
|
{
|
|||
|
|
int count = counts.Values[i];
|
|||
|
|
if (count != 0)
|
|||
|
|
{
|
|||
|
|
cachedValue = count > 0;
|
|||
|
|
isDirty = false;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果所有计数都为零或列表为空,则默认为 false
|
|||
|
|
cachedValue = false;
|
|||
|
|
isDirty = false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private int GetEffectiveCount()
|
|||
|
|
{
|
|||
|
|
// 从最高优先级向最低优先级迭代
|
|||
|
|
for (int i = counts.Count - 1; i >= 0; i--)
|
|||
|
|
{
|
|||
|
|
int count = counts.Values[i];
|
|||
|
|
if (count != 0) return count;
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|