mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
- 将 OnPauseStateChanged 事件从 Action<PauseGroup, bool> 类型改为 EventHandler<PauseStateChangedEventArgs> - 添加 PauseStateChangedEventArgs 类来封装事件数据 - 更新所有事件处理方法的签名以匹配新的事件参数 - 修改文档中相关的事件处理代码示例 - 在 PauseStackManager 中添加 RaisePauseStateChanged 方法统一处理事件触发 - 更新测试代码以适应新的事件处理方式
737 lines
18 KiB
Markdown
737 lines
18 KiB
Markdown
---
|
||
title: Godot 暂停处理
|
||
description: Godot 暂停处理系统提供了 GFramework 暂停管理与 Godot SceneTree 暂停的完整集成。
|
||
---
|
||
|
||
# Godot 暂停处理
|
||
|
||
## 概述
|
||
|
||
Godot 暂停处理系统是 GFramework.Godot 中连接框架暂停管理与 Godot 引擎暂停机制的核心组件。它提供了暂停栈管理、分组暂停、嵌套暂停等功能,让你可以在
|
||
Godot 项目中使用 GFramework 的暂停系统。
|
||
|
||
通过 Godot 暂停处理系统,你可以实现精细的暂停控制,支持游戏逻辑暂停、UI 暂停、动画暂停等多种场景,同时保持与 Godot SceneTree
|
||
暂停机制的完美兼容。
|
||
|
||
**主要特性**:
|
||
|
||
- 暂停栈管理(支持嵌套暂停)
|
||
- 分组暂停(Global、Gameplay、Animation、Audio 等)
|
||
- 与 Godot SceneTree.Paused 集成
|
||
- 暂停处理器机制
|
||
- 暂停作用域(支持 using 语法)
|
||
- 线程安全的暂停管理
|
||
|
||
## 核心概念
|
||
|
||
### 暂停栈管理器
|
||
|
||
`IPauseStackManager` 管理游戏中的暂停状态:
|
||
|
||
```csharp
|
||
public interface IPauseStackManager : IContextUtility
|
||
{
|
||
// 推入暂停请求
|
||
PauseToken Push(string reason, PauseGroup group = PauseGroup.Global);
|
||
|
||
// 弹出暂停请求
|
||
bool Pop(PauseToken token);
|
||
|
||
// 查询是否暂停
|
||
bool IsPaused(PauseGroup group = PauseGroup.Global);
|
||
|
||
// 获取暂停深度
|
||
int GetPauseDepth(PauseGroup group = PauseGroup.Global);
|
||
|
||
// 暂停状态变化事件
|
||
event EventHandler<PauseStateChangedEventArgs>? OnPauseStateChanged;
|
||
}
|
||
```
|
||
|
||
### 暂停组
|
||
|
||
`PauseGroup` 定义不同的暂停作用域:
|
||
|
||
```csharp
|
||
public enum PauseGroup
|
||
{
|
||
Global = 0, // 全局暂停(影响所有系统)
|
||
Gameplay = 1, // 游戏逻辑暂停(不影响 UI)
|
||
Animation = 2, // 动画暂停
|
||
Audio = 3, // 音频暂停
|
||
Custom1 = 10, // 自定义组 1
|
||
Custom2 = 11, // 自定义组 2
|
||
Custom3 = 12 // 自定义组 3
|
||
}
|
||
```
|
||
|
||
### 暂停令牌
|
||
|
||
`PauseToken` 唯一标识一个暂停请求:
|
||
|
||
```csharp
|
||
public readonly struct PauseToken
|
||
{
|
||
public Guid Id { get; }
|
||
public bool IsValid { get; }
|
||
}
|
||
```
|
||
|
||
### Godot 暂停处理器
|
||
|
||
`GodotPauseHandler` 响应暂停栈状态变化,控制 SceneTree.Paused:
|
||
|
||
```csharp
|
||
public class GodotPauseHandler : IPauseHandler
|
||
{
|
||
public int Priority => 0;
|
||
|
||
public void OnPauseStateChanged(PauseGroup group, bool isPaused)
|
||
{
|
||
// 只有 Global 组影响 Godot 的全局暂停
|
||
if (group == PauseGroup.Global)
|
||
{
|
||
_tree.Paused = isPaused;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 基本用法
|
||
|
||
### 设置暂停系统
|
||
|
||
```csharp
|
||
using GFramework.Godot.Architecture;
|
||
using GFramework.Godot.Pause;
|
||
using GFramework.Core.Pause;
|
||
|
||
public class GameArchitecture : AbstractArchitecture
|
||
{
|
||
protected override void InstallModules()
|
||
{
|
||
// 注册暂停栈管理器
|
||
var pauseManager = new PauseStackManager();
|
||
RegisterUtility<IPauseStackManager>(pauseManager);
|
||
|
||
// 注册 Godot 暂停处理器
|
||
var pauseHandler = new GodotPauseHandler(GetTree());
|
||
pauseManager.RegisterHandler(pauseHandler);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 基本暂停和恢复
|
||
|
||
```csharp
|
||
using Godot;
|
||
using GFramework.Godot.Extensions;
|
||
|
||
public partial class PauseMenu : Control
|
||
{
|
||
private PauseToken _pauseToken;
|
||
|
||
public void ShowPauseMenu()
|
||
{
|
||
// 暂停游戏
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
_pauseToken = pauseManager.Push("Pause menu opened");
|
||
|
||
Show();
|
||
}
|
||
|
||
public void HidePauseMenu()
|
||
{
|
||
// 恢复游戏
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
pauseManager.Pop(_pauseToken);
|
||
|
||
Hide();
|
||
}
|
||
}
|
||
```
|
||
|
||
### 使用暂停作用域
|
||
|
||
```csharp
|
||
using Godot;
|
||
using GFramework.Godot.Extensions;
|
||
|
||
public partial class DialogBox : Control
|
||
{
|
||
public async void ShowDialog()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
|
||
// 使用 using 语法自动管理暂停
|
||
using (pauseManager.PauseScope("Dialog shown"))
|
||
{
|
||
Show();
|
||
await ToSignal(GetTree().CreateTimer(3.0f), "timeout");
|
||
Hide();
|
||
} // 自动恢复
|
||
}
|
||
}
|
||
```
|
||
|
||
### 查询暂停状态
|
||
|
||
```csharp
|
||
using Godot;
|
||
using GFramework.Godot.Extensions;
|
||
|
||
public partial class GameController : Node
|
||
{
|
||
public override void _Process(double delta)
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
|
||
// 检查是否暂停
|
||
if (pauseManager.IsPaused())
|
||
{
|
||
GD.Print("游戏已暂停");
|
||
return;
|
||
}
|
||
|
||
// 游戏逻辑
|
||
UpdateGame(delta);
|
||
}
|
||
|
||
private void UpdateGame(double delta)
|
||
{
|
||
// 游戏更新逻辑
|
||
}
|
||
}
|
||
```
|
||
|
||
## 高级用法
|
||
|
||
### 分组暂停
|
||
|
||
```csharp
|
||
using Godot;
|
||
using GFramework.Godot.Extensions;
|
||
|
||
public partial class GameManager : Node
|
||
{
|
||
private PauseToken _gameplayPauseToken;
|
||
private PauseToken _animationPauseToken;
|
||
|
||
// 只暂停游戏逻辑,UI 仍然可以交互
|
||
public void PauseGameplay()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
_gameplayPauseToken = pauseManager.Push("Gameplay paused", PauseGroup.Gameplay);
|
||
}
|
||
|
||
public void ResumeGameplay()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
pauseManager.Pop(_gameplayPauseToken);
|
||
}
|
||
|
||
// 只暂停动画
|
||
public void PauseAnimations()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
_animationPauseToken = pauseManager.Push("Animations paused", PauseGroup.Animation);
|
||
}
|
||
|
||
public void ResumeAnimations()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
pauseManager.Pop(_animationPauseToken);
|
||
}
|
||
|
||
// 检查特定组的暂停状态
|
||
public bool IsGameplayPaused()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
return pauseManager.IsPaused(PauseGroup.Gameplay);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 嵌套暂停
|
||
|
||
```csharp
|
||
using Godot;
|
||
using GFramework.Godot.Extensions;
|
||
|
||
public partial class GameScene : Node
|
||
{
|
||
public async void ShowNestedDialogs()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
|
||
// 第一层暂停
|
||
using (pauseManager.PauseScope("First dialog"))
|
||
{
|
||
GD.Print($"暂停深度: {pauseManager.GetPauseDepth()}"); // 输出: 1
|
||
ShowDialog("第一个对话框");
|
||
await ToSignal(GetTree().CreateTimer(2.0f), "timeout");
|
||
|
||
// 第二层暂停
|
||
using (pauseManager.PauseScope("Second dialog"))
|
||
{
|
||
GD.Print($"暂停深度: {pauseManager.GetPauseDepth()}"); // 输出: 2
|
||
ShowDialog("第二个对话框");
|
||
await ToSignal(GetTree().CreateTimer(2.0f), "timeout");
|
||
}
|
||
|
||
GD.Print($"暂停深度: {pauseManager.GetPauseDepth()}"); // 输出: 1
|
||
}
|
||
|
||
GD.Print($"暂停深度: {pauseManager.GetPauseDepth()}"); // 输出: 0
|
||
}
|
||
|
||
private void ShowDialog(string message)
|
||
{
|
||
GD.Print(message);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 自定义暂停处理器
|
||
|
||
```csharp
|
||
using GFramework.Core.Abstractions.Pause;
|
||
using Godot;
|
||
|
||
// 自定义动画暂停处理器
|
||
public class AnimationPauseHandler : IPauseHandler
|
||
{
|
||
private readonly AnimationPlayer _animationPlayer;
|
||
|
||
public AnimationPauseHandler(AnimationPlayer animationPlayer)
|
||
{
|
||
_animationPlayer = animationPlayer;
|
||
}
|
||
|
||
public int Priority => 10;
|
||
|
||
public void OnPauseStateChanged(PauseGroup group, bool isPaused)
|
||
{
|
||
// 只响应 Animation 组
|
||
if (group == PauseGroup.Animation)
|
||
{
|
||
if (isPaused)
|
||
{
|
||
_animationPlayer.Pause();
|
||
GD.Print("动画已暂停");
|
||
}
|
||
else
|
||
{
|
||
_animationPlayer.Play();
|
||
GD.Print("动画已恢复");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 注册自定义处理器
|
||
public partial class GameController : Node
|
||
{
|
||
public override void _Ready()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
var animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
||
|
||
var animationHandler = new AnimationPauseHandler(animationPlayer);
|
||
pauseManager.RegisterHandler(animationHandler);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 音频暂停处理器
|
||
|
||
```csharp
|
||
using GFramework.Core.Abstractions.Pause;
|
||
using Godot;
|
||
|
||
public class AudioPauseHandler : IPauseHandler
|
||
{
|
||
private readonly AudioStreamPlayer _musicPlayer;
|
||
private readonly AudioStreamPlayer _sfxPlayer;
|
||
|
||
public AudioPauseHandler(AudioStreamPlayer musicPlayer, AudioStreamPlayer sfxPlayer)
|
||
{
|
||
_musicPlayer = musicPlayer;
|
||
_sfxPlayer = sfxPlayer;
|
||
}
|
||
|
||
public int Priority => 20;
|
||
|
||
public void OnPauseStateChanged(PauseGroup group, bool isPaused)
|
||
{
|
||
if (group == PauseGroup.Audio || group == PauseGroup.Global)
|
||
{
|
||
if (isPaused)
|
||
{
|
||
_musicPlayer.StreamPaused = true;
|
||
_sfxPlayer.StreamPaused = true;
|
||
}
|
||
else
|
||
{
|
||
_musicPlayer.StreamPaused = false;
|
||
_sfxPlayer.StreamPaused = false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 节点暂停模式控制
|
||
|
||
```csharp
|
||
using Godot;
|
||
using GFramework.Godot.Extensions;
|
||
|
||
public partial class GameNode : Node
|
||
{
|
||
public override void _Ready()
|
||
{
|
||
// 设置节点在暂停时的行为
|
||
|
||
// 暂停时停止处理
|
||
ProcessMode = ProcessModeEnum.Pausable;
|
||
|
||
// 暂停时继续处理(用于 UI)
|
||
// ProcessMode = ProcessModeEnum.Always;
|
||
|
||
// 暂停时停止,且子节点也停止
|
||
// ProcessMode = ProcessModeEnum.Inherit;
|
||
}
|
||
|
||
public override void _Process(double delta)
|
||
{
|
||
// 当 SceneTree.Paused = true 且 ProcessMode = Pausable 时
|
||
// 此方法不会被调用
|
||
UpdateGameLogic(delta);
|
||
}
|
||
|
||
private void UpdateGameLogic(double delta)
|
||
{
|
||
// 游戏逻辑
|
||
}
|
||
}
|
||
```
|
||
|
||
### UI 在暂停时继续工作
|
||
|
||
```csharp
|
||
using Godot;
|
||
using GFramework.Godot.Extensions;
|
||
|
||
public partial class PauseMenuUI : Control
|
||
{
|
||
public override void _Ready()
|
||
{
|
||
// UI 在游戏暂停时仍然可以交互
|
||
ProcessMode = ProcessModeEnum.Always;
|
||
|
||
GetNode<Button>("ResumeButton").Pressed += OnResumePressed;
|
||
GetNode<Button>("QuitButton").Pressed += OnQuitPressed;
|
||
}
|
||
|
||
private void OnResumePressed()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
|
||
// 获取所有暂停原因
|
||
var reasons = pauseManager.GetPauseReasons();
|
||
GD.Print($"当前暂停原因: {string.Join(", ", reasons)}");
|
||
|
||
// 清空所有暂停
|
||
pauseManager.ClearAll();
|
||
|
||
Hide();
|
||
}
|
||
|
||
private void OnQuitPressed()
|
||
{
|
||
GetTree().Quit();
|
||
}
|
||
}
|
||
```
|
||
|
||
### 监听暂停状态变化
|
||
|
||
```csharp
|
||
using Godot;
|
||
using GFramework.Godot.Extensions;
|
||
|
||
public partial class PauseIndicator : Label
|
||
{
|
||
public override void _Ready()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
|
||
// 订阅暂停状态变化事件
|
||
pauseManager.OnPauseStateChanged += OnPauseStateChanged;
|
||
}
|
||
|
||
public override void _ExitTree()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
pauseManager.OnPauseStateChanged -= OnPauseStateChanged;
|
||
}
|
||
|
||
private void OnPauseStateChanged(object? sender, PauseStateChangedEventArgs e)
|
||
{
|
||
if (e.Group == PauseGroup.Global)
|
||
{
|
||
Text = e.IsPaused ? "游戏已暂停" : "游戏运行中";
|
||
Visible = e.IsPaused;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 调试暂停状态
|
||
|
||
```csharp
|
||
using Godot;
|
||
using GFramework.Godot.Extensions;
|
||
|
||
public partial class PauseDebugger : Node
|
||
{
|
||
public override void _Ready()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
pauseManager.OnPauseStateChanged += OnPauseStateChanged;
|
||
}
|
||
|
||
private void OnPauseStateChanged(object? sender, PauseStateChangedEventArgs e)
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
|
||
GD.Print($"=== 暂停状态变化 ===");
|
||
GD.Print($"组: {e.Group}");
|
||
GD.Print($"状态: {(e.IsPaused ? "暂停" : "恢复")}");
|
||
GD.Print($"深度: {pauseManager.GetPauseDepth(e.Group)}");
|
||
|
||
var reasons = pauseManager.GetPauseReasons(e.Group);
|
||
if (reasons.Count > 0)
|
||
{
|
||
GD.Print($"原因:");
|
||
foreach (var reason in reasons)
|
||
{
|
||
GD.Print($" - {reason}");
|
||
}
|
||
}
|
||
}
|
||
|
||
public override void _Input(InputEvent @event)
|
||
{
|
||
// 按 F12 显示所有暂停状态
|
||
if (@event is InputEventKey keyEvent && keyEvent.Pressed && keyEvent.Keycode == Key.F12)
|
||
{
|
||
PrintAllPauseStates();
|
||
}
|
||
}
|
||
|
||
private void PrintAllPauseStates()
|
||
{
|
||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||
|
||
GD.Print("=== 所有暂停状态 ===");
|
||
|
||
foreach (PauseGroup group in Enum.GetValues(typeof(PauseGroup)))
|
||
{
|
||
var isPaused = pauseManager.IsPaused(group);
|
||
var depth = pauseManager.GetPauseDepth(group);
|
||
|
||
if (depth > 0)
|
||
{
|
||
GD.Print($"{group}: 暂停 (深度: {depth})");
|
||
var reasons = pauseManager.GetPauseReasons(group);
|
||
foreach (var reason in reasons)
|
||
{
|
||
GD.Print($" - {reason}");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
1. **使用暂停作用域管理生命周期**:避免忘记恢复
|
||
```csharp
|
||
✓ using (pauseManager.PauseScope("Dialog")) { ... }
|
||
✗ var token = pauseManager.Push("Dialog"); // 可能忘记 Pop
|
||
```
|
||
|
||
2. **为暂停提供清晰的原因**:便于调试
|
||
```csharp
|
||
✓ pauseManager.Push("Inventory opened");
|
||
✗ pauseManager.Push("pause"); // 原因不明确
|
||
```
|
||
|
||
3. **使用正确的暂停组**:避免影响不该暂停的系统
|
||
```csharp
|
||
✓ pauseManager.Push("Menu", PauseGroup.Gameplay); // 只暂停游戏逻辑
|
||
✗ pauseManager.Push("Menu", PauseGroup.Global); // 暂停所有系统包括 UI
|
||
```
|
||
|
||
4. **UI 节点设置 ProcessMode.Always**:确保 UI 在暂停时可用
|
||
```csharp
|
||
public override void _Ready()
|
||
{
|
||
ProcessMode = ProcessModeEnum.Always;
|
||
}
|
||
```
|
||
|
||
5. **游戏逻辑节点设置 ProcessMode.Pausable**:确保暂停时停止
|
||
```csharp
|
||
public override void _Ready()
|
||
{
|
||
ProcessMode = ProcessModeEnum.Pausable;
|
||
}
|
||
```
|
||
|
||
6. **保存暂停令牌以便恢复**:确保能正确恢复暂停
|
||
```csharp
|
||
private PauseToken _pauseToken;
|
||
|
||
public void Pause()
|
||
{
|
||
_pauseToken = pauseManager.Push("Paused");
|
||
}
|
||
|
||
public void Resume()
|
||
{
|
||
pauseManager.Pop(_pauseToken);
|
||
}
|
||
```
|
||
|
||
7. **使用事件监听暂停状态**:实现响应式 UI
|
||
```csharp
|
||
pauseManager.OnPauseStateChanged += (_, e) =>
|
||
{
|
||
UpdateUI(e.IsPaused);
|
||
};
|
||
```
|
||
|
||
8. **清理时注销事件监听**:避免内存泄漏
|
||
```csharp
|
||
public override void _ExitTree()
|
||
{
|
||
pauseManager.OnPauseStateChanged -= OnPauseStateChanged;
|
||
}
|
||
```
|
||
|
||
## 常见问题
|
||
|
||
### 问题:如何暂停游戏但保持 UI 可交互?
|
||
|
||
**解答**:
|
||
使用 `PauseGroup.Gameplay` 而不是 `PauseGroup.Global`:
|
||
|
||
```csharp
|
||
// 只暂停游戏逻辑
|
||
pauseManager.Push("Menu opened", PauseGroup.Gameplay);
|
||
|
||
// UI 节点设置为 Always
|
||
public override void _Ready()
|
||
{
|
||
ProcessMode = ProcessModeEnum.Always;
|
||
}
|
||
```
|
||
|
||
### 问题:嵌套暂停如何工作?
|
||
|
||
**解答**:
|
||
暂停栈支持嵌套,需要所有 Pop 才能完全恢复:
|
||
|
||
```csharp
|
||
var token1 = pauseManager.Push("First"); // 深度: 1, 暂停
|
||
var token2 = pauseManager.Push("Second"); // 深度: 2, 仍然暂停
|
||
|
||
pauseManager.Pop(token1); // 深度: 1, 仍然暂停
|
||
pauseManager.Pop(token2); // 深度: 0, 恢复
|
||
```
|
||
|
||
### 问题:如何实现自定义暂停行为?
|
||
|
||
**解答**:
|
||
实现 `IPauseHandler` 接口并注册:
|
||
|
||
```csharp
|
||
public class CustomPauseHandler : IPauseHandler
|
||
{
|
||
public int Priority => 0;
|
||
|
||
public void OnPauseStateChanged(PauseGroup group, bool isPaused)
|
||
{
|
||
// 自定义暂停逻辑
|
||
}
|
||
}
|
||
|
||
pauseManager.RegisterHandler(new CustomPauseHandler());
|
||
```
|
||
|
||
### 问题:暂停处理器的优先级如何工作?
|
||
|
||
**解答**:
|
||
数值越小优先级越高,按优先级顺序调用:
|
||
|
||
```csharp
|
||
handler1.Priority = 0; // 最先调用
|
||
handler2.Priority = 10; // 其次调用
|
||
handler3.Priority = 20; // 最后调用
|
||
```
|
||
|
||
### 问题:如何清空所有暂停?
|
||
|
||
**解答**:
|
||
使用 `ClearAll()` 或 `ClearGroup()`:
|
||
|
||
```csharp
|
||
// 清空所有组的暂停
|
||
pauseManager.ClearAll();
|
||
|
||
// 只清空特定组
|
||
pauseManager.ClearGroup(PauseGroup.Gameplay);
|
||
```
|
||
|
||
### 问题:暂停系统是线程安全的吗?
|
||
|
||
**解答**:
|
||
是的,`PauseStackManager` 使用 `ReaderWriterLockSlim` 确保线程安全:
|
||
|
||
```csharp
|
||
// 可以在多个线程中安全调用
|
||
Task.Run(() => pauseManager.Push("Thread 1"));
|
||
Task.Run(() => pauseManager.Push("Thread 2"));
|
||
```
|
||
|
||
### 问题:如何调试暂停问题?
|
||
|
||
**解答**:
|
||
使用暂停状态查询方法:
|
||
|
||
```csharp
|
||
// 检查是否暂停
|
||
bool isPaused = pauseManager.IsPaused(PauseGroup.Global);
|
||
|
||
// 获取暂停深度
|
||
int depth = pauseManager.GetPauseDepth(PauseGroup.Global);
|
||
|
||
// 获取所有暂停原因
|
||
var reasons = pauseManager.GetPauseReasons(PauseGroup.Global);
|
||
foreach (var reason in reasons)
|
||
{
|
||
GD.Print($"暂停原因: {reason}");
|
||
}
|
||
```
|
||
|
||
## 相关文档
|
||
|
||
- [Godot 架构集成](/zh-CN/godot/architecture) - Godot 架构基础
|
||
- [Godot 场景系统](/zh-CN/godot/scene) - Godot 场景集成
|
||
- [Godot UI 系统](/zh-CN/godot/ui) - Godot UI 集成
|
||
- [Godot 扩展](/zh-CN/godot/extensions) - Godot 扩展方法
|