# Godot 扩展方法 (Godot Extensions)

## 概述

Godot 扩展方法模块为 Godot 引擎提供了丰富的便捷扩展方法集合。这些扩展方法简化了常见的 Godot
开发任务，提高了代码的可读性和开发效率。该模块遵循流畅接口设计原则，支持链式调用。

## 模块结构

```mermaid
graph TD
    A[Extensions] --> B[GodotPathExtensions]
    A --> C[NodeExtensions]
    A --> D[SignalFluentExtensions]
    A --> E[UnRegisterExtension]
    D --> F[SignalBuilder]
    
    B --> G[路径判断扩展]
    C --> H[节点生命周期]
    C --> I[节点查询]
    C --> J[场景树操作]
    C --> K[输入控制]
    C --> L[调试工具]
    D --> M[信号连接系统]
    E --> N[事件管理]
```

## 扩展模块详解

### 1. 路径扩展 (GodotPathExtensions)

提供 Godot 虚拟路径的判断和识别功能。

**主要方法：**

- `IsUserPath()` - 判断是否为 `user://` 路径
- `IsResPath()` - 判断是否为 `res://` 路径
- `IsGodotPath()` - 判断是否为 Godot 虚拟路径

**使用示例：**

```csharp
string savePath = "user://save.dat";
string configPath = "res://config.json";
string logPath = "C:/logs/debug.log";

if (savePath.IsUserPath()) Console.WriteLine("用户数据路径");
if (configPath.IsResPath()) Console.WriteLine("资源路径");
if (logPath.IsGodotPath()) Console.WriteLine("Godot 虚拟路径");
else Console.WriteLine("文件系统路径");
```

### 2. 节点扩展 (NodeExtensions)

最丰富的扩展模块，提供全面的节点操作功能。

#### 节点生命周期管理

```csharp
// 安全释放节点
node.QueueFreeX();  // 延迟释放
node.FreeX();       // 立即释放

// 等待节点就绪
await node.WaitUntilReady();

// 检查节点有效性
if (node.IsValidNode()) Console.WriteLine("节点有效");
if (node.IsInvalidNode()) Console.WriteLine("节点无效");
```

#### 节点查询操作

```csharp
// 查找子节点
var sprite = node.FindChildX<Sprite2D>("Sprite");
var parent = node.GetParentX<Control>();

// 获取或创建节点
var panel = parent.GetOrCreateNode<Panel>("MainPanel");

// 遍历子节点
node.ForEachChild<Sprite2D>(sprite => {
    sprite.Modulate = Colors.White;
});
```

#### 场景树操作

```csharp
// 获取根节点
var root = node.GetRootNodeX();

// 异步添加子节点
await parent.AddChildX(childNode);

// 设置场景树暂停状态
node.Paused(true);   // 暂停
node.Paused(false);  // 恢复
```

#### 输入控制

```csharp
// 标记输入事件已处理
node.SetInputAsHandled();

// 禁用/启用输入
node.DisableInput();
node.EnableInput();
```

#### 调试工具

```csharp
// 打印节点路径
node.LogNodePath();

// 打印节点树
node.PrintTreeX();

// 安全延迟调用
node.SafeCallDeferred("UpdateUI");
```

#### 类型转换

```csharp
// 安全的类型转换
var button = node.OfType<Button>();
var sprite = childNode.OfType<Sprite2D>();
```

### 3. 信号扩展 (SignalFluentExtensions)

提供流畅的信号连接 API，详见 [signal/README.md](signal/README.md)。

**快速示例：**

```csharp
button.Signal(Button.SignalName.Pressed)
    .WithFlags(GodotObject.ConnectFlags.OneShot)
    .ToAndCall(new Callable(this, nameof(OnButtonPressed)));
```

### 4. 取消注册扩展 (UnRegisterExtension)

自动管理事件监听器的生命周期。

**主要方法：**

- `UnRegisterWhenNodeExitTree()` - 节点退出场景树时自动取消注册

**使用示例：**

```csharp
var unRegister = eventManager.Subscribe<GameEvent>(OnGameEvent);
unRegister.UnRegisterWhenNodeExitTree(node);
```

## 快速参考

### 常用代码片段

#### 场景节点管理

```csharp
public class GameManager : Node
{
    private Node _uiRoot;
    
    public override void _Ready()
    {
        _uiRoot = GetNode<Node>("UI");
        
        // 创建游戏面板
        var gamePanel = _uiRoot.GetOrCreateNode<Panel>("GamePanel");
        
        // 安全添加子节点
        var player = new Player();
        await AddChildX(player);
        
        // 查找并配置玩家
        var sprite = player.FindChildX<Sprite2D>("Sprite");
        if (sprite.IsValidNode()) sprite.Modulate = Colors.Red;
    }
    
    public void Cleanup()
    {
        // 安全释放所有子节点
        ForEachChild<Node>(child => child.QueueFreeX());
    }
}
```

#### UI 事件处理

```csharp
public class MainMenu : Control
{
    private Button _startButton;
    private Button _quitButton;
    
    public override void _Ready()
    {
        _startButton = FindChildX<Button>("StartButton");
        _quitButton = FindChildX<Button>("QuitButton");
        
        // 流畅的信号连接
        _startButton.Signal(BaseButton.SignalName.Pressed)
            .ToAndCall(new Callable(this, nameof(OnStartPressed)));
            
        _quitButton.Signal(BaseButton.SignalName.Pressed)
            .To(new Callable(this, nameof(OnQuitPressed)));
    }
    
    private void OnStartPressed()
    {
        GetTree().ChangeSceneToFile("res://scenes/game.tscn");
    }
    
    private void OnQuitPressed()
    {
        GetTree().Quit();
    }
}
```

#### 异步场景管理

```csharp
public class SceneManager : Node
{
    public async Task<T> LoadSceneAsync<T>(string scenePath) where T : Node
    {
        var packedScene = GD.Load<PackedScene>(scenePath);
        var instance = packedScene.Instantiate<T>();
        
        // 等待场景加载完成
        await instance.WaitUntilReady();
        
        return instance;
    }
    
    public async Task TransitionToScene(string scenePath)
    {
        var newScene = await LoadSceneAsync<Node>(scenePath);
        
        // 清理当前场景
        ForEachChild<Node>(child => child.QueueFreeX());
        
        // 加载新场景
        await AddChildX(newScene);
        
        // 设置输入处理
        newScene.SetInputAsHandled();
    }
}
```

## 设计原则

### 1. 安全性

- 所有节点操作都包含有效性检查
- 提供安全的类型转换方法
- 避免空引用异常

### 2. 便利性

- 流畅的 API 设计
- 支持链式调用
- 减少样板代码

### 3. 一致性

- 统一的命名约定
- 一致的返回类型
- 预测性方法行为

### 4. 性能

- 避免不必要的节点查找
- 最小化内存分配
- 优化常见操作

## 最佳实践

### 1. 节点生命周期

```csharp
// ✅ 推荐：使用安全释放
node.QueueFreeX();

// ❌ 避免：直接释放可能导致错误
node.QueueFree();
```

### 2. 节点查询

```csharp
// ✅ 推荐：类型安全的查找
var button = node.FindChildX<Button>("Button");

// ❌ 避免：需要手动类型转换
var button = node.FindChild("Button") as Button;
```

### 3. 异步操作

```csharp
// ✅ 推荐：等待节点就绪
await child.WaitUntilReady();

// ❌ 避免：假设节点已就绪
child.DoSomething();
```

### 4. 事件管理

```csharp
// ✅ 推荐：自动清理事件
var unRegister = eventSystem.Subscribe(eventHandler);
unRegister.UnRegisterWhenNodeExitTree(node);

// ❌ 避免：手动管理事件生命周期
// 可能导致内存泄漏
```

## 相关链接

- [信号连接系统](signal/README.md) - 详细的信号连接 API 文档
- [存储模块](../storage/README.md) - 文件存储系统
- [设置模块](../setting/README.md) - 游戏设置系统
- [设置系统](../../GFramework.Game/setting/README.md) - 通用设置框架