diff --git a/GFramework.Godot/coroutine/Segment.cs b/GFramework.Godot/coroutine/Segment.cs index 8ed2fb6..5d4cc50 100644 --- a/GFramework.Godot/coroutine/Segment.cs +++ b/GFramework.Godot/coroutine/Segment.cs @@ -6,10 +6,15 @@ public enum Segment { /// - /// 普通处理阶段,在每一帧的常规处理过程中执行 + /// 普通处理阶段,在每一帧的常规处理过程中执行(默认用于游戏级协程) /// Process, + /// + /// 在暂停状态下仍然执行的处理阶段,适合暂停菜单等需要继续更新的UI级协程 + /// + ProcessIgnorePause, + /// /// 物理处理阶段,在物理更新循环中执行,通常用于需要与物理引擎同步的操作 /// @@ -19,4 +24,4 @@ public enum Segment /// 延迟处理阶段,在当前帧结束后延迟执行,通常用于需要等待当前帧完成后再执行的操作 /// DeferredProcess -} \ No newline at end of file +} diff --git a/GFramework.Godot/coroutine/Timing.cs b/GFramework.Godot/coroutine/Timing.cs index 9a5a2d2..29fdf6c 100644 --- a/GFramework.Godot/coroutine/Timing.cs +++ b/GFramework.Godot/coroutine/Timing.cs @@ -26,6 +26,8 @@ public partial class Timing : Node private CoroutineScheduler? _processScheduler; private GodotTimeSource? _processTimeSource; + private CoroutineScheduler? _processIgnorePauseScheduler; + private GodotTimeSource? _processIgnorePauseTimeSource; /// /// 获取Process调度器,如果未初始化则抛出异常 @@ -34,6 +36,13 @@ public partial class Timing : Node _processScheduler ?? throw new InvalidOperationException( "Timing not yet initialized (_Ready not executed)"); + /// + /// 获取忽略暂停的Process调度器,如果未初始化则抛出异常 + /// + private CoroutineScheduler ProcessIgnorePauseScheduler => + _processIgnorePauseScheduler ?? throw new InvalidOperationException( + "Timing not yet initialized (_Ready not executed)"); + /// /// 获取Physics调度器,如果未初始化则抛出异常 /// @@ -108,6 +117,7 @@ public partial class Timing : Node public override void _Ready() { ProcessPriority = -1; + ProcessMode = ProcessModeEnum.Always; TrySetPhysicsPriority(-1); @@ -142,7 +152,12 @@ public partial class Timing : Node /// 时间增量 public override void _Process(double delta) { - _processScheduler?.Update(); + var paused = GetTree().Paused; + + if (!paused) + _processScheduler?.Update(); + + _processIgnorePauseScheduler?.Update(); _frameCounter++; CallDeferred(nameof(ProcessDeferred)); @@ -164,6 +179,9 @@ public partial class Timing : Node /// private void ProcessDeferred() { + if (GetTree().Paused) + return; + _deferredScheduler?.Update(); } @@ -187,6 +205,7 @@ public partial class Timing : Node private void InitializeSchedulers() { _processTimeSource = new GodotTimeSource(GetProcessDeltaTime); + _processIgnorePauseTimeSource = new GodotTimeSource(GetProcessDeltaTime); _physicsTimeSource = new GodotTimeSource(GetPhysicsProcessDeltaTime); _deferredTimeSource = new GodotTimeSource(GetProcessDeltaTime); @@ -195,6 +214,11 @@ public partial class Timing : Node _instanceId ); + _processIgnorePauseScheduler = new CoroutineScheduler( + _processIgnorePauseTimeSource, + _instanceId + ); + _physicsScheduler = new CoroutineScheduler( _physicsTimeSource, _instanceId, @@ -206,6 +230,7 @@ public partial class Timing : Node _instanceId, 64 ); + } /// @@ -257,6 +282,32 @@ public partial class Timing : Node #region 协程启动 API + /// + /// 运行游戏级协程(受暂停影响) + /// + /// 要运行的协程枚举器 + /// 协程标签,用于批量操作 + /// 协程句柄 + public static CoroutineHandle RunGameCoroutine( + IEnumerator coroutine, + string? tag = null) + { + return RunCoroutine(coroutine, Segment.Process, tag); + } + + /// + /// 运行UI级协程(忽略暂停) + /// + /// 要运行的协程枚举器 + /// 协程标签,用于批量操作 + /// 协程句柄 + public static CoroutineHandle RunUiCoroutine( + IEnumerator coroutine, + string? tag = null) + { + return RunCoroutine(coroutine, Segment.ProcessIgnorePause, tag); + } + /// /// 在指定段运行协程 /// @@ -291,6 +342,7 @@ public partial class Timing : Node return segment switch { Segment.Process => ProcessScheduler.Run(coroutine, tag), + Segment.ProcessIgnorePause => ProcessIgnorePauseScheduler.Run(coroutine, tag), Segment.PhysicsProcess => PhysicsScheduler.Run(coroutine, tag), Segment.DeferredProcess => DeferredScheduler.Run(coroutine, tag), _ => default @@ -359,6 +411,7 @@ public partial class Timing : Node private bool PauseOnInstance(CoroutineHandle handle) { return ProcessScheduler.Pause(handle) + || ProcessIgnorePauseScheduler.Pause(handle) || PhysicsScheduler.Pause(handle) || DeferredScheduler.Pause(handle); } @@ -372,6 +425,7 @@ public partial class Timing : Node private bool ResumeOnInstance(CoroutineHandle handle) { return ProcessScheduler.Resume(handle) + || ProcessIgnorePauseScheduler.Resume(handle) || PhysicsScheduler.Resume(handle) || DeferredScheduler.Resume(handle); } @@ -385,6 +439,7 @@ public partial class Timing : Node private bool KillOnInstance(CoroutineHandle handle) { return ProcessScheduler.Kill(handle) + || ProcessIgnorePauseScheduler.Kill(handle) || PhysicsScheduler.Kill(handle) || DeferredScheduler.Kill(handle); } @@ -399,6 +454,7 @@ public partial class Timing : Node { var count = 0; count += ProcessScheduler.KillByTag(tag); + count += ProcessIgnorePauseScheduler.KillByTag(tag); count += PhysicsScheduler.KillByTag(tag); count += DeferredScheduler.KillByTag(tag); return count; @@ -413,6 +469,7 @@ public partial class Timing : Node { var count = 0; count += ProcessScheduler.Clear(); + count += ProcessIgnorePauseScheduler.Clear(); count += PhysicsScheduler.Clear(); count += DeferredScheduler.Clear(); return count; @@ -524,4 +581,4 @@ public partial class Timing : Node } #endregion -} \ No newline at end of file +}