GeWuYou a8803f31be docs(GFramework.Game): 添加游戏功能模块完整文档
创建了 GFramework.Game 模块的详细 README 文档,涵盖以下核心内容:

- 模块概述和核心设计理念介绍
- 架构模块系统说明,包含 AbstractModule 使用示例
- 资产管理系统详解,包括资产目录和映射功能
- 存储系统实现,支持分层存储和缓存机制
- 序列化系统集成,基于 Newtonsoft.Json 的完整方案
- 丰富的代码示例,展示实际使用场景
- 最佳实践指南,涵盖数据模型设计和性能优化建议
- 性能特性说明和技术栈依赖关系
2026-01-12 13:40:36 +08:00

21 KiB
Raw Blame History

GFramework.Godot API 参考

GFramework.Godot 模块的完整 API 参考文档,包含 Godot 特定扩展和集成的详细说明。

📋 目录

架构集成

AbstractArchitecture

Godot 特定的架构基类,继承自 Core.Architecture。

新增方法

// Godot 模块安装
protected void InstallGodotModule(IGodotModule module);

protected void InstallGodotModule<T>() where T : IGodotModule, new();

使用示例

public class GameArchitecture : AbstractArchitecture
{
    protected override void Init()
    {
        RegisterModel(new PlayerModel());
        RegisterSystem(new CombatSystem());
        RegisterUtility(new StorageUtility());
    }
    
    protected override void InstallModules()
    {
        InstallGodotModule(new AudioModule());
        InstallGodotModule(new InputModule());
    }
}

IGodotModule

Godot 模块接口,继承自 IArchitectureModule。

属性

Node Node { get; }

方法

void Install(IArchitecture architecture);
void OnAttach(Architecture architecture);
void OnDetach(Architecture architecture);
void OnPhase(ArchitecturePhase phase, IArchitecture architecture);

使用示例

public class AudioModule : AbstractGodotModule
{
    // 模块节点本身
    public override Node Node => this;
    
    private AudioStreamPlayer _musicPlayer;
    
    public override void Install(IArchitecture architecture)
    {
        // 注册音频系统
        architecture.RegisterSystem(new AudioSystem());
        architecture.RegisterUtility(new AudioUtility());
    }
    
    public override void OnAttach(Architecture architecture)
    {
        // 创建音频播放器
        _musicPlayer = new AudioStreamPlayer();
        AddChild(_musicPlayer);
        
        Logger.Info("Audio module attached");
    }
    
    public override void OnDetach(Architecture architecture)
    {
        // 清理音频播放器
        _musicPlayer?.QueueFree();
        
        Logger.Info("Audio module detached");
    }
    
    public override void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
    {
        switch (phase)
        {
            case ArchitecturePhase.Ready:
                PlayBackgroundMusic();
                break;
        }
    }
    
    private void PlayBackgroundMusic()
    {
        var music = GD.Load<AudioStream>("res://audio/background.ogg");
        _musicPlayer.Stream = music;
        _musicPlayer.Play();
    }
}

AbstractGodotModule

Godot 模块抽象基类,实现了 IGodotModule 接口。

使用示例

[ContextAware]
[Log]
public partial class SaveModule : AbstractGodotModule
{
    private Timer _autoSaveTimer;
    
    public override void Install(IArchitecture architecture)
    {
        architecture.RegisterSystem(new SaveSystem());
        architecture.RegisterUtility(new SaveUtility());
    }
    
    public override void OnAttach(Architecture architecture)
    {
        // 创建自动保存计时器
        _autoSaveTimer = new Timer();
        _autoSaveTimer.WaitTime = 300; // 5分钟
        _autoSaveTimer.Timeout += OnAutoSave;
        AddChild(_autoSaveTimer);
        _autoSaveTimer.Start();
        
        Logger.Info("Save module attached with auto-save enabled");
    }
    
    private void OnAutoSave()
    {
        var saveSystem = Context.GetSystem<SaveSystem>();
        saveSystem.SaveGame("autosave");
        Logger.Debug("Auto-save completed");
    }
}

Node 扩展方法

安全节点获取

GetNodeX()

安全获取子节点,自动类型转换和 null 检查。

public static T GetNodeX<T>(this Node node, string path) where T : class;

使用示例

// 安全获取节点
var player = GetNodeX<Player>("Player");
var healthBar = GetNodeX<ProgressBar>("UI/HealthBar");

// 如果节点不存在或类型不匹配,会抛出异常
// 使用时不需要额外的 null 检查

GetChildX()

安全查找子节点,支持递归查找。

public static T GetChildX<T>(this Node node, string path) where T : class;

使用示例

// 递归查找子节点
var player = FindChildX<Player>("Player");
var sprite = FindChildX<Sprite2D>("Enemy/Sprite");

节点验证

IsValidNode()

检查节点是否有效且在场景树中。

public static bool IsValidNode(this Node node);

IsInvalidNode()

检查节点是否无效或不在场景树中。

public static bool IsInvalidNode(this Node node);

使用示例

Node someNode = GetNode("SomeNode");

if (IsValidNode(someNode))
{
    someNode.DoSomething();
}

if (IsInvalidNode(someNode))
{
    // 节点无效,需要重新获取
}

安全节点操作

AddChildX()

安全添加子节点,包含验证。

public static void AddChildX(this Node parent, Node child, bool forceReadableName = false, InternalMode internalMode = 0);

QueueFreeX()

安全销毁节点,包含验证。

public static void QueueFreeX(this Node node);

FreeX()

立即销毁节点,谨慎使用。

public static void FreeX(this Node node);

使用示例

// 创建并添加子节点
var bullet = bulletScene.Instantiate<Bullet>();
AddChildX(bullet);

// 安全销毁节点
bullet.QueueFreeX();

// 立即销毁(谨慎使用)
tempNode.FreeX();

异步节点操作

WaitUntilReady()

等待节点准备就绪。

public static async Task WaitUntilReady(this Node node);

WaitUntil()

等待条件满足。

public static async Task WaitUntil(this Node node, Func<bool> condition);

WaitUntilTimeout()

等待指定时间或条件满足。

public static async Task WaitUntilTimeout(this Node node, float timeoutSeconds);

使用示例

// 等待节点准备就绪
await this.WaitUntilReady();

// 等待条件满足
await this.WaitUntil(() => SomeCondition());

// 等待 2 秒
await this.WaitUntilTimeout(2.0f);

场景树操作

GetParentX()

安全获取父节点。

public static T GetParentX<T>(this Node node) where T : class;

ForEachChild()

遍历所有子节点。

public static void ForEachChild<T>(this Node node, Action<T> action) where T : Node;

使用示例

// 获取父节点
var parent = GetParentX<GameLevel>();

// 遍历所有子节点
this.ForEachChild<Node>(child => {
    if (child is Sprite2D sprite)
    {
        ProcessSprite(sprite);
    }
});

信号系统

SignalBuilder

信号构建器,提供流畅的信号连接 API。

构造函数

public SignalBuilder(Node node);

连接方法

public SignalBuilder Connect(Callable callable);
public SignalBuilder Connect<T1>(Callable<T1> callable);
public SignalBuilder Connect<T1, T2>(Callable<T1, T2> callable);
public SignalBuilder Connect<T1, T2, T3>(Callable<T1, T2, T3> callable);
public SignalBuilder Connect<T1, T2, T3, T4>(Callable<T1, T2, T3, T4> callable);

配置方法

public SignalBuilder WithFlags(ConnectFlags flags);
public SignalBuilder CallImmediately();

生命周期方法

public SignalBuilder UnRegisterWhenNodeExitTree(Node node);
public SignalBuilder AddToUnregisterList(IUnRegisterList unregisterList);

使用示例

// 基础连接
this.CreateSignalBuilder(Button.SignalName.Pressed)
    .Connect(OnButtonPressed)
    .UnRegisterWhenNodeExitTree(this);

// 带标志的连接
this.CreateSignalBuilder(Timer.SignalName.Timeout)
    .WithFlags(ConnectFlags.OneShot)
    .Connect(OnTimerTimeout);

// 立即调用连接
this.CreateSignalBuilder(CustomSignal.SignalName.CustomEvent)
    .CallImmediately()
    .Connect(OnCustomEvent);

// 多参数连接
this.CreateSignalBuilder()
    .AddSignal(SignalName.Parameter1, OnParameter1)
    .AddSignal(SignalName.Parameter2, OnParameter2)
    .AddSignal(SignalName.Parameter3, OnParameter3)
    .UnRegisterWhenNodeExitTree(this);

SignalExtension

信号扩展方法,简化信号创建。

CreateSignalBuilder()

创建信号构建器。

public static SignalBuilder CreateSignalBuilder(this Node node, string signalName);

ConnectSignal()

直接连接信号。

public static IUnRegister ConnectSignal(this Node node, string signalName, Callable callable);
public static IUnRegister ConnectSignal<T1>(this Node node, string signalName, Callable<T1> callable);

使用示例

// 创建信号构建器连接
this.CreateSignalBuilder(Button.SignalName.Pressed)
    .Connect(OnButtonPressed);

// 直接连接信号
this.ConnectSignal(Button.SignalName.Pressed, Callable.From(OnButtonPressed));

// 多参数信号连接
this.ConnectSignal(ComplexSignal.SignalName.DataChanged, 
    Callable.From(OnDataChanged));

信号与框架事件桥接

SignalEventBridge

信号事件桥接器,将 Godot 信号转换为框架事件。

使用示例

[ContextAware]
[Log]
public partial class GameController : Node, IController
{
    public override void _Ready()
    {
        // Godot 信号 -> 框架事件
        this.CreateSignalBuilder(Button.SignalName.Pressed)
            .Connect(() => {
                Context.SendEvent(new ButtonClickEvent { ButtonId = "start" });
            })
            .UnRegisterWhenNodeExitTree(this);
            
        // 框架事件 -> Godot 信号
        this.RegisterEvent<PlayerHealthChangeEvent>(OnPlayerHealthChange)
            .UnRegisterWhenNodeExitTree(this);
    }
    
    private void OnPlayerHealthChange(PlayerHealthChangeEvent e)
    {
        // 更新 Godot UI
        var healthBar = GetNode<ProgressBar>("UI/HealthBar");
        healthBar.Value = (float)e.NewHealth / e.MaxHealth * 100;
        
        // 发送 Godot 信号
        EmitSignal(SignalName.HealthUpdated, e.NewHealth, e.MaxHealth);
    }
    
    [Signal]
    public delegate void HealthUpdatedEventHandler(int newHealth, int maxHealth);
}

节点池化

AbstractNodePoolSystem<TKey, TNode>

节点池化系统基类TNode 必须是 Node。

抽象方法

protected abstract TNode CreateItem(TKey key);
protected abstract void OnSpawn(TNode item, TKey key);
protected abstract void OnDespawn(TNode item);
protected abstract bool CanDespawn(TNode item);

公共方法

public TNode Spawn(TKey key);
public void Despawn(TNode item);
public void DespawnAll();
public int GetActiveCount(TKey key);
public int GetTotalCount(TKey key);

使用示例

public class BulletPoolSystem : AbstractNodePoolSystem<string, Bullet>
{
    private readonly Dictionary<string, PackedScene> _scenes = new();
    
    public BulletPoolSystem()
    {
        _scenes["player"] = GD.Load<PackedScene>("res://scenes/PlayerBullet.tscn");
        _scenes["enemy"] = GD.Load<PackedScene>("res://scenes/EnemyBullet.tscn");
    }
    
    protected override Bullet CreateItem(string key)
    {
        if (_scenes.TryGetValue(key, out var scene))
        {
            return scene.Instantiate<Bullet>();
        }
        throw new ArgumentException($"Unknown bullet type: {key}");
    }
    
    protected override void OnSpawn(Bullet item, string key)
    {
        item.Reset();
        item.Position = Vector2.Zero;
        item.Visible = true;
        item.SetCollisionLayerValue(1, true);
        item.SetCollisionMaskValue(1, true);
    }
    
    protected override void OnDespawn(Bullet item)
    {
        item.Visible = false;
        item.SetCollisionLayerValue(1, false);
        item.SetCollisionMaskValue(1, false);
        
        // 移除父节点
        item.GetParent()?.RemoveChild(item);
    }
    
    protected override bool CanDespawn(Bullet item)
    {
        return !item.IsActive && item.GetParent() != null;
    }
}

// 使用示例
var bulletPool = new BulletPoolSystem();

// 从池中获取子弹
var bullet = bulletPool.Spawn("player");
AddChild(bullet);

// 回收子弹
bulletPool.Despawn(bullet);

IPoolableNode

可池化节点接口。

public interface IPoolableNode
{
    void Reset();
    void SetActive(bool active);
    bool IsActive { get; }
}

使用示例

public partial class Bullet : Area2D, IPoolableNode
{
    [Export] public float Speed { get; set; } = 500.0f;
    [Export] public float Damage { get; set; } = 10.0f;
    
    private bool _isActive;
    
    public bool IsActive => _isActive;
    
    public void Reset()
    {
        Position = Vector2.Zero;
        Rotation = 0;
        Velocity = Vector2.Zero;
        _isActive = false;
    }
    
    public void SetActive(bool active)
    {
        _isActive = active;
        Visible = active;
        SetProcess(active);
    }
    
    public override void _Ready()
    {
        BodyEntered += OnBodyEntered;
    }
    
    private void OnBodyEntered(Node body)
    {
        if (body is Enemy enemy && _isActive)
        {
            enemy.TakeDamage(Damage);
            // 子弹命中敌人,回收到池中
            var bulletPool = GetNode<BulletPoolSystem>("/root/BulletPool");
            bulletPool?.Despawn(this);
        }
    }
    
    public override void _Process(double delta)
    {
        if (!_isActive) return;
        
        Position += Transform.X * (float)(Speed * delta);
    }
}

资源管理

ResourceLoadUtility

资源加载工具类,简化和缓存 Godot 资源加载。

构造函数

public ResourceLoadUtility();

方法

public T LoadResource<T>(string path) where T : Resource;
public async Task<T> LoadResourceAsync<T>(string path) where T : Resource;
public void PreloadResource<T>(string path) where T : Resource;
public bool HasResource<T>(string path) where T : Resource;

使用示例

var resourceLoader = new ResourceLoadUtility();

// 同步加载资源
var playerTexture = resourceLoader.LoadResource<Texture2D>("res://textures/player.png");
var playerScene = resourceLoader.LoadResource<PackedScene>("res://scenes/Player.tscn");

// 异步加载资源
var musicStream = await resourceLoader.LoadResourceAsync<AudioStream>("res://audio/background.ogg");

// 预加载资源
resourceLoader.PreloadResource<Texture2D>("res://textures/enemy.png");
resourceLoader.PreloadResource<PackedScene>("res://scenes/enemy.tscn");

AbstractResourceFactoryUtility

抽象资源工厂工具基类。

抽象方法

protected abstract void RegisterFactories();
protected abstract T CreateFactory<T>(string path, Dictionary<string, object> metadata = null) where T : class;

使用示例

public class GameResourceFactory : AbstractResourceFactoryUtility
{
    protected override void RegisterFactories()
    {
        RegisterFactory<PlayerData>("res://data/players/{id}.json");
        RegisterFactory<WeaponConfig>("res://data/weapons/{id}.json");
        RegisterFactory<LevelConfig>("res://data/levels/{id}.json");
    }
    
    public PlayerData CreatePlayer(string playerId)
    {
        return CreateFactory<PlayerData>($"res://data/players/{playerId}.json");
    }
    
    public WeaponConfig CreateWeapon(string weaponId)
    {
        var metadata = new Dictionary<string, object>
        {
            ["weaponId"] = weaponId,
            ["loadTime"] = DateTime.Now
        };
        
        return CreateFactory<WeaponConfig>($"res://data/weapons/{weaponId}.json", metadata);
    }
}

日志系统

GodotLogger

Godot 特定的日志实现。

构造函数

public GodotLogger(string categoryName);
public GodotLogger(string categoryName, LogLevel minLevel);

方法

public void Log<T>(LogLevel level, T message, params object[] args);
public void Debug<T>(T message, params object[] args);
public void Info<T>(T message, params object[] args);
public void Warning<T>(T message, params object[] args);
public void Error<T>(T message, params object[] args);
public void Error<T>(Exception exception, T message, params object[] args);

使用示例

// 创建日志器
var logger = new GodotLogger("GameController");

// 不同级别的日志
logger.Debug("Player position: {0}", player.Position);
logger.Info("Game started");
logger.Warning("Low health: {0}", player.Health);
logger.Error("Failed to load resource: {0}", resourcePath);

// 带异常的错误日志
logger.Error(exception, "An error occurred while processing player input");

GodotLoggerFactory

Godot 日志工厂。

方法

public ILogger CreateLogger(string categoryName);
public ILogger CreateLogger(Type type);

使用示例

var factory = new GodotLoggerFactory();

// 创建日志器
var gameLogger = factory.CreateLogger("GameController");
var playerLogger = factory.CreateLogger(typeof(PlayerController));

// 在架构中使用
public class GameArchitecture : AbstractArchitecture
{
    protected override void Init()
    {
        LoggerProperties = new LoggerProperties
        {
            LoggerFactoryProvider = new GodotLoggerFactoryProvider(),
            MinLevel = LogLevel.Info
        };
        
        RegisterSystem(new GameController());
    }
}

池化管理

AbstractObjectPool

通用对象池基类。

构造函数

public AbstractObjectPool(
    Func<T> createFunc,
    Action<T> actionOnGet = null,
    Action<T> actionOnRelease = null,
    bool collectionCheck = false
);

方法

public T Get();
public void Release(T item);
public void Clear();
public int CountInactive { get; }
public int CountAll { get; }

使用示例

// 创建对象池
var explosionPool = new AbstractObjectPool<ExplosionEffect>(
    createFunc: () => new ExplosionEffect(),
    actionOnGet: effect => effect.Reset(),
    actionOnRelease: effect => Cleanup()
);

// 使用对象池
var effect = explosionPool.Get();
effect.Play(effect.Position);

// 回收对象
explosionPool.Release(effect);

音频系统

AudioSystem

音频系统,管理音乐和音效播放。

使用示例

[ContextAware]
[Log]
public partial class AudioSystem : AbstractSystem
{
    private AudioStreamPlayer _musicPlayer;
    private readonly Dictionary<string, AudioStream> _soundCache = new();
    
    protected override void OnInit()
    {
        InitializeAudioPlayers();
        CacheSounds();
        
        // 监听音频事件
        this.RegisterEvent<PlaySoundEvent>(OnPlaySound);
        this.RegisterEvent<PlayMusicEvent>(OnPlayMusic);
        this.RegisterEvent<StopMusicEvent>(OnStopMusic);
        this.RegisterEvent<SetVolumeEvent>(OnSetVolume);
    }
    
    private void InitializeAudioPlayers()
    {
        _musicPlayer = new AudioStreamPlayer();
        AddChild(_musicPlayer);
        
        // 配置音乐播放器
        _musicPlayer.Bus = "Music";
    }
    
    private void CacheSounds()
    {
        var soundPaths = new[]
        {
            "res://audio/jump.wav",
            "res://audio/attack.wav",
            "res://audio/hurt.wav",
            "res://audio/victory.wav"
        };
        
        foreach (var path in soundPaths)
        {
            var sound = GD.Load<AudioStream>(path);
            var soundName = Path.GetFileNameWithoutExtension(path);
            _soundCache[soundName] = sound;
        }
    }
    
    private void OnPlaySound(PlaySoundEvent e)
    {
        if (_soundCache.TryGetValue(e.SoundName, out var sound))
        {
            PlaySound(sound);
        }
        else
        {
            Logger.Warning($"Sound not found: {e.SoundName}");
        }
    }
    
    private void PlayMusic(PlayMusicEvent e)
    {
        var music = GD.Load<AudioStream>(e.MusicPath);
        _musicPlayer.Stream = music;
        _musicPlayer.Play();
        
        Logger.Info($"Playing music: {e.MusicPath}");
    }
    
    private void OnStopMusic(StopMusicEvent e)
    {
        _musicPlayer.Stop();
        Logger.Info("Music stopped");
    }
    
    private void OnSetVolume(SetVolumeEvent e)
    {
        AudioServer.SetBusVolume(e.BusName, e.Volume);
        Logger.Info($"Set volume for bus {e.BusName}: {e.Volume}");
    }
    
    private void PlaySound(AudioStream sound)
    {
        var player = new AudioStreamPlayer();
        player.Stream = sound;
        player.Bus = "SFX";
        player.Play();
        
        // 自动清理播放器
        this.CreateSignalBuilder(player.SignalName.Finished)
            .WithFlags(ConnectFlags.OneShot)
            .Connect(() => player.QueueFree())
            .UnRegisterWhenNodeExitTree(this);
    }
}

// 音频事件
public struct PlaySoundEvent { public string SoundName; }
public struct PlayMusicEvent { public string MusicPath; }
public struct StopMusicEvent { }
public struct SetVolumeEvent { public string BusName; public float Volume; }

文档版本: 1.0.0
更新日期: 2026-01-12