diff --git a/GFramework.Core.Tests/coroutine/DelayTests.cs b/GFramework.Core.Tests/coroutine/DelayTests.cs
new file mode 100644
index 00000000..e3ff5dd5
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/DelayTests.cs
@@ -0,0 +1,66 @@
+using GFramework.Core.coroutine.instructions;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine
+{
+ [TestFixture]
+ public class DelayTests
+ {
+ [Test]
+ public void Constructor_SetsInitialRemainingTime()
+ {
+ // Arrange & Act
+ var delay = new Delay(2.5);
+
+ // Assert
+ Assert.That(delay.IsDone, Is.False);
+ }
+
+ [Test]
+ public void Update_ReducesRemainingTime()
+ {
+ // Arrange
+ var delay = new Delay(2.0);
+
+ // Act
+ delay.Update(0.5);
+
+ // Assert
+ Assert.That(delay.IsDone, Is.False);
+ }
+
+ [Test]
+ public void Update_MultipleTimes_EventuallyCompletes()
+ {
+ // Arrange
+ var delay = new Delay(1.0);
+
+ // Act
+ delay.Update(0.5);
+ delay.Update(0.6); // Total: 1.1 > 1.0, so should be done
+
+ // Assert
+ Assert.That(delay.IsDone, Is.True);
+ }
+
+ [Test]
+ public void NegativeTime_TreatedAsZero()
+ {
+ // Arrange & Act
+ var delay = new Delay(-1.0);
+
+ // Assert
+ Assert.That(delay.IsDone, Is.True);
+ }
+
+ [Test]
+ public void ZeroTime_CompletesImmediately()
+ {
+ // Arrange & Act
+ var delay = new Delay(0.0);
+
+ // Assert
+ Assert.That(delay.IsDone, Is.True);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/coroutine/WaitForConditionChangeTests.cs b/GFramework.Core.Tests/coroutine/WaitForConditionChangeTests.cs
new file mode 100644
index 00000000..db91ee28
--- /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/WaitForCoroutineTests.cs b/GFramework.Core.Tests/coroutine/WaitForCoroutineTests.cs
new file mode 100644
index 00000000..768072dc
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/WaitForCoroutineTests.cs
@@ -0,0 +1,42 @@
+using GFramework.Core.Abstractions.coroutine;
+using GFramework.Core.coroutine.instructions;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine
+{
+ [TestFixture]
+ public class WaitForCoroutineTests
+ {
+ [Test]
+ public void Constructor_CreatesInstance()
+ {
+ // Arrange
+ var coroutine = CreateDummyCoroutine();
+
+ // Act
+ var waitForCoroutine = new WaitForCoroutine(coroutine);
+
+ // Assert
+ Assert.That(waitForCoroutine.IsDone, Is.False);
+ }
+
+ [Test]
+ public void Update_DoesNotChangeState()
+ {
+ // Arrange
+ var coroutine = CreateDummyCoroutine();
+ var waitForCoroutine = new WaitForCoroutine(coroutine);
+
+ // Act
+ waitForCoroutine.Update(1.0);
+
+ // Assert
+ Assert.That(waitForCoroutine.IsDone, Is.False);
+ }
+
+ private static IEnumerator CreateDummyCoroutine()
+ {
+ return new List().GetEnumerator();
+ }
+ }
+}
\ 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 00000000..d57ff72c
--- /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 00000000..a5d981fb
--- /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/WaitForFramesTests.cs b/GFramework.Core.Tests/coroutine/WaitForFramesTests.cs
new file mode 100644
index 00000000..43c2a682
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/WaitForFramesTests.cs
@@ -0,0 +1,74 @@
+using GFramework.Core.coroutine.instructions;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine
+{
+ [TestFixture]
+ public class WaitForFramesTests
+ {
+ [Test]
+ public void Constructor_SetsInitialFrameCount()
+ {
+ // Arrange & Act
+ var waitForFrames = new WaitForFrames(3);
+
+ // Assert
+ Assert.That(waitForFrames.IsDone, Is.False);
+ }
+
+ [Test]
+ public void Update_ReducesFrameCount()
+ {
+ // Arrange
+ var waitForFrames = new WaitForFrames(2);
+
+ // Act
+ waitForFrames.Update(0.1);
+
+ // Assert
+ Assert.That(waitForFrames.IsDone, Is.False);
+ }
+
+ [Test]
+ public void MultipleUpdates_EventuallyCompletes()
+ {
+ // Arrange
+ var waitForFrames = new WaitForFrames(2);
+
+ // Act
+ waitForFrames.Update(0.1); // 2-1 = 1 frame remaining
+ waitForFrames.Update(0.1); // 1-1 = 0 frames remaining
+
+ // Assert
+ Assert.That(waitForFrames.IsDone, Is.True);
+ }
+
+ [Test]
+ public void NegativeFrameCount_TreatedAsOne()
+ {
+ // Arrange & Act
+ var waitForFrames = new WaitForFrames(-1);
+
+ // Assert
+ Assert.That(waitForFrames.IsDone, Is.False);
+
+ // One update should complete it
+ waitForFrames.Update(0.1);
+ Assert.That(waitForFrames.IsDone, Is.True);
+ }
+
+ [Test]
+ public void ZeroFrameCount_TreatedAsOne()
+ {
+ // Arrange & Act
+ var waitForFrames = new WaitForFrames(0);
+
+ // Assert
+ Assert.That(waitForFrames.IsDone, Is.False);
+
+ // One update should complete it
+ waitForFrames.Update(0.1);
+ Assert.That(waitForFrames.IsDone, Is.True);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/coroutine/WaitForMultipleEventsTests.cs b/GFramework.Core.Tests/coroutine/WaitForMultipleEventsTests.cs
new file mode 100644
index 00000000..8bc30132
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/WaitForMultipleEventsTests.cs
@@ -0,0 +1,141 @@
+using GFramework.Core.Abstractions.events;
+using GFramework.Core.coroutine.instructions;
+using GFramework.Core.events;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine
+{
+ [TestFixture]
+ public class WaitForMultipleEventsTests
+ {
+ [SetUp]
+ public void SetUp()
+ {
+ eventBus = new EventBus();
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ (eventBus as IDisposable)?.Dispose();
+ }
+
+ private IEventBus eventBus;
+
+ [Test]
+ public void Constructor_RegistersBothEventTypes()
+ {
+ // Arrange & Act
+ var waitForMultipleEvents = new WaitForMultipleEvents(eventBus);
+
+ // Assert
+ Assert.That(waitForMultipleEvents.IsDone, Is.False);
+ Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(0));
+ }
+
+ [Test]
+ public async Task FirstEventWins_WhenBothEventsFired()
+ {
+ // Arrange
+ var waitForMultipleEvents = new WaitForMultipleEvents(eventBus);
+
+ // Act
+ eventBus.Send(new TestEvent1 { Data = "first_event" });
+ eventBus.Send(new TestEvent2 { Data = "second_event" });
+
+ // Assert
+ Assert.That(waitForMultipleEvents.IsDone, Is.True);
+ Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(1)); // First event should win
+ Assert.That(waitForMultipleEvents.FirstEventData?.Data, Is.EqualTo("first_event"));
+ Assert.That(waitForMultipleEvents.SecondEventData, Is.Null);
+ }
+
+ [Test]
+ public async Task SecondEventWins_WhenOnlySecondEventFired()
+ {
+ // Arrange
+ var waitForMultipleEvents = new WaitForMultipleEvents(eventBus);
+
+ // Act
+ eventBus.Send(new TestEvent2 { Data = "second_event" });
+
+ // Assert
+ Assert.That(waitForMultipleEvents.IsDone, Is.True);
+ Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(2)); // Second event should win
+ Assert.That(waitForMultipleEvents.SecondEventData?.Data, Is.EqualTo("second_event"));
+ Assert.That(waitForMultipleEvents.FirstEventData, Is.Null);
+ }
+
+ [Test]
+ public async Task FirstEventWins_WhenBothEventsFiredInReverseOrder()
+ {
+ // Arrange
+ var waitForMultipleEvents = new WaitForMultipleEvents(eventBus);
+
+ // Act
+ eventBus.Send(new TestEvent2 { Data = "second_event" });
+ eventBus.Send(new TestEvent1 { Data = "first_event" });
+
+ // Assert
+ Assert.That(waitForMultipleEvents.IsDone, Is.True);
+ // Actually, the second event should win because it fired first and set _done = true
+ Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(2)); // Second event wins since it fired first
+ Assert.That(waitForMultipleEvents.SecondEventData?.Data, Is.EqualTo("second_event"));
+ Assert.That(waitForMultipleEvents.FirstEventData, Is.Null);
+ }
+
+ [Test]
+ public async Task MultipleEvents_AfterCompletion_DoNotOverrideState()
+ {
+ // Arrange
+ var waitForMultipleEvents = new WaitForMultipleEvents(eventBus);
+
+ // Act - Fire first event
+ eventBus.Send(new TestEvent1 { Data = "first_event" });
+
+ // Verify first event was processed
+ Assert.That(waitForMultipleEvents.IsDone, Is.True);
+ Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(1));
+ Assert.That(waitForMultipleEvents.FirstEventData?.Data, Is.EqualTo("first_event"));
+
+ // Fire second event after completion
+ eventBus.Send(new TestEvent2 { Data = "second_event" });
+
+ // Assert - The state should not change
+ Assert.That(waitForMultipleEvents.IsDone, Is.True);
+ Assert.That(waitForMultipleEvents.TriggeredBy, Is.EqualTo(1)); // Should remain as 1, not change to 2
+ Assert.That(waitForMultipleEvents.FirstEventData?.Data,
+ Is.EqualTo("first_event")); // Should remain unchanged
+ Assert.That(waitForMultipleEvents.SecondEventData, Is.Null); // Should remain null
+ }
+
+ [Test]
+ public async Task Disposal_PreventsFurtherEventHandling()
+ {
+ // Arrange
+ var waitForMultipleEvents = new WaitForMultipleEvents(eventBus);
+
+ // Act - Dispose the instance
+ waitForMultipleEvents.Dispose();
+
+ // Fire an event after disposal
+ eventBus.Send(new TestEvent1 { Data = "after_disposal" });
+
+ // Assert - Event should not be processed due to disposal
+ // Since we disposed, no event data should be captured
+ Assert.That(waitForMultipleEvents.FirstEventData, Is.Null);
+ Assert.That(waitForMultipleEvents.IsDone, Is.False); // Should remain false after disposal
+ }
+
+ // Test event classes
+ private class TestEvent1
+ {
+ public string Data { get; set; } = string.Empty;
+ }
+
+ private class TestEvent2
+ {
+ public string Data { get; set; } = string.Empty;
+ }
+ }
+}
\ 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 00000000..fabff301
--- /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 00000000..d46f808d
--- /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 00000000..af86fc9b
--- /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 00000000..a017fb34
--- /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/WaitForTaskTTests.cs b/GFramework.Core.Tests/coroutine/WaitForTaskTTests.cs
new file mode 100644
index 00000000..ab446cda
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/WaitForTaskTTests.cs
@@ -0,0 +1,96 @@
+using GFramework.Core.coroutine.instructions;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine
+{
+ [TestFixture]
+ public class WaitForTaskTTests
+ {
+ [Test]
+ public void Constructor_WithNullTask_ThrowsArgumentNullException()
+ {
+ // Act & Assert
+ Assert.Throws(() => new WaitForTask(null!));
+ }
+
+ [Test]
+ public async Task Constructor_WithCompletedTask_IsDoneImmediately()
+ {
+ // Arrange
+ var completedTask = Task.FromResult("test");
+
+ // Act
+ var waitForTask = new WaitForTask(completedTask);
+
+ // Assert
+ Assert.That(waitForTask.IsDone, Is.True);
+ Assert.That(waitForTask.Result, Is.EqualTo("test"));
+ }
+
+ [Test]
+ public async Task Constructor_WithIncompleteTask_IsNotDoneInitially()
+ {
+ // Arrange
+ var tcs = new TaskCompletionSource();
+ var incompleteTask = tcs.Task;
+
+ // Act
+ var waitForTask = new WaitForTask(incompleteTask);
+
+ // Assert
+ Assert.That(waitForTask.IsDone, Is.False);
+ }
+
+ [Test]
+ public async Task TaskCompletes_CallbackSetsDoneFlag()
+ {
+ // Arrange
+ var tcs = new TaskCompletionSource();
+ var task = tcs.Task;
+ var waitForTask = new WaitForTask(task);
+
+ // Assert initial state
+ Assert.That(waitForTask.IsDone, Is.False);
+
+ // Act
+ tcs.SetResult("completed");
+ await Task.Delay(10); // Allow time for continuation
+
+ // Assert final state
+ Assert.That(waitForTask.IsDone, Is.True);
+ Assert.That(waitForTask.Result, Is.EqualTo("completed"));
+ }
+
+ [Test]
+ public async Task Update_DoesNotChangeState()
+ {
+ // Arrange
+ var completedTask = Task.FromResult("test");
+ var waitForTask = new WaitForTask(completedTask);
+
+ // Act
+ waitForTask.Update(0.1);
+
+ // Assert
+ Assert.That(waitForTask.IsDone, Is.True);
+ }
+
+ [Test]
+ public async Task TaskWithException_HoldsException()
+ {
+ // Arrange
+ var tcs = new TaskCompletionSource();
+ var task = tcs.Task;
+ var waitForTask = new WaitForTask(task);
+
+ // Act
+ tcs.SetException(new InvalidOperationException("Test exception"));
+ await Task.Delay(10); // Allow time for continuation
+
+ // Assert
+ Assert.That(waitForTask.IsDone, Is.True);
+ Assert.That(waitForTask.Exception, Is.Not.Null);
+ Assert.That(waitForTask.Exception?.InnerException, Is.TypeOf());
+ }
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/coroutine/WaitOneFrameTests.cs b/GFramework.Core.Tests/coroutine/WaitOneFrameTests.cs
new file mode 100644
index 00000000..1f2af7ad
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/WaitOneFrameTests.cs
@@ -0,0 +1,46 @@
+using GFramework.Core.coroutine.instructions;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine
+{
+ [TestFixture]
+ public class WaitOneFrameTests
+ {
+ [Test]
+ public void Constructor_CreatesInstance()
+ {
+ // Act
+ var waitOneFrame = new WaitOneFrame();
+
+ // Assert
+ Assert.That(waitOneFrame.IsDone, Is.False);
+ }
+
+ [Test]
+ public void Update_MakesItDone()
+ {
+ // Arrange
+ var waitOneFrame = new WaitOneFrame();
+
+ // Act
+ waitOneFrame.Update(0.1);
+
+ // Assert
+ Assert.That(waitOneFrame.IsDone, Is.True);
+ }
+
+ [Test]
+ public void Update_MultipleTimes_RemainsDone()
+ {
+ // Arrange
+ var waitOneFrame = new WaitOneFrame();
+
+ // Act
+ waitOneFrame.Update(0.1);
+ waitOneFrame.Update(0.1);
+
+ // Assert
+ Assert.That(waitOneFrame.IsDone, Is.True);
+ }
+ }
+}
\ 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 00000000..c9b04d36
--- /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.Tests/coroutine/WaitUntilTests.cs b/GFramework.Core.Tests/coroutine/WaitUntilTests.cs
new file mode 100644
index 00000000..47fffb77
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/WaitUntilTests.cs
@@ -0,0 +1,55 @@
+using GFramework.Core.coroutine.instructions;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine
+{
+ [TestFixture]
+ public class WaitUntilTests
+ {
+ [Test]
+ public void Constructor_WithNullPredicate_ThrowsArgumentNullException()
+ {
+ // Act & Assert
+ Assert.Throws(() => new WaitUntil(null!));
+ }
+
+ [Test]
+ public void IsDone_ReturnsPredicateResult_True()
+ {
+ // Arrange
+ var condition = false;
+ var waitUntil = new WaitUntil(() => condition);
+
+ // Act
+ condition = true;
+
+ // Assert
+ Assert.That(waitUntil.IsDone, Is.True);
+ }
+
+ [Test]
+ public void IsDone_ReturnsPredicateResult_False()
+ {
+ // Arrange
+ var condition = false;
+ var waitUntil = new WaitUntil(() => condition);
+
+ // Assert
+ Assert.That(waitUntil.IsDone, Is.False);
+ }
+
+ [Test]
+ public void Update_DoesNotChangeState()
+ {
+ // Arrange
+ var condition = false;
+ var waitUntil = new WaitUntil(() => condition);
+
+ // Act
+ waitUntil.Update(0.1);
+
+ // Assert
+ Assert.That(waitUntil.IsDone, Is.False);
+ }
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Core.Tests/coroutine/WaitWhileTests.cs b/GFramework.Core.Tests/coroutine/WaitWhileTests.cs
new file mode 100644
index 00000000..9829b7ed
--- /dev/null
+++ b/GFramework.Core.Tests/coroutine/WaitWhileTests.cs
@@ -0,0 +1,66 @@
+using GFramework.Core.coroutine.instructions;
+using NUnit.Framework;
+
+namespace GFramework.Core.Tests.coroutine
+{
+ [TestFixture]
+ public class WaitWhileTests
+ {
+ [Test]
+ public void Constructor_WithNullPredicate_ThrowsArgumentNullException()
+ {
+ // Act & Assert
+ Assert.Throws(() => new WaitWhile(null!));
+ }
+
+ [Test]
+ public void IsDone_ReturnsInverseOfPredicateResult_True()
+ {
+ // Arrange
+ var condition = true;
+ var waitWhile = new WaitWhile(() => condition);
+
+ // Act
+ condition = false;
+
+ // Assert
+ Assert.That(waitWhile.IsDone, Is.True);
+ }
+
+ [Test]
+ public void IsDone_ReturnsInverseOfPredicateResult_False()
+ {
+ // Arrange
+ var condition = false;
+ var waitWhile = new WaitWhile(() => condition);
+
+ // Assert
+ Assert.That(waitWhile.IsDone, Is.True); // Because !false = true
+ }
+
+ [Test]
+ public void IsDone_WhenPredicateReturnsTrue()
+ {
+ // Arrange
+ var condition = true;
+ var waitWhile = new WaitWhile(() => condition);
+
+ // Assert
+ Assert.That(waitWhile.IsDone, Is.False); // Because !true = false
+ }
+
+ [Test]
+ public void Update_DoesNotChangeState()
+ {
+ // Arrange
+ var condition = true;
+ var waitWhile = new WaitWhile(() => condition);
+
+ // Act
+ waitWhile.Update(0.1);
+
+ // Assert
+ Assert.That(waitWhile.IsDone, Is.False);
+ }
+ }
+}
\ 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 00000000..0380daf8
--- /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 00000000..f03c48fa
--- /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 00000000..a2ebe6c7
--- /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 00000000..3b5a7c7d
--- /dev/null
+++ b/GFramework.Core/coroutine/instructions/WaitForMultipleEvents.cs
@@ -0,0 +1,117 @@
+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)
+ {
+ // 如果已经完成或者被释放,则直接返回
+ if (_done || _disposed) return;
+
+ FirstEventData = eventData;
+ TriggeredBy = 1;
+ _done = true;
+
+ // 立即注销事件监听器
+ _unRegister1?.UnRegister();
+ _unRegister2?.UnRegister();
+ _unRegister1 = null;
+ _unRegister2 = null;
+ }
+
+ ///
+ /// 第二个事件触发处理
+ ///
+ private void OnSecondEvent(TEvent2 eventData)
+ {
+ // 如果已经完成或者被释放,则直接返回
+ if (_done || _disposed) return;
+
+ SecondEventData = eventData;
+ TriggeredBy = 2;
+ _done = true;
+
+ // 立即注销事件监听器
+ _unRegister1?.UnRegister();
+ _unRegister2?.UnRegister();
+ _unRegister1 = null;
+ _unRegister2 = null;
+ }
+}
\ 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 00000000..8f146445
--- /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 00000000..5c77a05e
--- /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 00000000..541d02ab
--- /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 00000000..2ae6ee4e
--- /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 00000000..b90ce2a4
--- /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