Merge branch 'develop' into feature/yingli1fic

This commit is contained in:
Ovid
2025-08-02 18:02:30 +08:00
26 changed files with 3123 additions and 2891 deletions
@@ -3,7 +3,6 @@ using UnityEngine.Localization.Settings;
using Yarn.Unity;
using AibisDream.Framework;
using AibisDream.Utility;
using UnityEngine;
namespace AibisDream
{
@@ -1,24 +1,40 @@
using UnityEngine;
using System;
using AibisDream.Kit;
using DG.Tweening;
using TMPro;
using UnityEngine;
namespace AibisDream.FixSystem
{
public class MoleModule : BodyModule
{
private static WhackMoleSystem WhackMoleSystem => FixSystemCenter.SystemDic.Get<WhackMoleSystem>();
#region
private Material _picMaterial;
private TMP_Text _screenText;
private SpriteRenderer _processBar;
#endregion
public bool isInMoleGame;
public bool isLightOn;
private static readonly int SineGlowFade = Shader.PropertyToID("_SineGlowFade");
private static readonly int AddColorFade = Shader.PropertyToID("_AddColorFade");
private static readonly int AddColorColor = Shader.PropertyToID("_AddColorColor");
private float _countDownPct;
private Tween _countDownTween;
public event Action<MoleModule, bool> OnLightMoleEnd;
protected override void InitReference()
{
base.InitReference();
_picMaterial = transform.Find("Module Pic").GetComponent<SpriteRenderer>().material;
_screenText = transform.Find("Screen Text").GetComponent<TMP_Text>();
_processBar = transform.Find("Process Bar").GetComponent<SpriteRenderer>();
}
// 重写PlugIn和PlugOut就好了
public override void PlugIn()
{
@@ -26,13 +42,13 @@ namespace AibisDream.FixSystem
{
base.PlugIn();
}
else
else if (isLightOn)
{
// 触发WhackMoleSystem的插入事件
WhackMoleSystem.OnPlugIn(data.moduleName);
// 打中了
HitMole();
}
}
public override void PlugOut()
{
// TODO 拔出来会有效果吗?存疑
@@ -42,23 +58,78 @@ namespace AibisDream.FixSystem
public void StartFlicker()
{
_screenText.text = "Checking...";
_picMaterial.SetFloat(SineGlowFade, 1);
}
public void StopFlicker()
{
_picMaterial.SetFloat(SineGlowFade, 0);
}
public void LightOn(Color color)
public void LightOn(float lightTime)
{
_picMaterial.SetColor(AddColorColor, color);
// 视觉部分
StartFlicker();
_picMaterial.SetColor(AddColorColor, Color.red);
_picMaterial.SetFloat(AddColorFade, 1);
_processBar.color = Color.red;
_processBar.transform.localScale = Vector3.one;
// 逻辑部分
isLightOn = true;
_countDownPct = 100;
_countDownTween = DOTween.To(() => _countDownPct, value => _countDownPct = value, 0, lightTime)
.OnUpdate(CountingDown)
.OnComplete(OverTime);
}
public void LightOff()
private void CountingDown()
{
// TODO 显示倒计时
_screenText.text = $"{_countDownPct:F1}%";
_processBar.transform.localScale = new Vector3(_countDownPct / 100, 1, 1);
}
private void OverTime()
{
// TODO 超时
isLightOn = false;
LightOff();
OnLightMoleEnd?.Invoke(this, false);
OnLightMoleEnd = null;
_countDownTween = null;
}
private void LightOff()
{
_picMaterial.SetFloat(AddColorFade, 0);
_processBar.color = Color.clear;
// TODO 继续闪烁
StartFlicker();
}
private void HitMole()
{
_countDownTween.Kill();
isLightOn = false;
// 命中后成功反馈
ActionKit.Sequence()
.Callback(() =>
{
if (ColorUtility.TryParseHtmlString("#67C23A", out var color))
{
_picMaterial.SetColor(AddColorColor, color);
}
})
.Callback(() => _processBar.color = Color.green)
.Callback(() => _screenText.text = "Success")
.Delay(0.7f)
.Callback(LightOff)
.Start(this);
OnLightMoleEnd?.Invoke(this, true);
OnLightMoleEnd = null;
}
#endregion
@@ -6,23 +6,26 @@ namespace AibisDream.FixSystem
[CreateAssetMenu(fileName = "WhackMoldData", menuName = "Level Data/WhackMoldData")]
public class WhackMoleData : ScriptableObject
{
public WhackMoleNode[] nodes;
[Header("基本参数")]
public float moleExistTime = 1f;
public int flickerFreq = 10;
public Vector2 batchDuration = new(2, 3);
public int totalBatchNum = 5;
public float batchGap = 1f;
[Header("批次序列")]
public WhackMoleBatch[] batches;
public WhackMoleBatch GetBatch(int index)
{
return index >= batches.Length ? batches[^1] : batches[index];
}
}
[Serializable]
public struct WhackMoleNode
public struct WhackMoleBatch
{
public WhackMoleCommand command;
public string moduleName;
public float flickerTime;
public float lightOnTime;
}
public enum WhackMoleCommand
{
SingleModuleLightOn,
MultipleModuleLightOn,
SingleModuleColorOn,
MultipleModuleColorOn
public int moleNum;
public Vector2 durationRange;
}
}
@@ -1,269 +1,166 @@
using System;
using System.Collections;
using System.Collections.Generic;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEngine;
using UnityEngine.Events;
using Random = UnityEngine.Random;
namespace AibisDream.FixSystem
{
public class WhackMoleHandler
{
private readonly MonoBehaviour _mono;
private AbsWhackMoleNodeHandler _nodeHandler;
private static readonly WhackMoleSystem WhackMoleSystem = FixSystemCenter.SystemDic.Get<WhackMoleSystem>();
public event Action<bool> OnGameEnd;
private readonly WhackMoleData _data;
private WhackMoleHandler(MonoBehaviour mono)
#region
private int _batchIdx;
private readonly Dictionary<string, MoleModule> _moleModules;
private readonly List<WhackMoleBatchHandler> _batchHandlers;
private WhackMoleRes _res;
public event Action<WhackMoleRes> OnGameEnd;
#endregion
public WhackMoleHandler(WhackMoleData data)
{
_mono = mono;
_data = data;
_batchIdx = 0;
_moleModules = WhackMoleSystem.MoleModules;
// 生成batch序列并链接
_batchHandlers = CreateBatchHandler(data);
// 统计一些基本数据
CalcBaseData();
}
public void OnPlugIn(string moduleName)
private void CalcBaseData()
{
_nodeHandler.OnPlugIn(moduleName);
}
public void OnPlugOut(string moduleName)
{
_nodeHandler.OnPlugOut(moduleName);
}
public void StartGame()
{
Handle();
}
private void Handle()
{
_nodeHandler.onHandleEnd.AddListener(OnHandleEnd);
_mono.StartCoroutine(_nodeHandler.Handle());
}
private void OnHandleEnd(bool isSuccess)
{
if (isSuccess)
_res.totalMoleBatch = _data.totalBatchNum;
for (int i = 0; i < _data.totalBatchNum; i++)
{
// TODO 进入下一关
_nodeHandler.onHandleEnd.RemoveAllListeners();
if (_nodeHandler.nextHandler != null)
{
_nodeHandler = _nodeHandler.nextHandler;
Handle();
}
else
{
OnGameEnd?.Invoke(true);
OnGameEnd = null;
}
}
else
{
// TODO 进入失败结局
OnGameEnd?.Invoke(false);
OnGameEnd = null;
_res.totalMoleNum += _data.GetBatch(i).moleNum;
}
}
public static WhackMoleHandler Create(WhackMoleData data, MonoBehaviour mono)
public void Start()
{
var res = new WhackMoleHandler(mono);
AbsWhackMoleNodeHandler lastHandler = null;
foreach (var node in data.nodes)
foreach (var mole in _moleModules.Values)
{
var handler = res.CreateNodeHandler(node);
res._nodeHandler ??= handler;
if (lastHandler != null)
{
lastHandler.nextHandler = handler;
}
mole.isInMoleGame = true;
}
WhackMoleSystem.StartAllFlicker();
ActionKit.Coroutine(_batchHandlers[_batchIdx].StartBatch).StartGlobal();
}
lastHandler = handler;
private List<WhackMoleBatchHandler> CreateBatchHandler(WhackMoleData data)
{
List<WhackMoleBatchHandler> res = new();
for (int i = 0; i < data.totalBatchNum; i++)
{
var curHandler = new WhackMoleBatchHandler(_moleModules.Values, data, i);
curHandler.OnBatchEnd += OnBatchEnd;
res.Add(curHandler);
}
return res;
}
private AbsWhackMoleNodeHandler CreateNodeHandler(WhackMoleNode node)
private void OnBatchEnd(int hitMoleNum)
{
AbsWhackMoleNodeHandler handler = node.command switch
_batchIdx++;
_res.hitMoleNum += hitMoleNum;
_res.passBatchNum++;
if (_batchIdx >= _data.totalBatchNum)
{
WhackMoleCommand.SingleModuleLightOn => new SingleModuleLightOnHandler(),
WhackMoleCommand.MultipleModuleLightOn => new MultipleModuleLightOnHandler(),
WhackMoleCommand.SingleModuleColorOn => new SingleModuleColorOnHandler(),
WhackMoleCommand.MultipleModuleColorOn => new MultipleModuleColorOnHandler(),
_ => throw new ArgumentOutOfRangeException()
};
handler.Init(node);
return handler;
WhackMoleSystem.StopAllFlicker();
OnGameEnd?.Invoke(_res);
return;
}
// 继续下一个批次,如果有中间状态就在这里处理
ActionKit.Sequence().Delay(_data.batchGap).Coroutine(_batchHandlers[_batchIdx].StartBatch).StartGlobal();
}
}
public abstract class AbsWhackMoleNodeHandler
public class WhackMoleBatchHandler
{
protected static WhackMoleSystem WhackMoleSystem => FixSystemCenter.SystemDic.Get<WhackMoleSystem>();
private readonly WhackMoleData _globalData;
protected WhackMoleNode node;
public AbsWhackMoleNodeHandler nextHandler;
private readonly ISelector<MoleModule> _moleSelector;
private readonly List<float> _lightGaps = new();
private readonly List<MoleModule> _lightingMoles = new();
public readonly UnityEvent<bool> onHandleEnd = new();
private bool _isBatchEnd;
private int _hitMoleNum;
public void Init(WhackMoleNode nodeData)
public event Action<int> OnBatchEnd;
public WhackMoleBatchHandler(IEnumerable<MoleModule> molesModules, WhackMoleData data, int index)
{
node = nodeData;
}
public IEnumerator Handle()
{
EnumEventSystem.Global.Send(WhackMoleState.BeforePlug);
yield return BeforePlug();
EnumEventSystem.Global.Send(WhackMoleState.WaitPlug, node.lightOnTime);
yield return WaitPlug();
EnumEventSystem.Global.Send(WhackMoleState.AfterPlug);
yield return AfterPlug();
}
protected virtual IEnumerator BeforePlug()
{
WhackMoleSystem.StartAllFlicker();
yield return new WaitForSeconds(node.flickerTime);
WhackMoleSystem.StopAllFlicker();
}
protected abstract IEnumerator WaitPlug();
protected abstract IEnumerator AfterPlug();
public abstract void OnPlugIn(string moduleName);
public abstract void OnPlugOut(string moduleName);
}
public class SingleModuleLightOnHandler : AbsWhackMoleNodeHandler
{
private bool _isPlugIn;
protected override IEnumerator WaitPlug()
{
Debug.Log("进入等待");
// 先等待
yield return new WaitForSeconds(1f);
_isPlugIn = false;
WhackMoleSystem.LightOnModule(node.moduleName);
// 进入循环等待插入事件,规定时间内未插入则进入失败结局
var waitTime = 0f;
while (!_isPlugIn && waitTime < node.lightOnTime)
_globalData = data;
var batchData = data.GetBatch(index);
// 创建选择器
_moleSelector = new LimitedSelector<MoleModule>(molesModules);
// 设置亮起时间间隔
for (var i = 0; i < batchData.moleNum; i++)
{
waitTime += Time.deltaTime;
var gap = Random.Range(batchData.durationRange.x, batchData.durationRange.y);
_lightGaps.Add(gap);
}
_lightGaps.Sort();
}
public IEnumerator StartBatch()
{
// 利用协程记时
float batchTime = 0f;
while (!_isBatchEnd)
{
OnUpdate(batchTime);
batchTime += Time.deltaTime;
yield return null;
EnumEventSystem.Global.Send(WhackMoleState.WaitPlug, node.lightOnTime - waitTime);
}
OnBatchEnd?.Invoke(_hitMoleNum);
OnBatchEnd = null;
}
private void OnUpdate(float batchTime)
{
// 点亮一些模块,其他的继续闪烁
while (_lightGaps.Count > 0 && _lightGaps[0] <= batchTime)
{
var lightOnMole = _moleSelector.Select();
lightOnMole.LightOn(_globalData.moleExistTime);
lightOnMole.OnLightMoleEnd += OnLightMoleEnd;
// 最后同步其他容器
_lightGaps.RemoveAt(0);
_lightingMoles.Add(lightOnMole);
}
}
protected override IEnumerator AfterPlug()
private void OnLightMoleEnd(MoleModule mole, bool isPlugin)
{
Debug.Log("进入后处理");
WhackMoleSystem.LightOffModule(node.moduleName);
if (_isPlugIn)
// 从亮起列表中移除
_lightingMoles.Remove(mole);
if (isPlugin) _hitMoleNum++;
// 当所有模块都熄灭的时候,游戏结束
if (_lightingMoles.Count <= 0 && _lightGaps.Count <= 0)
{
// TODO 正常插入,触发效果并进入下一个关卡
yield return new WaitForSeconds(1);
onHandleEnd?.Invoke(true);
}
else
{
// TODO 超时,触发失败结局
onHandleEnd?.Invoke(false);
}
}
public override void OnPlugIn(string moduleName)
{
if (moduleName == node.moduleName)
{
_isPlugIn = true;
}
}
public override void OnPlugOut(string moduleName)
{
if (moduleName == node.moduleName)
{
_isPlugIn = false;
_isBatchEnd = true;
}
}
}
public class MultipleModuleLightOnHandler : AbsWhackMoleNodeHandler
public struct WhackMoleRes
{
protected override IEnumerator WaitPlug()
{
// 等待插入
yield return new WaitUntil(() => false);
}
protected override IEnumerator AfterPlug()
{
throw new NotImplementedException();
}
public override void OnPlugIn(string moduleName)
{
}
public override void OnPlugOut(string moduleName)
{
throw new NotImplementedException();
}
}
public class SingleModuleColorOnHandler : AbsWhackMoleNodeHandler
{
protected override IEnumerator WaitPlug()
{
throw new NotImplementedException();
}
protected override IEnumerator AfterPlug()
{
throw new NotImplementedException();
}
public override void OnPlugIn(string moduleName)
{
}
public override void OnPlugOut(string moduleName)
{
throw new NotImplementedException();
}
}
public class MultipleModuleColorOnHandler : AbsWhackMoleNodeHandler
{
protected override IEnumerator WaitPlug()
{
throw new NotImplementedException();
}
protected override IEnumerator AfterPlug()
{
throw new NotImplementedException();
}
public override void OnPlugIn(string moduleName)
{
}
public override void OnPlugOut(string moduleName)
{
throw new NotImplementedException();
}
}
public enum WhackMoleState
{
BeforePlug,
WaitPlug,
AfterPlug,
public int totalMoleBatch;
public int failBatchNum;
public int passBatchNum;
public int totalMoleNum;
public int hitMoleNum;
}
}
@@ -1,3 +1,3 @@
fileFormatVersion: 2
guid: d1b796d518a64802a34ce6ad301b3a00
timeCreated: 1752129433
guid: a845f09d13dd4cb0b5f111d8fa2e40a4
timeCreated: 1753442701
@@ -1,57 +0,0 @@
using System;
using AibisDream.Framework;
using TMPro;
using UnityEngine;
namespace AibisDream.FixSystem
{
public class WhackMoleLog : MonoBehaviour
{
private TMP_Text _countDownText;
private TMP_Text _stateText;
private TMP_Text _resText;
private void Awake()
{
_countDownText = transform.Find("倒计时").GetComponent<TMP_Text>();
_stateText = transform.Find("当前状态").GetComponent<TMP_Text>();
_resText = transform.Find("结果").GetComponent<TMP_Text>();
EnumEventSystem.Global.Register(WhackMoleState.BeforePlug, OnBeforePlug);
EnumEventSystem.Global.Register<WhackMoleState, float>(WhackMoleState.WaitPlug, OnWaitPlug);
EnumEventSystem.Global.Register(WhackMoleState.AfterPlug, OnAfterPlug);
}
public void Init()
{
_countDownText.text = "倒计时:等待";
_stateText.text = "当前状态:开始";
_resText.text = "结果:等待";
}
private void OnBeforePlug()
{
_stateText.text = "当前状态:前置效果";
_countDownText.text = "倒计时:0";
}
private void OnWaitPlug(float time)
{
_stateText.text = "当前状态:插线倒计时";
_countDownText.text = $"倒计时:{time:F}";
}
private void OnAfterPlug()
{
_stateText.text = "当前状态:后置效果";
_countDownText.text = "倒计时:0";
}
public void OnGameEnd(bool isSuccess)
{
_stateText.text = "当前状态:游戏结束";
_countDownText.text = "倒计时:0";
_resText.text = "结果:" + (isSuccess ? "成功" : "失败");
}
}
}
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 1c60dc35d51a4c349889aa59f70a6442
timeCreated: 1753262821
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using AibisDream.Framework;
using UnityEngine;
using Yarn.Unity;
@@ -10,8 +9,6 @@ namespace AibisDream.FixSystem
public class WhackMoleSystem : MonoBehaviour
{
private BodyModuleSystem _bodyModuleSystem;
private WhackMoleHandler _handler;
private WhackMoleLog _log;
private Dictionary<string, MoleModule> _moleModules;
@@ -19,41 +16,22 @@ namespace AibisDream.FixSystem
{
_bodyModuleSystem = GetComponent<BodyModuleSystem>();
FixSystemCenter.SystemDic.Register(this);
_log = GetComponentInChildren<WhackMoleLog>();
}
#region
public void StartWhack(WhackMoleData levelData)
{
_handler = WhackMoleHandler.Create(levelData, this);
_handler.OnGameEnd += OnWhackEnd;
// 获取当前所有模块
_moleModules =
_bodyModuleSystem.BodyModules.ToDictionary(item => item.data.moduleName, item => item as MoleModule);
_moleModules.Values.ToList().ForEach(item => item.isInMoleGame = true);
_log.Init();
_handler.StartGame();
WhackMoleHandler handler = new WhackMoleHandler(levelData);
handler.OnGameEnd += OnGameEnd;
handler.Start();
}
private void OnWhackEnd(bool isSuccess)
private void OnGameEnd(WhackMoleRes res)
{
_moleModules.Values.ToList().ForEach(item => item.isInMoleGame = false);
// TODO 触发游戏结束
_log.OnGameEnd(isSuccess);
DialogController.Instance.StartDialogNode(isSuccess ? "打地鼠游戏通过" : "打地鼠游戏失败");
Debug.Log($"结果:共计{res.totalMoleNum}个,成功击中{res.hitMoleNum}个");
}
public void OnPlugIn(string moduleName)
{
_handler?.OnPlugIn(moduleName);
}
public void OnPlugOut(string moduleName)
{
_handler?.OnPlugOut(moduleName);
}
#endregion
#region , BodyModuleSystem实现
@@ -73,38 +51,34 @@ namespace AibisDream.FixSystem
module.StopFlicker();
}
}
public void LightOnModule(string moduleName)
public Dictionary<string, MoleModule> MoleModules
{
if (_moleModules.TryGetValue(moduleName, out var moleModule))
get
{
moleModule.LightOn(Color.red);
}
else
{
Debug.LogError($"没有找到模块:{moduleName}");
}
}
if (_moleModules == null)
{
_moleModules = new Dictionary<string, MoleModule>();
foreach (var module in _bodyModuleSystem.BodyModules)
{
if (module is MoleModule moleModule)
{
_moleModules.Add(moleModule.data.moduleName, moleModule);
}
}
}
public void LightOffModule(string moduleName)
{
if (_moleModules.TryGetValue(moduleName, out var moleModule))
{
moleModule.LightOff();
}
else
{
Debug.LogError($"没有找到模块:{moduleName}");
return _moleModules;
}
}
#endregion
}
public static class WholeMoleCommand
{
private static WhackMoleSystem WhackMoleSystem => FixSystemCenter.SystemDic.Get<WhackMoleSystem>();
[YarnCommand("start_whack_game")]
public static void StartWhack(string levelName)
{
@@ -1,5 +1,4 @@
using System;
using AibisDream.FixSystem;
using UnityEngine;
namespace AibisDream.Framework
@@ -0,0 +1,69 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace AibisDream.Framework
{
public class MultipleSelector<T> : IMultipleSelector<T>
{
private readonly List<T> _items;
private int _batchSize;
public MultipleSelector(IEnumerable<T> items, int batchSize)
{
_items = new List<T>(items);
_batchSize = batchSize;
}
public T[] Select()
{
int[] indexArray = IMultipleSelector<T>.MultiRange(0, Count - 1, _batchSize);
return indexArray.Select(index => _items[index]).ToArray();
}
public void RemoveItem(T item)
{
_items.Remove(item);
}
public void AddItem(T item)
{
_items.Add(item);
}
public void SetBatchSize(int batchSize)
{
_batchSize = batchSize;
}
public int Count => _items.Count;
}
public interface IMultipleSelector<T>
{
T[] Select();
void RemoveItem(T item);
void AddItem(T item);
int Count { get; }
static int[] MultiRange(int start, int end, int batchSize)
{
// 确保要求的数量不超过范围
if (batchSize > end - start + 1)
{
Debug.LogError("要求的数量超过了范围内的数字总数");
return default;
}
var uniqueNumbers = new HashSet<int>();
while (uniqueNumbers.Count < batchSize)
{
var number = Random.Range(start, end + 1);
uniqueNumbers.Add(number);
}
return uniqueNumbers.ToArray();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6409fbaa417b4c55841a8ca0abe16593
timeCreated: 1753859058
@@ -4,16 +4,30 @@ using System.Linq;
namespace AibisDream.Framework
{
public class RandomSelector<T> : ISelector<T>
public class SingleSelector<T> : ISelector<T>
{
private readonly List<T> _items;
private readonly List<int> _prefixSums;
private readonly int _totalWeight;
private readonly Random _random;
#region
public void AddItem(T item)
{
throw new NotImplementedException();
}
public void RemoveItem(T item)
{
throw new NotImplementedException();
}
public int Count => _items.Count;
public RandomSelector(IEnumerable<T> items, Func<T, int> weightSelector)
#endregion
public SingleSelector(IEnumerable<T> items, Func<T, int> weightSelector)
{
if (items == null) throw new ArgumentNullException(nameof(items));
if (weightSelector == null) throw new ArgumentNullException(nameof(weightSelector));
@@ -21,7 +35,7 @@ namespace AibisDream.Framework
var itemList = items.ToList();
_items = new List<T>(itemList.Count);
_prefixSums = new List<int>(itemList.Count);
int sum = 0;
foreach (var item in itemList)
{
@@ -40,7 +54,7 @@ namespace AibisDream.Framework
_totalWeight = sum;
_random = new Random();
}
public T Select()
{
if (_totalWeight == 0)
@@ -79,21 +93,35 @@ namespace AibisDream.Framework
private readonly List<int> _batchWeight;
private readonly int _totalWeight;
private readonly Random _random;
private int _currentWeight;
private List<int> _curBatchWeight;
#region
public void AddItem(T item)
{
throw new NotImplementedException();
}
public void RemoveItem(T item)
{
throw new NotImplementedException();
}
#endregion
public int Count => _totalWeight;
public BatchSelector(IEnumerable<T> items, Func<T, int> weightSelector)
{
{
if (items == null) throw new ArgumentNullException(nameof(items));
if (weightSelector == null) throw new ArgumentNullException(nameof(weightSelector));
var itemList = items.ToList();
_items = new List<T>(itemList.Count);
_batchWeight = new List<int>(itemList.Count);
int sum = 0;
foreach (var item in itemList)
{
@@ -110,7 +138,7 @@ namespace AibisDream.Framework
}
_curBatchWeight = new List<int>(_batchWeight);
_totalWeight = sum;
_currentWeight = sum;
_random = new Random();
@@ -129,14 +157,14 @@ namespace AibisDream.Framework
{
ResetSelector();
}
int randomValue = _random.Next(0, _currentWeight);
int index = BinarySearch(randomValue);
// 选择后减去权重
_currentWeight -= 1;
_curBatchWeight[index] -= 1;
return _items[index];
}
@@ -162,6 +190,64 @@ namespace AibisDream.Framework
}
}
public class LimitedSelector<T> : ISelector<T>
{
private readonly List<T> _items;
private readonly Random _random;
public LimitedSelector(IEnumerable<T> items)
{
_items = items.ToList();
_random = new Random();
}
public T Select()
{
if (_items.Count == 0)
{
throw new InvalidOperationException("Selector is Empty");
}
var res = _items[_random.Next(0, _items.Count)];
_items.Remove(res);
return res;
}
public int Count => _items.Count;
}
public class UnRepeatSelector<T> : ISelector<T>
{
private readonly List<T> _items;
private readonly Random _random;
private T _lastCache;
public int Count => _items.Count;
public UnRepeatSelector(IEnumerable<T> items)
{
_items = items.ToList();
_random = new Random();
}
public T Select()
{
if (_items.Count == 0)
{
throw new InvalidOperationException("Selector is Empty");
}
T res;
do
{
res = _items[_random.Next(0, _items.Count)];
} while (Equals(res, _lastCache));
_lastCache = res;
return res;
}
}
public interface ISelector<out T>
{
T Select();
@@ -74,7 +74,7 @@ namespace AibisDream
protected virtual ISelector<MobileObjectData> CreateSelector(IEnumerable<MobileObjectData> datas)
{
return new RandomSelector<MobileObjectData>(datas, data => data.weight);
return new SingleSelector<MobileObjectData>(datas, data => data.weight);
}
private List<MobileObjectData> SetPublicVariable()