From 47481986966063fe62e5e2bd124da1eda0b96674 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Tue, 10 Feb 2026 23:14:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(coroutine):=20=E6=B7=BB=E5=8A=A0=E5=A4=9A?= =?UTF-8?q?=E7=A7=8D=E5=8D=8F=E7=A8=8B=E7=AD=89=E5=BE=85=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=E5=8F=8A=E5=AF=B9=E5=BA=94=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现 WaitForConditionChange 指令,支持等待条件状态变化 - 实现 WaitForEndOfFrame 指令,支持等待当前帧渲染完成 - 实现 WaitForFixedUpdate 指令,支持等待物理固定更新周期 - 实现 WaitForMultipleEvents 指令,支持等待多个事件中的任意一个触发 - 实现 WaitForNextFrame 指令,支持等待下一帧开始 - 实现 WaitForPredicate 指令,支持通用谓词等待功能 - 实现 WaitForSecondsRealtime 指令,支持基于真实时间的等待 - 实现 WaitForSecondsScaled 指令,支持受时间缩放影响的等待 - 实现 WaitUntilOrTimeout 指令,支持带超时的条件等待 - 为所有新指令添加完整的单元测试覆盖 --- .../coroutine/WaitForConditionChangeTests.cs | 124 ++++++++++++++++++ .../coroutine/WaitForEndOfFrameTests.cs | 61 +++++++++ .../coroutine/WaitForFixedUpdateTests.cs | 61 +++++++++ .../coroutine/WaitForNextFrameTests.cs | 61 +++++++++ .../coroutine/WaitForPredicateTests.cs | 87 ++++++++++++ .../coroutine/WaitForSecondsRealtimeTests.cs | 80 +++++++++++ .../coroutine/WaitForSecondsScaledTests.cs | 80 +++++++++++ .../coroutine/WaitUntilOrTimeoutTests.cs | 109 +++++++++++++++ .../instructions/WaitForConditionChange.cs | 46 +++++++ .../instructions/WaitForEndOfFrame.cs | 27 ++++ .../instructions/WaitForFixedUpdate.cs | 27 ++++ .../instructions/WaitForMultipleEvents.cs | 99 ++++++++++++++ .../instructions/WaitForNextFrame.cs | 26 ++++ .../instructions/WaitForPredicate.cs | 28 ++++ .../instructions/WaitForSecondsRealtime.cs | 30 +++++ .../instructions/WaitForSecondsScaled.cs | 30 +++++ .../instructions/WaitUntilOrTimeout.cs | 40 ++++++ 17 files changed, 1016 insertions(+) create mode 100644 GFramework.Core.Tests/coroutine/WaitForConditionChangeTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitForEndOfFrameTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitForFixedUpdateTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitForNextFrameTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitForPredicateTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitForSecondsRealtimeTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitForSecondsScaledTests.cs create mode 100644 GFramework.Core.Tests/coroutine/WaitUntilOrTimeoutTests.cs create mode 100644 GFramework.Core/coroutine/instructions/WaitForConditionChange.cs create mode 100644 GFramework.Core/coroutine/instructions/WaitForEndOfFrame.cs create mode 100644 GFramework.Core/coroutine/instructions/WaitForFixedUpdate.cs create mode 100644 GFramework.Core/coroutine/instructions/WaitForMultipleEvents.cs create mode 100644 GFramework.Core/coroutine/instructions/WaitForNextFrame.cs create mode 100644 GFramework.Core/coroutine/instructions/WaitForPredicate.cs create mode 100644 GFramework.Core/coroutine/instructions/WaitForSecondsRealtime.cs create mode 100644 GFramework.Core/coroutine/instructions/WaitForSecondsScaled.cs create mode 100644 GFramework.Core/coroutine/instructions/WaitUntilOrTimeout.cs diff --git a/GFramework.Core.Tests/coroutine/WaitForConditionChangeTests.cs b/GFramework.Core.Tests/coroutine/WaitForConditionChangeTests.cs new file mode 100644 index 0000000..db91ee2 --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitForConditionChangeTests.cs @@ -0,0 +1,124 @@ +using GFramework.Core.Abstractions.coroutine; +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine; + +/// +/// WaitForConditionChange的单元测试类 +/// +[TestFixture] +public class WaitForConditionChangeTests +{ + /// + /// 验证WaitForConditionChange初始状态为未完成 + /// + [Test] + public void WaitForConditionChange_Should_Not_Be_Done_Initially() + { + var condition = false; + var wait = new WaitForConditionChange(() => condition, true); + + Assert.That(wait.IsDone, Is.False); + } + + /// + /// 验证WaitForConditionChange从false变为true时完成 + /// + [Test] + public void WaitForConditionChange_Should_Be_Done_When_Changing_From_False_To_True() + { + var condition = false; + var wait = new WaitForConditionChange(() => condition, true); + + // 初始状态记录 + wait.Update(0.1); + + condition = true; + wait.Update(0.1); + + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForConditionChange从true变为false时完成 + /// + [Test] + public void WaitForConditionChange_Should_Be_Done_When_Changing_From_True_To_False() + { + var condition = true; + var wait = new WaitForConditionChange(() => condition, false); + + // 初始状态记录 + wait.Update(0.1); + + condition = false; + wait.Update(0.1); + + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForConditionChange不响应相同状态的变化 + /// + [Test] + public void WaitForConditionChange_Should_Not_Be_Done_When_No_State_Change() + { + var condition = false; + var wait = new WaitForConditionChange(() => condition, true); + + // 初始状态记录 + wait.Update(0.1); + + // 仍然是false,没有状态改变 + wait.Update(0.1); + + Assert.That(wait.IsDone, Is.False); + } + + /// + /// 验证WaitForConditionChange多次状态切换只响应第一次 + /// + [Test] + public void WaitForConditionChange_Should_Only_Respond_To_First_Transition() + { + var condition = false; + var wait = new WaitForConditionChange(() => condition, true); + + // 记录初始状态 + wait.Update(0.1); + Assert.That(wait.IsDone, Is.False); + + // 触发状态转换到目标状态 + condition = true; + wait.Update(0.1); + Assert.That(wait.IsDone, Is.True); + + // 再次切换回原始状态 + condition = false; + wait.Update(0.1); + + // 应该仍然保持完成状态 + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForConditionChange抛出ArgumentNullException当conditionGetter为null + /// + [Test] + public void WaitForConditionChange_Should_Throw_ArgumentNullException_When_ConditionGetter_Is_Null() + { + Assert.Throws(() => new WaitForConditionChange(null!, true)); + } + + /// + /// 验证WaitForConditionChange实现IYieldInstruction接口 + /// + [Test] + public void WaitForConditionChange_Should_Implement_IYieldInstruction() + { + var wait = new WaitForConditionChange(() => false, true); + + Assert.That(wait, Is.InstanceOf()); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitForEndOfFrameTests.cs b/GFramework.Core.Tests/coroutine/WaitForEndOfFrameTests.cs new file mode 100644 index 0000000..d57ff72 --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitForEndOfFrameTests.cs @@ -0,0 +1,61 @@ +using GFramework.Core.Abstractions.coroutine; +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine; + +/// +/// WaitForEndOfFrame的单元测试类 +/// +[TestFixture] +public class WaitForEndOfFrameTests +{ + /// + /// 验证WaitForEndOfFrame初始状态为未完成 + /// + [Test] + public void WaitForEndOfFrame_Should_Not_Be_Done_Initially() + { + var wait = new WaitForEndOfFrame(); + + Assert.That(wait.IsDone, Is.False); + } + + /// + /// 验证WaitForEndOfFrame在Update后应该完成 + /// + [Test] + public void WaitForEndOfFrame_Should_Be_Done_After_Update() + { + var wait = new WaitForEndOfFrame(); + + wait.Update(0.016); + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForEndOfFrame多次Update后仍保持完成状态 + /// + [Test] + public void WaitForEndOfFrame_Should_Remain_Done_After_Multiple_Updates() + { + var wait = new WaitForEndOfFrame(); + + wait.Update(0.016); + Assert.That(wait.IsDone, Is.True); + + wait.Update(0.016); + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForEndOfFrame实现IYieldInstruction接口 + /// + [Test] + public void WaitForEndOfFrame_Should_Implement_IYieldInstruction() + { + var wait = new WaitForEndOfFrame(); + + Assert.That(wait, Is.InstanceOf()); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitForFixedUpdateTests.cs b/GFramework.Core.Tests/coroutine/WaitForFixedUpdateTests.cs new file mode 100644 index 0000000..a5d981f --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitForFixedUpdateTests.cs @@ -0,0 +1,61 @@ +using GFramework.Core.Abstractions.coroutine; +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine; + +/// +/// WaitForFixedUpdate的单元测试类 +/// +[TestFixture] +public class WaitForFixedUpdateTests +{ + /// + /// 验证WaitForFixedUpdate初始状态为未完成 + /// + [Test] + public void WaitForFixedUpdate_Should_Not_Be_Done_Initially() + { + var wait = new WaitForFixedUpdate(); + + Assert.That(wait.IsDone, Is.False); + } + + /// + /// 验证WaitForFixedUpdate在Update后应该完成 + /// + [Test] + public void WaitForFixedUpdate_Should_Be_Done_After_Update() + { + var wait = new WaitForFixedUpdate(); + + wait.Update(0.016); + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForFixedUpdate多次Update后仍保持完成状态 + /// + [Test] + public void WaitForFixedUpdate_Should_Remain_Done_After_Multiple_Updates() + { + var wait = new WaitForFixedUpdate(); + + wait.Update(0.016); + Assert.That(wait.IsDone, Is.True); + + wait.Update(0.016); + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForFixedUpdate实现IYieldInstruction接口 + /// + [Test] + public void WaitForFixedUpdate_Should_Implement_IYieldInstruction() + { + var wait = new WaitForFixedUpdate(); + + Assert.That(wait, Is.InstanceOf()); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitForNextFrameTests.cs b/GFramework.Core.Tests/coroutine/WaitForNextFrameTests.cs new file mode 100644 index 0000000..fabff30 --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitForNextFrameTests.cs @@ -0,0 +1,61 @@ +using GFramework.Core.Abstractions.coroutine; +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine; + +/// +/// WaitForNextFrame的单元测试类 +/// +[TestFixture] +public class WaitForNextFrameTests +{ + /// + /// 验证WaitForNextFrame初始状态为未完成 + /// + [Test] + public void WaitForNextFrame_Should_Not_Be_Done_Initially() + { + var wait = new WaitForNextFrame(); + + Assert.That(wait.IsDone, Is.False); + } + + /// + /// 验证WaitForNextFrame在Update后应该完成 + /// + [Test] + public void WaitForNextFrame_Should_Be_Done_After_Update() + { + var wait = new WaitForNextFrame(); + + wait.Update(0.016); + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForNextFrame多次Update后仍保持完成状态 + /// + [Test] + public void WaitForNextFrame_Should_Remain_Done_After_Multiple_Updates() + { + var wait = new WaitForNextFrame(); + + wait.Update(0.016); + Assert.That(wait.IsDone, Is.True); + + wait.Update(0.016); + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForNextFrame实现IYieldInstruction接口 + /// + [Test] + public void WaitForNextFrame_Should_Implement_IYieldInstruction() + { + var wait = new WaitForNextFrame(); + + Assert.That(wait, Is.InstanceOf()); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitForPredicateTests.cs b/GFramework.Core.Tests/coroutine/WaitForPredicateTests.cs new file mode 100644 index 0000000..d46f808 --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitForPredicateTests.cs @@ -0,0 +1,87 @@ +using GFramework.Core.Abstractions.coroutine; +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine; + +/// +/// WaitForPredicate的单元测试类 +/// +[TestFixture] +public class WaitForPredicateTests +{ + /// + /// 验证WaitForPredicate默认等待条件为真时完成 + /// + [Test] + public void WaitForPredicate_Should_Wait_For_True_By_Default() + { + var condition = false; + var wait = new WaitForPredicate(() => condition); + + Assert.That(wait.IsDone, Is.False); + + condition = true; + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForPredicate可以等待条件为假时完成 + /// + [Test] + public void WaitForPredicate_Should_Wait_For_False_When_Specified() + { + var condition = true; + var wait = new WaitForPredicate(() => condition, false); + + Assert.That(wait.IsDone, Is.False); + + condition = false; + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForPredicate多次检查条件 + /// + [Test] + public void WaitForPredicate_Should_Check_Condition_Multiple_Times() + { + var callCount = 0; + var wait = new WaitForPredicate(() => + { + callCount++; + return callCount >= 3; + }); + + Assert.That(wait.IsDone, Is.False); + Assert.That(callCount, Is.EqualTo(1)); + + wait.Update(0.1); + Assert.That(wait.IsDone, Is.False); + Assert.That(callCount, Is.EqualTo(2)); + + wait.Update(0.1); + Assert.That(wait.IsDone, Is.True); + Assert.That(callCount, Is.EqualTo(3)); + } + + /// + /// 验证WaitForPredicate抛出ArgumentNullException当predicate为null + /// + [Test] + public void WaitForPredicate_Should_Throw_ArgumentNullException_When_Predicate_Is_Null() + { + Assert.Throws(() => new WaitForPredicate(null!)); + } + + /// + /// 验证WaitForPredicate实现IYieldInstruction接口 + /// + [Test] + public void WaitForPredicate_Should_Implement_IYieldInstruction() + { + var wait = new WaitForPredicate(() => true); + + Assert.That(wait, Is.InstanceOf()); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitForSecondsRealtimeTests.cs b/GFramework.Core.Tests/coroutine/WaitForSecondsRealtimeTests.cs new file mode 100644 index 0000000..af86fc9 --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitForSecondsRealtimeTests.cs @@ -0,0 +1,80 @@ +using GFramework.Core.Abstractions.coroutine; +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine; + +/// +/// WaitForSecondsRealtime的单元测试类 +/// +[TestFixture] +public class WaitForSecondsRealtimeTests +{ + /// + /// 验证WaitForSecondsRealtime初始状态根据时间设置 + /// + [Test] + public void WaitForSecondsRealtime_Should_Handle_Initial_State_Correctly() + { + var waitZero = new WaitForSecondsRealtime(0); + var waitPositive = new WaitForSecondsRealtime(1.0); + + Assert.That(waitZero.IsDone, Is.True); + Assert.That(waitPositive.IsDone, Is.False); + } + + /// + /// 验证WaitForSecondsRealtime应该在指定时间后完成 + /// + [Test] + public void WaitForSecondsRealtime_Should_Be_Done_After_Specified_Time() + { + var wait = new WaitForSecondsRealtime(1.0); + + wait.Update(0.5); + Assert.That(wait.IsDone, Is.False); + + wait.Update(0.5); + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForSecondsRealtime可以处理负数时间 + /// + [Test] + public void WaitForSecondsRealtime_Should_Handle_Negative_Time() + { + var wait = new WaitForSecondsRealtime(-1.0); + + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForSecondsRealtime多次更新累积时间 + /// + [Test] + public void WaitForSecondsRealtime_Should_Accumulate_Time_Over_Multiple_Updates() + { + var wait = new WaitForSecondsRealtime(2.0); + + wait.Update(0.5); + Assert.That(wait.IsDone, Is.False); + + wait.Update(1.0); + Assert.That(wait.IsDone, Is.False); + + wait.Update(0.5); + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForSecondsRealtime实现IYieldInstruction接口 + /// + [Test] + public void WaitForSecondsRealtime_Should_Implement_IYieldInstruction() + { + var wait = new WaitForSecondsRealtime(1.0); + + Assert.That(wait, Is.InstanceOf()); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitForSecondsScaledTests.cs b/GFramework.Core.Tests/coroutine/WaitForSecondsScaledTests.cs new file mode 100644 index 0000000..a017fb3 --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitForSecondsScaledTests.cs @@ -0,0 +1,80 @@ +using GFramework.Core.Abstractions.coroutine; +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine; + +/// +/// WaitForSecondsScaled的单元测试类 +/// +[TestFixture] +public class WaitForSecondsScaledTests +{ + /// + /// 验证WaitForSecondsScaled初始状态根据时间设置 + /// + [Test] + public void WaitForSecondsScaled_Should_Handle_Initial_State_Correctly() + { + var waitZero = new WaitForSecondsScaled(0); + var waitPositive = new WaitForSecondsScaled(1.0); + + Assert.That(waitZero.IsDone, Is.True); + Assert.That(waitPositive.IsDone, Is.False); + } + + /// + /// 验证WaitForSecondsScaled应该在指定时间后完成 + /// + [Test] + public void WaitForSecondsScaled_Should_Be_Done_After_Specified_Time() + { + var wait = new WaitForSecondsScaled(1.0); + + wait.Update(0.5); + Assert.That(wait.IsDone, Is.False); + + wait.Update(0.5); + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForSecondsScaled可以处理负数时间 + /// + [Test] + public void WaitForSecondsScaled_Should_Handle_Negative_Time() + { + var wait = new WaitForSecondsScaled(-1.0); + + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForSecondsScaled多次更新累积时间 + /// + [Test] + public void WaitForSecondsScaled_Should_Accumulate_Time_Over_Multiple_Updates() + { + var wait = new WaitForSecondsScaled(2.0); + + wait.Update(0.5); + Assert.That(wait.IsDone, Is.False); + + wait.Update(1.0); + Assert.That(wait.IsDone, Is.False); + + wait.Update(0.5); + Assert.That(wait.IsDone, Is.True); + } + + /// + /// 验证WaitForSecondsScaled实现IYieldInstruction接口 + /// + [Test] + public void WaitForSecondsScaled_Should_Implement_IYieldInstruction() + { + var wait = new WaitForSecondsScaled(1.0); + + Assert.That(wait, Is.InstanceOf()); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/coroutine/WaitUntilOrTimeoutTests.cs b/GFramework.Core.Tests/coroutine/WaitUntilOrTimeoutTests.cs new file mode 100644 index 0000000..c9b04d3 --- /dev/null +++ b/GFramework.Core.Tests/coroutine/WaitUntilOrTimeoutTests.cs @@ -0,0 +1,109 @@ +using GFramework.Core.Abstractions.coroutine; +using GFramework.Core.coroutine.instructions; +using NUnit.Framework; + +namespace GFramework.Core.Tests.coroutine; + +/// +/// WaitUntilOrTimeout的单元测试类 +/// +[TestFixture] +public class WaitUntilOrTimeoutTests +{ + /// + /// 验证WaitUntilOrTimeout初始状态为未完成 + /// + [Test] + public void WaitUntilOrTimeout_Should_Not_Be_Done_Initially() + { + var condition = false; + var wait = new WaitUntilOrTimeout(() => condition, 5.0); + + Assert.That(wait.IsDone, Is.False); + Assert.That(wait.ConditionMet, Is.False); + Assert.That(wait.IsTimedOut, Is.False); + } + + /// + /// 验证WaitUntilOrTimeout应该在条件满足时完成 + /// + [Test] + public void WaitUntilOrTimeout_Should_Be_Done_When_Condition_Met() + { + var condition = false; + var wait = new WaitUntilOrTimeout(() => condition, 5.0); + + condition = true; + wait.Update(0.1); + + Assert.That(wait.IsDone, Is.True); + Assert.That(wait.ConditionMet, Is.True); + Assert.That(wait.IsTimedOut, Is.False); + } + + /// + /// 验证WaitUntilOrTimeout应该在超时时完成 + /// + [Test] + public void WaitUntilOrTimeout_Should_Be_Done_When_Timed_Out() + { + var condition = false; + var wait = new WaitUntilOrTimeout(() => condition, 1.0); + + wait.Update(1.5); + + Assert.That(wait.IsDone, Is.True); + Assert.That(wait.ConditionMet, Is.False); + Assert.That(wait.IsTimedOut, Is.True); + } + + /// + /// 验证WaitUntilOrTimeout可以处理零超时时间 + /// + [Test] + public void WaitUntilOrTimeout_Should_Handle_Zero_Timeout() + { + var condition = false; + var wait = new WaitUntilOrTimeout(() => condition, 0); + + wait.Update(0.1); + + Assert.That(wait.IsDone, Is.True); + Assert.That(wait.IsTimedOut, Is.True); + } + + /// + /// 验证WaitUntilOrTimeout可以处理负数超时时间 + /// + [Test] + public void WaitUntilOrTimeout_Should_Handle_Negative_Timeout() + { + var condition = false; + var wait = new WaitUntilOrTimeout(() => condition, -1.0); + + wait.Update(0.1); + + Assert.That(wait.IsDone, Is.True); + Assert.That(wait.IsTimedOut, Is.True); + } + + /// + /// 验证WaitUntilOrTimeout抛出ArgumentNullException当predicate为null + /// + [Test] + public void WaitUntilOrTimeout_Should_Throw_ArgumentNullException_When_Predicate_Is_Null() + { + Assert.Throws(() => new WaitUntilOrTimeout(null!, 1.0)); + } + + /// + /// 验证WaitUntilOrTimeout实现IYieldInstruction接口 + /// + [Test] + public void WaitUntilOrTimeout_Should_Implement_IYieldInstruction() + { + var wait = new WaitUntilOrTimeout(() => false, 1.0); + + Assert.That(wait, Is.InstanceOf()); + } +} \ No newline at end of file diff --git a/GFramework.Core/coroutine/instructions/WaitForConditionChange.cs b/GFramework.Core/coroutine/instructions/WaitForConditionChange.cs new file mode 100644 index 0000000..0380daf --- /dev/null +++ b/GFramework.Core/coroutine/instructions/WaitForConditionChange.cs @@ -0,0 +1,46 @@ +using GFramework.Core.Abstractions.coroutine; + +namespace GFramework.Core.coroutine.instructions; + +/// +/// 等待条件状态发生变化的指令 +/// 当条件从一种状态切换到另一种状态时完成 +/// +/// 获取当前条件状态的函数 +/// 期望转换到的目标状态 +public sealed class WaitForConditionChange(Func conditionGetter, bool waitForTransitionTo) : IYieldInstruction +{ + private readonly Func _conditionGetter = + conditionGetter ?? throw new ArgumentNullException(nameof(conditionGetter)); + + private bool? _initialState; + private bool _isCompleted; + + /// + /// 更新方法,检测条件变化 + /// + /// 时间增量 + public void Update(double deltaTime) + { + if (_isCompleted) + return; + + if (!_initialState.HasValue) + { + _initialState = _conditionGetter(); + return; + } + + // 检查是否发生了期望的状态转换 + var currentState = _conditionGetter(); + if (currentState == waitForTransitionTo && _initialState.Value != waitForTransitionTo) + { + _isCompleted = true; + } + } + + /// + /// 获取等待是否已完成(条件发生了期望的状态转换) + /// + public bool IsDone => _isCompleted; +} \ No newline at end of file diff --git a/GFramework.Core/coroutine/instructions/WaitForEndOfFrame.cs b/GFramework.Core/coroutine/instructions/WaitForEndOfFrame.cs new file mode 100644 index 0000000..f03c48f --- /dev/null +++ b/GFramework.Core/coroutine/instructions/WaitForEndOfFrame.cs @@ -0,0 +1,27 @@ +using GFramework.Core.Abstractions.coroutine; + +namespace GFramework.Core.coroutine.instructions; + +/// +/// 等待当前帧渲染完成的指令 +/// 通常用于需要在渲染完成后执行的操作 +/// +public sealed class WaitForEndOfFrame : IYieldInstruction +{ + private bool _completed; + + /// + /// 更新方法,在帧末尾被调用 + /// + /// 时间增量 + public void Update(double deltaTime) + { + // 在帧结束时标记完成 + _completed = true; + } + + /// + /// 获取等待是否已完成 + /// + public bool IsDone => _completed; +} \ No newline at end of file diff --git a/GFramework.Core/coroutine/instructions/WaitForFixedUpdate.cs b/GFramework.Core/coroutine/instructions/WaitForFixedUpdate.cs new file mode 100644 index 0000000..a2ebe6c --- /dev/null +++ b/GFramework.Core/coroutine/instructions/WaitForFixedUpdate.cs @@ -0,0 +1,27 @@ +using GFramework.Core.Abstractions.coroutine; + +namespace GFramework.Core.coroutine.instructions; + +/// +/// 等待下一个物理固定更新周期的指令 +/// 主要用于需要与物理系统同步的操作 +/// +public sealed class WaitForFixedUpdate : IYieldInstruction +{ + private bool _completed; + + /// + /// 更新方法,在固定更新时被调用 + /// + /// 时间增量 + public void Update(double deltaTime) + { + // 在固定更新周期中标记完成 + _completed = true; + } + + /// + /// 获取等待是否已完成 + /// + public bool IsDone => _completed; +} \ No newline at end of file diff --git a/GFramework.Core/coroutine/instructions/WaitForMultipleEvents.cs b/GFramework.Core/coroutine/instructions/WaitForMultipleEvents.cs new file mode 100644 index 0000000..e06a7b6 --- /dev/null +++ b/GFramework.Core/coroutine/instructions/WaitForMultipleEvents.cs @@ -0,0 +1,99 @@ +using GFramework.Core.Abstractions.coroutine; +using GFramework.Core.Abstractions.events; + +namespace GFramework.Core.coroutine.instructions; + +/// +/// 等待多个事件中的任意一个触发的指令 +/// 实现了 IDisposable 接口,支持资源释放 +/// +/// 第一个事件类型 +/// 第二个事件类型 +public sealed class WaitForMultipleEvents : IYieldInstruction, IDisposable +{ + private bool _disposed; + private volatile bool _done; + private IUnRegister? _unRegister1; + private IUnRegister? _unRegister2; + + /// + /// 初始化 WaitForMultipleEvents 实例 + /// + /// 事件总线实例 + public WaitForMultipleEvents(IEventBus eventBus) + { + var eventBus1 = eventBus ?? throw new ArgumentNullException(nameof(eventBus)); + + // 注册两个事件的监听器 + _unRegister1 = eventBus1.Register(OnFirstEvent); + _unRegister2 = eventBus1.Register(OnSecondEvent); + } + + /// + /// 获取第一个事件的数据(如果已触发) + /// + public TEvent1? FirstEventData { get; private set; } + + /// + /// 获取第二个事件的数据(如果已触发) + /// + public TEvent2? SecondEventData { get; private set; } + + /// + /// 获取是哪个事件先触发(1表示第一个事件,2表示第二个事件) + /// + public int TriggeredBy { get; private set; } + + /// + /// 释放资源 + /// + public void Dispose() + { + if (_disposed) return; + + _unRegister1?.UnRegister(); + _unRegister2?.UnRegister(); + _unRegister1 = null; + _unRegister2 = null; + _disposed = true; + } + + /// + /// 获取等待是否已完成 + /// + public bool IsDone => _done; + + /// + /// 更新方法 + /// + /// 时间增量 + public void Update(double deltaTime) + { + if (!_done || (_unRegister1 == null && _unRegister2 == null)) return; + + _unRegister1?.UnRegister(); + _unRegister2?.UnRegister(); + _unRegister1 = null; + _unRegister2 = null; + } + + /// + /// 第一个事件触发处理 + /// + private void OnFirstEvent(TEvent1 eventData) + { + FirstEventData = eventData; + TriggeredBy = 1; + _done = true; + } + + /// + /// 第二个事件触发处理 + /// + private void OnSecondEvent(TEvent2 eventData) + { + SecondEventData = eventData; + TriggeredBy = 2; + _done = true; + } +} \ No newline at end of file diff --git a/GFramework.Core/coroutine/instructions/WaitForNextFrame.cs b/GFramework.Core/coroutine/instructions/WaitForNextFrame.cs new file mode 100644 index 0000000..8f14644 --- /dev/null +++ b/GFramework.Core/coroutine/instructions/WaitForNextFrame.cs @@ -0,0 +1,26 @@ +using GFramework.Core.Abstractions.coroutine; + +namespace GFramework.Core.coroutine.instructions; + +/// +/// 等待下一帧的指令(与WaitOneFrame功能相同,提供另一种命名选择) +/// 用于需要明确表达"等待到下一帧开始"的场景 +/// +public sealed class WaitForNextFrame : IYieldInstruction +{ + private bool _completed; + + /// + /// 更新方法,在下一帧被调用时将完成状态设置为true + /// + /// 时间间隔 + public void Update(double deltaTime) + { + _completed = true; + } + + /// + /// 获取当前等待指令是否已完成 + /// + public bool IsDone => _completed; +} \ No newline at end of file diff --git a/GFramework.Core/coroutine/instructions/WaitForPredicate.cs b/GFramework.Core/coroutine/instructions/WaitForPredicate.cs new file mode 100644 index 0000000..5c77a05 --- /dev/null +++ b/GFramework.Core/coroutine/instructions/WaitForPredicate.cs @@ -0,0 +1,28 @@ +using GFramework.Core.Abstractions.coroutine; + +namespace GFramework.Core.coroutine.instructions; + +/// +/// 通用谓词等待指令 +/// 支持自定义比较逻辑,可以替代 WaitUntil 和 WaitWhile +/// +/// 条件判断函数 +/// true表示等待条件为真时完成,false表示等待条件为假时完成 +public sealed class WaitForPredicate(Func predicate, bool waitForTrue = true) : IYieldInstruction +{ + private readonly Func _predicate = predicate ?? throw new ArgumentNullException(nameof(predicate)); + + /// + /// 更新协程状态 + /// + /// 时间增量 + public void Update(double deltaTime) + { + // 不需要特殊处理时间 + } + + /// + /// 获取协程指令是否已完成 + /// + public bool IsDone => waitForTrue ? _predicate() : !_predicate(); +} \ No newline at end of file diff --git a/GFramework.Core/coroutine/instructions/WaitForSecondsRealtime.cs b/GFramework.Core/coroutine/instructions/WaitForSecondsRealtime.cs new file mode 100644 index 0000000..541d02a --- /dev/null +++ b/GFramework.Core/coroutine/instructions/WaitForSecondsRealtime.cs @@ -0,0 +1,30 @@ +using GFramework.Core.Abstractions.coroutine; + +namespace GFramework.Core.coroutine.instructions; + +/// +/// 基于真实时间的等待指令(不受时间缩放影响) +/// 适用于需要精确计时的场景,如UI动画、计时器等 +/// +/// 需要等待的秒数 +public sealed class WaitForSecondsRealtime(double seconds) : IYieldInstruction +{ + /// + /// 剩余等待时间(真实时间) + /// + private double _remaining = Math.Max(0, seconds); + + /// + /// 更新延迟计时器(使用真实时间) + /// + /// 时间增量 + public void Update(double deltaTime) + { + _remaining -= deltaTime; + } + + /// + /// 获取延迟是否完成 + /// + public bool IsDone => _remaining <= 0; +} \ No newline at end of file diff --git a/GFramework.Core/coroutine/instructions/WaitForSecondsScaled.cs b/GFramework.Core/coroutine/instructions/WaitForSecondsScaled.cs new file mode 100644 index 0000000..2ae6ee4 --- /dev/null +++ b/GFramework.Core/coroutine/instructions/WaitForSecondsScaled.cs @@ -0,0 +1,30 @@ +using GFramework.Core.Abstractions.coroutine; + +namespace GFramework.Core.coroutine.instructions; + +/// +/// 受时间缩放影响的等待指令 +/// 明确表示会受到游戏时间缩放的影响 +/// +/// 需要等待的秒数 +public sealed class WaitForSecondsScaled(double seconds) : IYieldInstruction +{ + /// + /// 剩余等待时间(受时间缩放影响) + /// + private double _remaining = Math.Max(0, seconds); + + /// + /// 更新延迟计时器(受时间缩放影响) + /// + /// 时间增量 + public void Update(double deltaTime) + { + _remaining -= deltaTime; + } + + /// + /// 获取延迟是否完成 + /// + public bool IsDone => _remaining <= 0; +} \ No newline at end of file diff --git a/GFramework.Core/coroutine/instructions/WaitUntilOrTimeout.cs b/GFramework.Core/coroutine/instructions/WaitUntilOrTimeout.cs new file mode 100644 index 0000000..b90ce2a --- /dev/null +++ b/GFramework.Core/coroutine/instructions/WaitUntilOrTimeout.cs @@ -0,0 +1,40 @@ +using GFramework.Core.Abstractions.coroutine; + +namespace GFramework.Core.coroutine.instructions; + +/// +/// 带超时的条件等待指令 +/// 当条件满足或超时时间到达时完成 +/// +/// 条件判断函数 +/// 超时时间(秒) +public sealed class WaitUntilOrTimeout(Func predicate, double timeoutSeconds) : IYieldInstruction +{ + private readonly Func _predicate = predicate ?? throw new ArgumentNullException(nameof(predicate)); + private readonly double _timeout = Math.Max(0, timeoutSeconds); + private double _elapsedTime; + + /// + /// 获取是否因条件满足而完成 + /// + public bool ConditionMet => _predicate(); + + /// + /// 获取是否因超时而完成 + /// + public bool IsTimedOut => _elapsedTime >= _timeout; + + /// + /// 更新方法,累计时间和检查条件 + /// + /// 时间增量 + public void Update(double deltaTime) + { + _elapsedTime += deltaTime; + } + + /// + /// 获取等待是否已完成(条件满足或超时) + /// + public bool IsDone => ConditionMet || IsTimedOut; +} \ No newline at end of file