mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
docs(sidebar): 更新侧边栏导航结构并移除API参考页面
- 调整Core模块导航链接结构,从overview页面改为根路径 - 重构Core模块侧边栏,将原有的6个主要类别扩展为15个详细分类 - 精简Game模块侧边栏,保留场景管理和游戏设置两个主要功能 - 更新Godot集成模块侧边栏,新增协程、信号、存储等功能分类 - 修改源码生成器模块命名,将枚举扩展重命名为枚举生成器 - 新增抽象接口侧边栏,包含Core和Game抽象接口文档 - 调整教程模块顺序,新增入门教程和Godot集成教程分类 - 移除独立的API参考导航项,将其整合到相应模块中 - 修正生成器API文档链接路径错误问题
This commit is contained in:
parent
bc89ff07a1
commit
317eddca9b
@ -41,12 +41,11 @@ export default defineConfig({
|
||||
nav: [
|
||||
{ text: '首页', link: '/zh-CN/' },
|
||||
{ text: '入门指南', link: '/zh-CN/getting-started/installation' },
|
||||
{ text: 'Core', link: '/zh-CN/core/overview' },
|
||||
{ text: 'Core', link: '/zh-CN/core/' },
|
||||
{ text: 'Game', link: '/zh-CN/game/overview' },
|
||||
{ text: 'Godot', link: '/zh-CN/godot/overview' },
|
||||
{ text: '源码生成器', link: '/zh-CN/source-generators/overview' },
|
||||
{ text: '教程', link: '/zh-CN/tutorials/basic-tutorial' },
|
||||
{ text: 'API参考', link: '/zh-CN/api-reference/core-api' }
|
||||
],
|
||||
|
||||
sidebar: {
|
||||
@ -65,12 +64,22 @@ export default defineConfig({
|
||||
{
|
||||
text: 'Core 核心框架',
|
||||
items: [
|
||||
{ text: '概览', link: '/zh-CN/core/overview' },
|
||||
{ text: '架构组件', link: '/zh-CN/core/architecture/architecture' },
|
||||
{ text: '命令查询系统', link: '/zh-CN/core/command-query/commands' },
|
||||
{ text: '事件系统', link: '/zh-CN/core/events/event-bus' },
|
||||
{ text: '属性系统', link: '/zh-CN/core/property/bindable-property' },
|
||||
{ text: '工具类', link: '/zh-CN/core/utilities/ioc-container' }
|
||||
{ text: '概览', link: '/zh-CN/core/' },
|
||||
{ text: '架构组件', link: '/zh-CN/core/architecture' },
|
||||
{ text: '命令系统', link: '/zh-CN/core/command' },
|
||||
{ text: '查询系统', link: '/zh-CN/core/query' },
|
||||
{ text: '事件系统', link: '/zh-CN/core/events' },
|
||||
{ text: '属性系统', link: '/zh-CN/core/property' },
|
||||
{ text: 'IoC容器', link: '/zh-CN/core/ioc' },
|
||||
{ text: '对象池', link: '/zh-CN/core/pool' },
|
||||
{ text: '日志系统', link: '/zh-CN/core/logging' },
|
||||
{ text: '扩展方法', link: '/zh-CN/core/extensions' },
|
||||
{ text: '工具类', link: '/zh-CN/core/utility' },
|
||||
{ text: '模型层', link: '/zh-CN/core/model' },
|
||||
{ text: '系统层', link: '/zh-CN/core/system' },
|
||||
{ text: '控制器', link: '/zh-CN/core/controller' },
|
||||
{ text: '规则系统', link: '/zh-CN/core/rule' },
|
||||
{ text: '环境接口', link: '/zh-CN/core/environment' }
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -80,10 +89,8 @@ export default defineConfig({
|
||||
text: 'Game 游戏模块',
|
||||
items: [
|
||||
{ text: '概览', link: '/zh-CN/game/overview' },
|
||||
{ text: '模块系统', link: '/zh-CN/game/modules/architecture-modules' },
|
||||
{ text: '存储系统', link: '/zh-CN/game/storage/scoped-storage' },
|
||||
{ text: '资源管理', link: '/zh-CN/game/assets/asset-catalog' },
|
||||
{ text: '序列化', link: '/zh-CN/game/serialization/json-serializer' }
|
||||
{ text: '场景管理', link: '/zh-CN/game/scene-management' },
|
||||
{ text: '游戏设置', link: '/zh-CN/game/setting' }
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -93,10 +100,11 @@ export default defineConfig({
|
||||
text: 'Godot 集成',
|
||||
items: [
|
||||
{ text: '概览', link: '/zh-CN/godot/overview' },
|
||||
{ text: '集成指南', link: '/zh-CN/godot/integration/architecture-integration' },
|
||||
{ text: '节点扩展', link: '/zh-CN/godot/node-extensions/node-extensions' },
|
||||
{ text: '对象池', link: '/zh-CN/godot/pooling/node-pool' },
|
||||
{ text: '日志系统', link: '/zh-CN/godot/logging/godot-logger' }
|
||||
{ text: '协程系统', link: '/zh-CN/godot/coroutine' },
|
||||
{ text: '节点扩展', link: '/zh-CN/godot/extensions' },
|
||||
{ text: '信号系统', link: '/zh-CN/godot/signal' },
|
||||
{ text: '存储系统', link: '/zh-CN/godot/storage' },
|
||||
{ text: '设置系统', link: '/zh-CN/godot/setting' }
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -105,21 +113,32 @@ export default defineConfig({
|
||||
{
|
||||
text: '源码生成器',
|
||||
items: [
|
||||
{ text: '概览', link: '/zh-CN/source-generators/overview' },
|
||||
{ text: '概览', link: '/zh-CN/source-generators/' },
|
||||
{ text: '日志生成器', link: '/zh-CN/source-generators/logging-generator' },
|
||||
{ text: '枚举扩展', link: '/zh-CN/source-generators/enum-extensions' },
|
||||
{ text: '枚举扩展', link: '/zh-CN/source-generators/enum-generator' },
|
||||
{ text: '规则生成器', link: '/zh-CN/source-generators/rule-generator' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/zh-CN/abstractions/': [
|
||||
{
|
||||
text: '抽象接口',
|
||||
items: [
|
||||
{ text: 'Core Abstractions', link: '/zh-CN/abstractions/core-abstractions' },
|
||||
{ text: 'Game Abstractions', link: '/zh-CN/abstractions/game-abstractions' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/zh-CN/tutorials/': [
|
||||
{
|
||||
text: '教程',
|
||||
items: [
|
||||
{ text: '入门教程', link: '/zh-CN/tutorials/getting-started' },
|
||||
{ text: '基础教程', link: '/zh-CN/tutorials/basic-tutorial' },
|
||||
{ text: '高级模式', link: '/zh-CN/tutorials/advanced-patterns' },
|
||||
{ text: '最佳实践', link: '/zh-CN/tutorials/best-practices' }
|
||||
{ text: 'Godot集成', link: '/zh-CN/tutorials/godot-integration' },
|
||||
{ text: '高级模式', link: '/zh-CN/tutorials/advanced-patterns' }
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -131,7 +150,7 @@ export default defineConfig({
|
||||
{ text: 'Core API', link: '/zh-CN/api-reference/core-api' },
|
||||
{ text: 'Game API', link: '/zh-CN/api-reference/game-api' },
|
||||
{ text: 'Godot API', link: '/zh-CN/api-reference/godot-api' },
|
||||
{ text: '生成器 API', link: '/zh-CN/api-reference/generators-api' }
|
||||
{ text: '生成器 API', link: '/zh-CN/api-reference/source-generators-api' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
192
docs/zh-CN/abstractions/core-abstractions.md
Normal file
192
docs/zh-CN/abstractions/core-abstractions.md
Normal file
@ -0,0 +1,192 @@
|
||||
# Core Abstractions
|
||||
|
||||
> GFramework.Core.Abstractions 核心抽象接口定义
|
||||
|
||||
## 概述
|
||||
|
||||
GFramework.Core.Abstractions 包含了框架的所有核心接口定义,这些接口定义了组件之间的契约,实现了依赖倒置和面向接口编程。
|
||||
|
||||
## 核心接口
|
||||
|
||||
### IArchitecture
|
||||
|
||||
应用程序架构接口:
|
||||
|
||||
```csharp
|
||||
public interface IArchitecture
|
||||
{
|
||||
void Initialize();
|
||||
void Destroy();
|
||||
|
||||
T GetModel<T>() where T : IModel;
|
||||
T GetSystem<T>() where T : ISystem;
|
||||
T GetUtility<T>() where T : IUtility;
|
||||
|
||||
void RegisterModel(IModel model);
|
||||
void RegisterSystem(ISystem system);
|
||||
void RegisterUtility(IUtility utility);
|
||||
}
|
||||
```
|
||||
|
||||
### IModel
|
||||
|
||||
数据模型接口:
|
||||
|
||||
```csharp
|
||||
public interface IModel
|
||||
{
|
||||
void Init();
|
||||
void Dispose();
|
||||
|
||||
IArchitecture Architecture { get; }
|
||||
}
|
||||
```
|
||||
|
||||
### ISystem
|
||||
|
||||
业务逻辑系统接口:
|
||||
|
||||
```csharp
|
||||
public interface ISystem
|
||||
{
|
||||
void Init();
|
||||
void Dispose();
|
||||
|
||||
IArchitecture Architecture { get; }
|
||||
}
|
||||
```
|
||||
|
||||
### IController
|
||||
|
||||
控制器接口:
|
||||
|
||||
```csharp
|
||||
public interface IController : IBelongToArchitecture
|
||||
{
|
||||
void Init();
|
||||
void Dispose();
|
||||
}
|
||||
```
|
||||
|
||||
### IUtility
|
||||
|
||||
工具类接口:
|
||||
|
||||
```csharp
|
||||
public interface IUtility
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
## 事件接口
|
||||
|
||||
### IEvent
|
||||
|
||||
事件基接口:
|
||||
|
||||
```csharp
|
||||
public interface IEvent
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
### IEventHandler
|
||||
|
||||
事件处理器接口:
|
||||
|
||||
```csharp
|
||||
public interface IEventHandler<TEvent> where TEvent : IEvent
|
||||
{
|
||||
void Handle(TEvent event);
|
||||
}
|
||||
```
|
||||
|
||||
## 命令查询接口
|
||||
|
||||
### ICommand
|
||||
|
||||
命令接口:
|
||||
|
||||
```csharp
|
||||
public interface ICommand
|
||||
{
|
||||
void Execute();
|
||||
}
|
||||
```
|
||||
|
||||
### IQuery
|
||||
|
||||
查询接口:
|
||||
|
||||
```csharp
|
||||
public interface IQuery<TResult>
|
||||
{
|
||||
TResult Execute();
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖注入接口
|
||||
|
||||
### IIocContainer
|
||||
|
||||
IOC 容器接口:
|
||||
|
||||
```csharp
|
||||
public interface IIocContainer
|
||||
{
|
||||
void Register<TInterface, TImplementation>() where TImplementation : TInterface;
|
||||
void Register<TInterface>(TInterface instance);
|
||||
TInterface Resolve<TInterface>();
|
||||
bool IsRegistered<TInterface>();
|
||||
}
|
||||
```
|
||||
|
||||
## 生命周期接口
|
||||
|
||||
### ILifecycle
|
||||
|
||||
组件生命周期接口:
|
||||
|
||||
```csharp
|
||||
public interface ILifecycle
|
||||
{
|
||||
void OnInit();
|
||||
void OnDestroy();
|
||||
}
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 通过接口实现依赖注入
|
||||
|
||||
```csharp
|
||||
public class MyService : IMyService
|
||||
{
|
||||
private readonly IArchitecture _architecture;
|
||||
|
||||
public MyService(IArchitecture architecture)
|
||||
{
|
||||
_architecture = architecture;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 自定义事件
|
||||
|
||||
```csharp
|
||||
public class PlayerDiedEvent : IEvent
|
||||
{
|
||||
public int PlayerId { get; set; }
|
||||
public Vector2 Position { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**相关文档**:
|
||||
|
||||
- [Core 概述](../core)
|
||||
- [Architecture](../core/architecture)
|
||||
- [Events](../core/events)
|
||||
- [Command](../core/command)
|
||||
- [Query](../core/query)
|
||||
113
docs/zh-CN/abstractions/game-abstractions.md
Normal file
113
docs/zh-CN/abstractions/game-abstractions.md
Normal file
@ -0,0 +1,113 @@
|
||||
# Game Abstractions
|
||||
|
||||
> GFramework.Game.Abstractions 游戏模块抽象接口定义
|
||||
|
||||
## 概述
|
||||
|
||||
GFramework.Game.Abstractions 包含了游戏特定功能的抽象接口,这些接口定义了游戏开发中的通用契约。
|
||||
|
||||
## 存档接口
|
||||
|
||||
### ISaveSystem
|
||||
|
||||
存档系统接口:
|
||||
|
||||
```csharp
|
||||
public interface ISaveSystem
|
||||
{
|
||||
void Save(string slotId, SaveData data);
|
||||
SaveData Load(string slotId);
|
||||
bool HasSave(string slotId);
|
||||
void Delete(string slotId);
|
||||
List<SaveSlotInfo> GetAllSaveSlots();
|
||||
}
|
||||
```
|
||||
|
||||
### ISaveData
|
||||
|
||||
存档数据接口:
|
||||
|
||||
```csharp
|
||||
public interface ISaveData
|
||||
{
|
||||
int Version { get; }
|
||||
DateTime Timestamp { get; }
|
||||
void Validate();
|
||||
}
|
||||
```
|
||||
|
||||
## 设置接口
|
||||
|
||||
### IGameSettings
|
||||
|
||||
游戏设置接口:
|
||||
|
||||
```csharp
|
||||
public interface IGameSettings
|
||||
{
|
||||
AudioSettings Audio { get; }
|
||||
GraphicsSettings Graphics { get; }
|
||||
InputSettings Input { get; }
|
||||
|
||||
void Save();
|
||||
void Load();
|
||||
void ResetToDefaults();
|
||||
}
|
||||
```
|
||||
|
||||
## 场景管理接口
|
||||
|
||||
### ISceneManager
|
||||
|
||||
场景管理器接口:
|
||||
|
||||
```csharp
|
||||
public interface ISceneManager
|
||||
{
|
||||
void SwitchScene<TScene>() where TScene : IScene;
|
||||
Task SwitchSceneAsync<TScene>() where TScnee : IScene;
|
||||
|
||||
void PushScene<TScene>() where TScene : IScene;
|
||||
void PopScene();
|
||||
|
||||
IScene CurrentScene { get; }
|
||||
}
|
||||
```
|
||||
|
||||
### IScene
|
||||
|
||||
场景接口:
|
||||
|
||||
```csharp
|
||||
public interface IScene
|
||||
{
|
||||
void OnEnter();
|
||||
void OnExit();
|
||||
void OnUpdate(float delta);
|
||||
}
|
||||
```
|
||||
|
||||
## 资源管理接口
|
||||
|
||||
### IAssetManager
|
||||
|
||||
资源管理器接口:
|
||||
|
||||
```csharp
|
||||
public interface IAssetManager
|
||||
{
|
||||
T Load<T>(string path) where T : Resource;
|
||||
void Preload<T>(string path) where T : Resource;
|
||||
void Unload(string path);
|
||||
bool IsLoaded(string path);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**相关文档**:
|
||||
|
||||
- [Game 概述](../game)
|
||||
- [Core Abstractions](./core-abstractions)
|
||||
- [存档系统](../game/storage)
|
||||
- [场景管理](../game/scene-management)
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,834 +0,0 @@
|
||||
# GFramework.Game API 参考
|
||||
|
||||
> GFramework.Game 模块的完整 API 参考文档,包含游戏特定功能的详细说明。
|
||||
|
||||
## 📋 目录
|
||||
|
||||
- [架构模块](#架构模块)
|
||||
- [资产管理系统](#资产管理系统)
|
||||
- [存储系统](#存储系统)
|
||||
- [序列化系统](#序列化系统)
|
||||
- [数据模型](#数据模型)
|
||||
- [工具类](#工具类)
|
||||
|
||||
## 架构模块
|
||||
|
||||
### IArchitectureModule
|
||||
|
||||
架构模块接口,定义了模块的基本行为。
|
||||
|
||||
#### 方法签名
|
||||
|
||||
```csharp
|
||||
void Install(IArchitecture architecture);
|
||||
void OnAttach(Architecture architecture);
|
||||
void OnDetach(Architecture architecture);
|
||||
void OnPhase(ArchitecturePhase phase, IArchitecture architecture);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
public class AudioModule : IArchitectureModule
|
||||
{
|
||||
public void Install(IArchitecture architecture)
|
||||
{
|
||||
architecture.RegisterSystem(new AudioSystem());
|
||||
architecture.RegisterUtility(new AudioUtility());
|
||||
}
|
||||
|
||||
public void OnAttach(Architecture architecture)
|
||||
{
|
||||
Logger.Info("Audio module attached to architecture");
|
||||
}
|
||||
|
||||
public void OnDetach(Architecture architecture)
|
||||
{
|
||||
Logger.Info("Audio module detached from architecture");
|
||||
}
|
||||
|
||||
public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
|
||||
{
|
||||
switch (phase)
|
||||
{
|
||||
case ArchitecturePhase.Ready:
|
||||
// 架构准备就绪,可以开始播放背景音乐
|
||||
PlayBackgroundMusic();
|
||||
break;
|
||||
case ArchitecturePhase.Destroying:
|
||||
// 架构正在销毁,清理音频资源
|
||||
CleanupAudioResources();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### AbstractModule
|
||||
|
||||
抽象模块基类,实现了 IArchitectureModule 接口。
|
||||
|
||||
#### 构造函数
|
||||
|
||||
```csharp
|
||||
public AbstractModule();
|
||||
```
|
||||
|
||||
#### 可用方法
|
||||
|
||||
```csharp
|
||||
// 发送事件
|
||||
protected void SendEvent<T>(T e) where T : new();
|
||||
protected void SendEvent<T>(T e);
|
||||
|
||||
// 获取模型
|
||||
protected T GetModel<T>() where T : class, IModel;
|
||||
protected T GetSystem<T>() where T : class, ISystem;
|
||||
protected T GetUtility<T>() where T : class, IUtility;
|
||||
|
||||
// 发送命令
|
||||
protected void SendCommand(ICommand command);
|
||||
protected TResult SendCommand<TResult>(ICommand<TResult> command);
|
||||
|
||||
// 发送查询
|
||||
protected TResult SendQuery<TResult>(IQuery<TResult> query);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
public class SaveModule : AbstractModule
|
||||
{
|
||||
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,因为不是 Node
|
||||
// 在具体的模块实现中处理
|
||||
}
|
||||
|
||||
public override void OnDetach(Architecture architecture)
|
||||
{
|
||||
_autoSaveTimer?.Stop();
|
||||
_autoSaveTimer = null;
|
||||
}
|
||||
|
||||
public override void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
|
||||
{
|
||||
switch (phase)
|
||||
{
|
||||
case ArchitecturePhase.Ready:
|
||||
Logger.Info("Save module ready");
|
||||
break;
|
||||
case ArchitecturePhase.Destroying:
|
||||
Logger.Info("Save module destroying");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAutoSave()
|
||||
{
|
||||
var saveSystem = GetSystem<SaveSystem>();
|
||||
saveSystem.SaveAutoSave();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 资产管理系统
|
||||
|
||||
### IAssetCatalogUtility
|
||||
|
||||
资产目录工具接口,定义了资产管理的基本行为。
|
||||
|
||||
#### 方法签名
|
||||
|
||||
```csharp
|
||||
// 场景资产注册
|
||||
void RegisterSceneUnit(string key, string scenePath);
|
||||
void RegisterScenePage(string key, string scenePath);
|
||||
void RegisterAsset<T>(string key, string path) where T : Resource;
|
||||
void RegisterAsset(string key, Type type, string path);
|
||||
|
||||
// 映射资产注册
|
||||
void RegisterSceneUnit(string key, AssetMapping mapping);
|
||||
void RegisterScenePage(string key, AssetMapping mapping);
|
||||
void RegisterAsset(string key, AssetMapping mapping);
|
||||
|
||||
// 查询方法
|
||||
bool HasSceneUnit(string key);
|
||||
bool HasScenePage(string key);
|
||||
bool HasAsset<T>(string key);
|
||||
bool HasAsset(string key, Type type);
|
||||
|
||||
// 获取方法
|
||||
T GetScene<T>(string key) where T : PackedScene;
|
||||
T GetScenePage<T>(string key) where T : PackedScene;
|
||||
T GetAsset<T>(string key) where T : Resource;
|
||||
T GetAsset(string key, Type type);
|
||||
|
||||
// 元数据获取
|
||||
AssetCatalogMapping GetAssetMetadata(string key);
|
||||
```
|
||||
|
||||
#### AssetCatalogMapping
|
||||
|
||||
资产映射数据类。
|
||||
|
||||
#### 属性
|
||||
|
||||
```csharp
|
||||
public string Key { get; set; }
|
||||
public string Path { get; set; }
|
||||
public Type Type { get; set; }
|
||||
public Dictionary<string, object> Metadata { get; set; }
|
||||
public DateTime RegisteredAt { get; set; }
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
public class GameAssetCatalog : AbstractAssetCatalogUtility
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
// 注册场景资产
|
||||
RegisterSceneUnit("Player", "res://scenes/Player.tscn");
|
||||
RegisterSceneUnit("Enemy", "res://scenes/Enemy.tscn");
|
||||
RegisterScenePage("MainMenu", "res://ui/MainMenu.tscn");
|
||||
RegisterScenePage("GameUI", "res://ui/GameUI.tscn");
|
||||
|
||||
// 注册通用资产
|
||||
RegisterAsset<Texture2D>("PlayerTexture", "res://textures/player.png");
|
||||
RegisterAsset<Texture2D>("EnemyTexture", "res://textures/enemy.png");
|
||||
RegisterAsset<AudioStream>("ShootSound", "res://audio/shoot.wav");
|
||||
RegisterAsset<AudioStream>("ExplosionSound", "res://audio/explosion.wav");
|
||||
|
||||
// 使用元数据注册
|
||||
var playerMapping = new AssetMapping
|
||||
{
|
||||
Key = "Player",
|
||||
Path = "res://scenes/Player.tscn",
|
||||
Type = typeof(PackedScene),
|
||||
Metadata = new Dictionary<string, object>
|
||||
{
|
||||
["category"] = "character",
|
||||
["tags"] = new[] { "player", "hero", "controlled" },
|
||||
["health"] = 100,
|
||||
["speed"] = 5.0f
|
||||
}
|
||||
};
|
||||
RegisterSceneUnit("Player", playerMapping);
|
||||
}
|
||||
|
||||
protected override bool ValidateAsset(string key, string path)
|
||||
{
|
||||
if (!FileAccess.FileExists(path))
|
||||
{
|
||||
GD.PrintErr($"Asset file not found: {path}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
{
|
||||
GD.PrintErr("Asset key cannot be empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnAssetLoaded(string key, object asset)
|
||||
{
|
||||
GD.Print($"Asset loaded: {key} of type {asset.GetType().Name}");
|
||||
|
||||
// 对特定资产进行额外处理
|
||||
if (key == "Player" && asset is PackedScene playerScene)
|
||||
{
|
||||
PreloadPlayerComponents(playerScene);
|
||||
}
|
||||
}
|
||||
|
||||
private void PreloadPlayerComponents(PackedScene playerScene)
|
||||
{
|
||||
// 预加载玩家组件到内存
|
||||
playerScene.Instantiate(); // 实例化以加载子节点
|
||||
}
|
||||
|
||||
// 获取资产
|
||||
public PackedScene GetPlayerScene() => GetScene<PackedScene>("Player");
|
||||
public PackedScene GetEnemyScene() => GetScene<PackedScene>("Enemy");
|
||||
public Texture2D GetPlayerTexture() => GetAsset<Texture2D>("PlayerTexture");
|
||||
public AudioStream GetShootSound() => GetAsset<AudioStream>("ShootSound");
|
||||
}
|
||||
```
|
||||
|
||||
### AbstractResourceFactoryUtility
|
||||
|
||||
抽象资源工厂工具基类。
|
||||
|
||||
#### 抽象方法
|
||||
|
||||
```csharp
|
||||
protected abstract void RegisterFactories();
|
||||
protected abstract T CreateFactory<T>(string path, Dictionary<string, object> metadata = null) where T : class;
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
public class GameResourceFactory : AbstractResourceFactoryUtility
|
||||
{
|
||||
protected override void RegisterFactories()
|
||||
{
|
||||
RegisterFactory<PlayerData>("res://data/players/{id}.json");
|
||||
RegisterFactory<WeaponConfig>("res://data/weapons/{id}.json");
|
||||
RegisterFactory<LevelData>("res://data/levels/{id}.json");
|
||||
}
|
||||
|
||||
public PlayerData CreatePlayer(string playerId)
|
||||
{
|
||||
var playerPath = $"res://data/players/{playerId}.json";
|
||||
return CreateFactory<PlayerData>(playerPath);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public LevelData CreateLevel(string levelId)
|
||||
{
|
||||
return CreateFactory<LevelData>($"res://data/levels/{levelId}.json");
|
||||
}
|
||||
|
||||
protected override PlayerData CreateFactory<PlayerData>(string path, Dictionary<string, object> metadata)
|
||||
{
|
||||
if (!FileAccess.FileExists(path))
|
||||
{
|
||||
return new PlayerData(); // 返回默认数据
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var json = FileAccess.Open(path, FileAccess.ModeFlags.Read).GetAsText();
|
||||
var data = JsonConvert.DeserializeObject<PlayerData>(json);
|
||||
|
||||
// 如果有元数据,可以用来修改数据
|
||||
if (metadata != null)
|
||||
{
|
||||
data.LastLoadedAt = metadata.GetValueOrDefault("loadTime", DateTime.Now);
|
||||
data.LoadCount = metadata.GetValueOrDefault("loadCount", 0) + 1;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GD.PrintErr($"Failed to load player data from {path}: {ex.Message}");
|
||||
return new PlayerData();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 存储系统
|
||||
|
||||
### IStorage
|
||||
|
||||
存储接口,定义了数据持久化的基本行为。
|
||||
|
||||
#### 方法签名
|
||||
|
||||
```csharp
|
||||
// 读写操作
|
||||
void Write<T>(string key, T data);
|
||||
T Read<T>(string key, T defaultValue = default);
|
||||
Task WriteAsync<T>(string key, T data);
|
||||
Task<T> ReadAsync<T>(string key, T defaultValue = default);
|
||||
|
||||
// 存在检查
|
||||
bool Has(string key);
|
||||
void Delete(string key);
|
||||
void Clear();
|
||||
```
|
||||
|
||||
#### IScopedStorage
|
||||
|
||||
作用域存储接口,支持命名空间隔离。
|
||||
|
||||
#### 构造函数
|
||||
|
||||
```csharp
|
||||
public ScopedStorage(IStorage storage, string scope, string delimiter = ".");
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
// 创建根存储
|
||||
var rootStorage = new FileStorage("user://data/");
|
||||
|
||||
// 创建分层存储
|
||||
var playerStorage = new ScopedStorage(rootStorage, "player");
|
||||
var saveStorage = new ScopedStorage(rootStorage, "saves");
|
||||
var settingsStorage = new ScopedStorage(rootStorage, "settings");
|
||||
|
||||
// 使用分层存储
|
||||
playerStorage.Write("profile", playerProfile);
|
||||
playerStorage.Write("inventory", inventory);
|
||||
playerStorage.Write("stats", playerStats);
|
||||
|
||||
saveStorage.Write("slot_1", saveData);
|
||||
saveStorage.Write("slot_2", saveData);
|
||||
|
||||
settingsStorage.Write("graphics", graphicsSettings);
|
||||
settingsStorage.Write("audio", audioSettings);
|
||||
|
||||
// 读取数据
|
||||
var profile = playerStorage.Read<PlayerProfile>("profile", new PlayerProfile());
|
||||
var inventory = playerStorage.Read<Inventory>("inventory", new Inventory());
|
||||
|
||||
// 使用完整路径
|
||||
playerStorage.Write("savegames/auto", autoSaveData); // 写入 player/savegames/auto.json
|
||||
```
|
||||
|
||||
### FileStorage
|
||||
|
||||
文件存储实现,基于 Godot 的 FileAccess。
|
||||
|
||||
#### 构造函数
|
||||
|
||||
```csharp
|
||||
public FileStorage(string rootPath, bool createDirectoryIfNotExists = true);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
// 创建文件存储
|
||||
var storage = new FileStorage("user://saves");
|
||||
|
||||
// 基础用法
|
||||
storage.Write("player", playerData);
|
||||
var loadedPlayer = storage.Read<Player>("player", new Player());
|
||||
|
||||
// 异步用法
|
||||
await storage.WriteAsync("player", playerData);
|
||||
var loadedPlayer = await storage.ReadAsync<Player>("player");
|
||||
|
||||
// 检查存在性
|
||||
bool hasPlayerData = storage.Has("player");
|
||||
storage.Delete("old_save");
|
||||
storage.Clear();
|
||||
```
|
||||
|
||||
### JsonStorage
|
||||
|
||||
JSON 存储实现,使用 Newtonsoft.Json 进行序列化。
|
||||
|
||||
#### 构造函数
|
||||
|
||||
```csharp
|
||||
public JsonStorage(IFileStorage fileStorage, JsonSerializerSettings settings = null);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
var fileStorage = new FileStorage("user://saves");
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
Formatting = Formatting.Indented,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
DefaultValueHandling = DefaultValueHandling.Populate
|
||||
};
|
||||
|
||||
var storage = new JsonStorage(fileStorage, settings);
|
||||
|
||||
// 自定义序列化
|
||||
storage.Write("player", playerData, customSerializer);
|
||||
|
||||
// 压缩缩存储
|
||||
storage.Write("player", playerData, serializer: new JsonSerializer
|
||||
{
|
||||
Formatting = Formatting.None
|
||||
});
|
||||
```
|
||||
|
||||
### CachedStorage
|
||||
|
||||
缓存存储实现,提高频繁访问的性能。
|
||||
|
||||
#### 构造函数
|
||||
|
||||
```csharp
|
||||
public CachedStorage(IStorage innerStorage, TimeSpan cacheExpiry = default);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
var fileStorage = new FileStorage("user://saves");
|
||||
var cachedStorage = new CachedStorage(fileStorage, TimeSpan.FromMinutes(5));
|
||||
|
||||
// 第一次读取会从存储加载
|
||||
var player1 = cachedStorage.Read<Player>("player");
|
||||
|
||||
// 第二次读取会从缓存返回(如果未过期)
|
||||
var player2 = cachedStorage.Read<Player>("player");
|
||||
|
||||
// 手动清除缓存
|
||||
cachedStorage.ClearCache();
|
||||
|
||||
// 检查缓存状态
|
||||
var playerInCache = cachedStorage.IsCached("player");
|
||||
```
|
||||
|
||||
## 序列化系统
|
||||
|
||||
### JsonSerializer
|
||||
|
||||
JSON 序列化工具类,基于 Newtonsoft.Json。
|
||||
|
||||
#### 构造函数
|
||||
|
||||
```csharp
|
||||
public JsonSerializer(JsonSerializerSettings settings = null);
|
||||
```
|
||||
|
||||
#### 方法
|
||||
|
||||
```csharp
|
||||
// 基础序列化
|
||||
public string Serialize<T>(T data);
|
||||
public void SerializeToFile<T>(string path, T data);
|
||||
|
||||
// 反序列化
|
||||
public T Deserialize<T>(string json);
|
||||
public T DeserializeFromFile<T>(string path, T defaultValue = default);
|
||||
|
||||
// 异步序列化
|
||||
public Task<string> SerializeAsync<T>(T data);
|
||||
public Task<T> DeserializeAsync<T>(string json, T defaultValue = default);
|
||||
|
||||
// 压缩序列化
|
||||
public string SerializeCompressed<T>(T data);
|
||||
public T DeserializeCompressed<T>(string compressedJson);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
var serializer = new JsonSerializer();
|
||||
|
||||
// 基础序列化
|
||||
var json = serializer.Serialize(playerData);
|
||||
var loadedPlayer = serializer.Deserialize<Player>(json);
|
||||
|
||||
// 文件操作
|
||||
serializer.SerializeToFile("player.json", playerData);
|
||||
var loadedFromFile = serializer.DeserializeFromFile<Player>("player.json");
|
||||
|
||||
// 异步操作
|
||||
var json = await serializer.SerializeAsync(playerData);
|
||||
var loadedAsync = await serializer.DeserializeAsync<Player>(json);
|
||||
|
||||
// 压缩操作
|
||||
var compressed = serializer.SerializeCompressed(playerData);
|
||||
var decompressed = serializer.DeserializeCompressed<Player>(compressed);
|
||||
```
|
||||
|
||||
### ISerializable
|
||||
|
||||
可序列化接口。
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
public class PlayerData : ISerializable
|
||||
{
|
||||
public string PlayerId { get; set; }
|
||||
public int Level { get; set; }
|
||||
public int Score { get; set; }
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
[JsonProperty("last_saved_at")]
|
||||
public DateTime LastSavedAt { get; set; }
|
||||
|
||||
[JsonProperty("inventory_items")]
|
||||
public List<InventoryItem> Inventory { get; set; }
|
||||
|
||||
// 自定义序列化方法
|
||||
[OnSerializing]
|
||||
public void OnSerializing()
|
||||
{
|
||||
// 序列化前的处理
|
||||
LastSavedAt = DateTime.Now;
|
||||
}
|
||||
|
||||
[OnDeserialized]
|
||||
public void OnDeserialized()
|
||||
{
|
||||
// 反序列化后的处理
|
||||
if (LastSavedAt == default)
|
||||
{
|
||||
LastSavedAt = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 数据模型
|
||||
|
||||
### SaveData
|
||||
|
||||
存档数据类。
|
||||
|
||||
#### 属性
|
||||
|
||||
```csharp
|
||||
public string Version { get; set; } = "1.0.0";
|
||||
public DateTime SavedAt { get; set; }
|
||||
public Dictionary<string, object> PlayerData { get; set; } = new();
|
||||
public Dictionary<string, object> GameData { get; set; } = new();
|
||||
public Dictionary<string, object> SystemData { get; set; } = new();
|
||||
public Dictionary<string, object> ModuleData { get; set; } = new();
|
||||
public Dictionary<string, object> SettingsData { get; set; } = new();
|
||||
```
|
||||
|
||||
### PlayerData
|
||||
|
||||
玩家数据类。
|
||||
|
||||
#### 属性
|
||||
|
||||
```csharp
|
||||
[JsonProperty("player_id")]
|
||||
public string PlayerId { get; set; }
|
||||
|
||||
[JsonProperty("player_name")]
|
||||
public string PlayerName { get; set; }
|
||||
|
||||
[JsonProperty("level")]
|
||||
public int Level { get; set; }
|
||||
|
||||
[JsonProperty("experience")]
|
||||
public long Experience { get; set; }
|
||||
|
||||
[JsonProperty("health")]
|
||||
public int Health { get; set; }
|
||||
public int MaxHealth { get; set; }
|
||||
|
||||
[JsonProperty("position")]
|
||||
public Vector3 Position { get; set; }
|
||||
|
||||
[JsonProperty("inventory")]
|
||||
public InventoryData Inventory { get; set; }
|
||||
|
||||
[JsonProperty("skills")]
|
||||
public List<SkillData> Skills { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### GameData
|
||||
|
||||
游戏数据类。
|
||||
|
||||
#### 属性
|
||||
|
||||
```csharp
|
||||
[JsonProperty("current_level")]
|
||||
public int CurrentLevel { get; set; }
|
||||
|
||||
[JsonProperty("high_score")]
|
||||
public int HighScore { get; set; }
|
||||
|
||||
[JsonProperty("total_play_time")]
|
||||
public float TotalPlayTime { get; set; }
|
||||
|
||||
[JsonProperty("enemies_defeated")]
|
||||
public int EnemiesDefeated { get; set; }
|
||||
|
||||
[JsonProperty("achievements_unlocked")]
|
||||
public List<string> AchievementsUnlocked { get; set; }
|
||||
```
|
||||
|
||||
### InventoryData
|
||||
|
||||
背包数据类。
|
||||
|
||||
#### 属性
|
||||
|
||||
```csharp
|
||||
[JsonProperty("slots")]
|
||||
public List<InventorySlot> Slots { get; set; } = new();
|
||||
|
||||
[JsonProperty("equipment")]
|
||||
public Dictionary<string, string> Equipment { get; set; } = new();
|
||||
```
|
||||
|
||||
### InventorySlot
|
||||
|
||||
背包槽位类。
|
||||
|
||||
#### 属性
|
||||
|
||||
```csharp
|
||||
[JsonProperty("item_id")]
|
||||
public string ItemId { get; set; }
|
||||
|
||||
[JsonProperty("quantity")]
|
||||
public int Quantity { get; set; }
|
||||
|
||||
[JsonProperty("durability")]
|
||||
public int Durability { get; set; }
|
||||
|
||||
[JsonProperty("metadata")]
|
||||
public Dictionary<string, object> Metadata { get; set; } = new();
|
||||
```
|
||||
|
||||
## 工具类
|
||||
|
||||
### StorageUtility
|
||||
|
||||
存储工具类,提供高级存储功能。
|
||||
|
||||
#### 构造函数
|
||||
|
||||
```csharp
|
||||
public StorageUtility(IStorage storage, IVersionMigrationManager migrationManager = null);
|
||||
```
|
||||
|
||||
#### 方法
|
||||
|
||||
```csharp
|
||||
// 自动保存
|
||||
public void EnableAutoSave(IArchitecture architecture, float intervalMinutes = 5.0f);
|
||||
public void DisableAutoSave();
|
||||
|
||||
// 存档管理
|
||||
public void CreateSave(int slotId, SaveData data);
|
||||
public SaveData LoadSave(int slotId);
|
||||
public List<SaveSlotInfo> GetSaveSlots();
|
||||
public void DeleteSave(int slotId);
|
||||
|
||||
// 数据迁移
|
||||
public void RegisterMigration<T>(int fromVersion, int toVersion, Func<T, T> migrator);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
[ContextAware]
|
||||
[Log]
|
||||
public partial class GameManager : Node, IController
|
||||
{
|
||||
private StorageUtility _storageUtility;
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
_storageUtility = Context.GetUtility<StorageUtility>();
|
||||
|
||||
// 注册数据迁移
|
||||
_storageUtility.RegisterMigration<PlayerData>(1, 2, MigratePlayerDataV1ToV2);
|
||||
_storageUtility.RegisterMigration<PlayerData>(2, 3, MigratePlayerDataV2ToV3);
|
||||
|
||||
// 启用自动保存
|
||||
_storageUtility.EnableAutoSave(Context, 5.0f);
|
||||
|
||||
// 监听存档相关事件
|
||||
this.RegisterEvent<SaveRequestEvent>(OnSaveRequest);
|
||||
this.RegisterEvent<LoadRequestEvent>(OnLoadRequest);
|
||||
}
|
||||
|
||||
private void OnSaveRequest(SaveRequestEvent e)
|
||||
{
|
||||
var saveData = CreateSaveData();
|
||||
_storageUtility.CreateSave(e.SlotId, saveData);
|
||||
}
|
||||
|
||||
private void OnLoadRequest(LoadRequestEvent e)
|
||||
{
|
||||
var saveData = _storageUtility.LoadSave(e.SlotId);
|
||||
if (saveData != null)
|
||||
{
|
||||
RestoreGameData(saveData);
|
||||
}
|
||||
}
|
||||
|
||||
private SaveData CreateSaveData()
|
||||
{
|
||||
var playerModel = Context.GetModel<PlayerModel>();
|
||||
var gameModel = Context.GetModel<GameModel>();
|
||||
|
||||
return new SaveData
|
||||
{
|
||||
Version = "1.0.0",
|
||||
SavedAt = DateTime.Now,
|
||||
PlayerData = new Dictionary<string, object>
|
||||
{
|
||||
["player"] = playerModel.GetData(),
|
||||
["statistics"] = playerModel.GetStatistics()
|
||||
},
|
||||
GameData = new Dictionary<string, object>
|
||||
{
|
||||
["game"] = gameModel.GetData()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private PlayerData MigratePlayerDataV1ToV2(PlayerData v1Data)
|
||||
{
|
||||
return new PlayerData
|
||||
{
|
||||
PlayerId = v1Data.PlayerId,
|
||||
PlayerName = v1Data.PlayerName,
|
||||
Level = v1Data.Level,
|
||||
Experience = v1Data.Experience,
|
||||
Health = v1Data.Health,
|
||||
MaxHealth = Math.Max(100, v1Data.MaxHealth), // V2 新增最大生命值
|
||||
Position = v1Data.Position,
|
||||
Inventory = v1Data.Inventory,
|
||||
Skills = v1Data.Skills // V1 的 Kills 字段在 V2 中重命名为 Skills
|
||||
};
|
||||
}
|
||||
|
||||
private PlayerData MigratePlayerDataV2ToV3(PlayerData v2Data)
|
||||
{
|
||||
return new PlayerData
|
||||
{
|
||||
PlayerId = v2Data.PlayerId,
|
||||
PlayerName = Versioning.GetVersionString(v2Data.Version),
|
||||
Level = v2Data.Level,
|
||||
Experience = v2Data.Experience,
|
||||
Health = v2Data.Health,
|
||||
MaxHealth = v2Data.MaxHealth,
|
||||
Position = v2Data.Position,
|
||||
Inventory = v2Data.Inventory,
|
||||
Skills = v2Data.Skills,
|
||||
Achievements = v2Data.Achievements ?? new List<string>() // V3 新增成就系统
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: 1.0.0
|
||||
**更新日期**: 2026-01-12
|
||||
@ -1,951 +0,0 @@
|
||||
# GFramework.Godot API 参考
|
||||
|
||||
> GFramework.Godot 模块的完整 API 参考文档,包含 Godot 特定扩展和集成的详细说明。
|
||||
|
||||
## 📋 目录
|
||||
|
||||
- [架构集成](#架构集成)
|
||||
- [Node 扩展方法](#node-扩展方法)
|
||||
- [信号系统](#信号系统)
|
||||
- [节点池化](#节点池化)
|
||||
- [资源管理](#资源管理)
|
||||
- [日志系统](#日志系统)
|
||||
- [池化管理](#池化管理)
|
||||
- [音频系统](#音频系统)
|
||||
|
||||
## 架构集成
|
||||
|
||||
### AbstractArchitecture
|
||||
|
||||
Godot 特定的架构基类,继承自 Core.Architecture。
|
||||
|
||||
#### 新增方法
|
||||
|
||||
```csharp
|
||||
// Godot 模块安装
|
||||
protected void InstallGodotModule(IGodotModule module);
|
||||
|
||||
protected void InstallGodotModule<T>() where T : IGodotModule, new();
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
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。
|
||||
|
||||
#### 属性
|
||||
|
||||
```csharp
|
||||
Node Node { get; }
|
||||
```
|
||||
|
||||
#### 方法
|
||||
|
||||
```csharp
|
||||
void Install(IArchitecture architecture);
|
||||
void OnAttach(Architecture architecture);
|
||||
void OnDetach(Architecture architecture);
|
||||
void OnPhase(ArchitecturePhase phase, IArchitecture architecture);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
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 接口。
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
[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<T>()
|
||||
|
||||
安全获取子节点,自动类型转换和 null 检查。
|
||||
|
||||
```csharp
|
||||
public static T GetNodeX<T>(this Node node, string path) where T : class;
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
// 安全获取节点
|
||||
var player = GetNodeX<Player>("Player");
|
||||
var healthBar = GetNodeX<ProgressBar>("UI/HealthBar");
|
||||
|
||||
// 如果节点不存在或类型不匹配,会抛出异常
|
||||
// 使用时不需要额外的 null 检查
|
||||
```
|
||||
|
||||
#### GetChildX<T>()
|
||||
|
||||
安全查找子节点,支持递归查找。
|
||||
|
||||
```csharp
|
||||
public static T GetChildX<T>(this Node node, string path) where T : class;
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
// 递归查找子节点
|
||||
var player = FindChildX<Player>("Player");
|
||||
var sprite = FindChildX<Sprite2D>("Enemy/Sprite");
|
||||
```
|
||||
|
||||
### 节点验证
|
||||
|
||||
#### IsValidNode()
|
||||
|
||||
检查节点是否有效且在场景树中。
|
||||
|
||||
```csharp
|
||||
public static bool IsValidNode(this Node node);
|
||||
```
|
||||
|
||||
#### IsInvalidNode()
|
||||
|
||||
检查节点是否无效或不在场景树中。
|
||||
|
||||
```csharp
|
||||
public static bool IsInvalidNode(this Node node);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
Node someNode = GetNode("SomeNode");
|
||||
|
||||
if (IsValidNode(someNode))
|
||||
{
|
||||
someNode.DoSomething();
|
||||
}
|
||||
|
||||
if (IsInvalidNode(someNode))
|
||||
{
|
||||
// 节点无效,需要重新获取
|
||||
}
|
||||
```
|
||||
|
||||
### 安全节点操作
|
||||
|
||||
#### AddChildX()
|
||||
|
||||
安全添加子节点,包含验证。
|
||||
|
||||
```csharp
|
||||
public static void AddChildX(this Node parent, Node child, bool forceReadableName = false, InternalMode internalMode = 0);
|
||||
```
|
||||
|
||||
#### QueueFreeX()
|
||||
|
||||
安全销毁节点,包含验证。
|
||||
|
||||
```csharp
|
||||
public static void QueueFreeX(this Node node);
|
||||
```
|
||||
|
||||
#### FreeX()
|
||||
|
||||
立即销毁节点,谨慎使用。
|
||||
|
||||
```csharp
|
||||
public static void FreeX(this Node node);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
// 创建并添加子节点
|
||||
var bullet = bulletScene.Instantiate<Bullet>();
|
||||
AddChildX(bullet);
|
||||
|
||||
// 安全销毁节点
|
||||
bullet.QueueFreeX();
|
||||
|
||||
// 立即销毁(谨慎使用)
|
||||
tempNode.FreeX();
|
||||
```
|
||||
|
||||
### 异步节点操作
|
||||
|
||||
#### WaitUntilReady()
|
||||
|
||||
等待节点准备就绪。
|
||||
|
||||
```csharp
|
||||
public static async Task WaitUntilReady(this Node node);
|
||||
```
|
||||
|
||||
#### WaitUntil()
|
||||
|
||||
等待条件满足。
|
||||
|
||||
```csharp
|
||||
public static async Task WaitUntil(this Node node, Func<bool> condition);
|
||||
```
|
||||
|
||||
#### WaitUntilTimeout()
|
||||
|
||||
等待指定时间或条件满足。
|
||||
|
||||
```csharp
|
||||
public static async Task WaitUntilTimeout(this Node node, float timeoutSeconds);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
// 等待节点准备就绪
|
||||
await this.WaitUntilReady();
|
||||
|
||||
// 等待条件满足
|
||||
await this.WaitUntil(() => SomeCondition());
|
||||
|
||||
// 等待 2 秒
|
||||
await this.WaitUntilTimeout(2.0f);
|
||||
```
|
||||
|
||||
### 场景树操作
|
||||
|
||||
#### GetParentX<T>()
|
||||
|
||||
安全获取父节点。
|
||||
|
||||
```csharp
|
||||
public static T GetParentX<T>(this Node node) where T : class;
|
||||
```
|
||||
|
||||
#### ForEachChild()
|
||||
|
||||
遍历所有子节点。
|
||||
|
||||
```csharp
|
||||
public static void ForEachChild<T>(this Node node, Action<T> action) where T : Node;
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
// 获取父节点
|
||||
var parent = GetParentX<GameLevel>();
|
||||
|
||||
// 遍历所有子节点
|
||||
this.ForEachChild<Node>(child => {
|
||||
if (child is Sprite2D sprite)
|
||||
{
|
||||
ProcessSprite(sprite);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 信号系统
|
||||
|
||||
### SignalBuilder
|
||||
|
||||
信号构建器,提供流畅的信号连接 API。
|
||||
|
||||
#### 构造函数
|
||||
|
||||
```csharp
|
||||
public SignalBuilder(Node node);
|
||||
```
|
||||
|
||||
#### 连接方法
|
||||
|
||||
```csharp
|
||||
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);
|
||||
```
|
||||
|
||||
#### 配置方法
|
||||
|
||||
```csharp
|
||||
public SignalBuilder WithFlags(ConnectFlags flags);
|
||||
public SignalBuilder CallImmediately();
|
||||
```
|
||||
|
||||
#### 生命周期方法
|
||||
|
||||
```csharp
|
||||
public SignalBuilder UnRegisterWhenNodeExitTree(Node node);
|
||||
public SignalBuilder AddToUnregisterList(IUnRegisterList unregisterList);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
// 基础连接
|
||||
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()
|
||||
|
||||
创建信号构建器。
|
||||
|
||||
```csharp
|
||||
public static SignalBuilder CreateSignalBuilder(this Node node, string signalName);
|
||||
```
|
||||
|
||||
#### ConnectSignal()
|
||||
|
||||
直接连接信号。
|
||||
|
||||
```csharp
|
||||
public static IUnRegister ConnectSignal(this Node node, string signalName, Callable callable);
|
||||
public static IUnRegister ConnectSignal<T1>(this Node node, string signalName, Callable<T1> callable);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
// 创建信号构建器连接
|
||||
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 信号转换为框架事件。
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
[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。
|
||||
|
||||
#### 抽象方法
|
||||
|
||||
```csharp
|
||||
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);
|
||||
```
|
||||
|
||||
#### 公共方法
|
||||
|
||||
```csharp
|
||||
public TNode Spawn(TKey key);
|
||||
public void Despawn(TNode item);
|
||||
public void DespawnAll();
|
||||
public int GetActiveCount(TKey key);
|
||||
public int GetTotalCount(TKey key);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
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
|
||||
|
||||
可池化节点接口。
|
||||
|
||||
```csharp
|
||||
public interface IPoolableNode
|
||||
{
|
||||
void Reset();
|
||||
void SetActive(bool active);
|
||||
bool IsActive { get; }
|
||||
}
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
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 资源加载。
|
||||
|
||||
#### 构造函数
|
||||
|
||||
```csharp
|
||||
public ResourceLoadUtility();
|
||||
```
|
||||
|
||||
#### 方法
|
||||
|
||||
```csharp
|
||||
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;
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
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
|
||||
|
||||
抽象资源工厂工具基类。
|
||||
|
||||
#### 抽象方法
|
||||
|
||||
```csharp
|
||||
protected abstract void RegisterFactories();
|
||||
protected abstract T CreateFactory<T>(string path, Dictionary<string, object> metadata = null) where T : class;
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
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 特定的日志实现。
|
||||
|
||||
#### 构造函数
|
||||
|
||||
```csharp
|
||||
public GodotLogger(string categoryName);
|
||||
public GodotLogger(string categoryName, LogLevel minLevel);
|
||||
```
|
||||
|
||||
#### 方法
|
||||
|
||||
```csharp
|
||||
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);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
// 创建日志器
|
||||
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 日志工厂。
|
||||
|
||||
#### 方法
|
||||
|
||||
```csharp
|
||||
public ILogger CreateLogger(string categoryName);
|
||||
public ILogger CreateLogger(Type type);
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
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<T>
|
||||
|
||||
通用对象池基类。
|
||||
|
||||
#### 构造函数
|
||||
|
||||
```csharp
|
||||
public AbstractObjectPool(
|
||||
Func<T> createFunc,
|
||||
Action<T> actionOnGet = null,
|
||||
Action<T> actionOnRelease = null,
|
||||
bool collectionCheck = false
|
||||
);
|
||||
```
|
||||
|
||||
#### 方法
|
||||
|
||||
```csharp
|
||||
public T Get();
|
||||
public void Release(T item);
|
||||
public void Clear();
|
||||
public int CountInactive { get; }
|
||||
public int CountAll { get; }
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
// 创建对象池
|
||||
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
|
||||
|
||||
音频系统,管理音乐和音效播放。
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```csharp
|
||||
[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
|
||||
@ -1,601 +0,0 @@
|
||||
# GFramework.SourceGenerators API 参考
|
||||
|
||||
> GFramework.SourceGenerators 模块的完整 API 参考文档,包含所有源代码生成器的详细说明。
|
||||
|
||||
## 📋 目录
|
||||
|
||||
- [日志生成器](#日志生成器)
|
||||
- [上下文感知生成器](#上下文感知生成器)
|
||||
- [枚举扩展生成器](#枚举扩展生成器)
|
||||
- [诊断系统](#诊断系统)
|
||||
- [通用工具](#通用工具)
|
||||
|
||||
## 日志生成器
|
||||
|
||||
### [Log] 属性
|
||||
|
||||
为标记的类自动生成 ILogger 字段。
|
||||
|
||||
#### 构造函数参数
|
||||
|
||||
```csharp
|
||||
[Log(
|
||||
string fieldName = "Logger", // 生成的字段名
|
||||
AccessModifier accessModifier = AccessModifier.Private, // 访问修饰符
|
||||
bool isStatic = true, // 是否生成静态字段
|
||||
string loggerName = null, // 自定义日志器名称
|
||||
LogLevel minLevel = LogLevel.None, // 最小日志级别
|
||||
bool includeLoggerInterface = false // 是否包含 ILogger 接口
|
||||
bool enableConditionalCompilation = false // 是否启用条件编译
|
||||
string loggerInterfaceName = "ILogger" // 日志接口名称
|
||||
bool suppressAutoGeneratedAttribute = false // 是否抑制自动生成属性
|
||||
string category = null // 日志类别
|
||||
bool forceContextualLogging = false // 是否强制上下文日志
|
||||
bool enableStructuredLogging = false // 是否启用结构化日志
|
||||
string loggerFactoryName = null // 日志工厂名称
|
||||
string logMessagePrefix = null // 日志消息前缀
|
||||
bool enablePerformanceLogging = false // 是否启用性能日志
|
||||
bool enableAsyncLogging = false // 是否启用异步日志
|
||||
bool enableFluentLogging = false // 是否启用流畅日志
|
||||
bool enableScopedLogging = false // 是否启用作用域日志
|
||||
)]
|
||||
```
|
||||
|
||||
#### 生成的代码示例
|
||||
|
||||
```csharp
|
||||
// 默认配置生成的代码
|
||||
public partial class MyClass
|
||||
{
|
||||
private static readonly ILogger Logger =
|
||||
LoggerFactory.Create(builder => builder
|
||||
.AddConsole()
|
||||
.SetMinimumLevel(LogLevel.Information)
|
||||
.CreateLogger<MyClass>());
|
||||
}
|
||||
|
||||
// 自定义配置生成的代码
|
||||
[Log(
|
||||
fieldName = "CustomLogger",
|
||||
accessModifier = AccessModifier.Public,
|
||||
isStatic = false,
|
||||
loggerName = "Custom.MyClass",
|
||||
minLevel = LogLevel.Debug,
|
||||
includeLoggerInterface = true
|
||||
)]
|
||||
public partial class CustomClass : ILogger
|
||||
{
|
||||
public ILogger CustomLogger { get; }
|
||||
|
||||
static CustomClass()
|
||||
{
|
||||
CustomLogger = LoggerFactory.Create(builder => builder
|
||||
.AddConsole()
|
||||
.SetMinimumLevel(LogLevel.Debug)
|
||||
.CreateLogger<CustomClass>());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 支持的方法
|
||||
|
||||
生成的 Logger 支持以下方法:
|
||||
|
||||
```csharp
|
||||
// 基础日志方法
|
||||
Logger.LogDebug("Debug message");
|
||||
Logger.LogInformation("Info message");
|
||||
Logger.LogWarning("Warning message");
|
||||
Logger.LogError("Error message");
|
||||
Logger.LogCritical("Critical message");
|
||||
|
||||
// 带格式化的日志方法
|
||||
Logger.LogInformation("Player {Name} has {Health} health", playerName, playerHealth);
|
||||
|
||||
// 异步日志方法
|
||||
await Logger.LogInformationAsync("Async message");
|
||||
|
||||
// 结构化日志
|
||||
Logger.LogInformation(new { PlayerName = "John", Health = 100 }, "Player {Name} has {Health} health");
|
||||
```
|
||||
|
||||
## 上下文感知生成器
|
||||
|
||||
### [ContextAware] 属性
|
||||
|
||||
为标记的类自动实现 IContextAware 接口。
|
||||
|
||||
#### 生成的代码示例
|
||||
|
||||
```csharp
|
||||
[ContextAware]
|
||||
public partial class MyClass : IContextAware
|
||||
{
|
||||
private IContextAware.Context _context;
|
||||
|
||||
public IContextAware.Context Context => _context ??= new LazyContext(this);
|
||||
|
||||
public void SetContext(IContextAware.Context context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public IContextAware.Context GetContext()
|
||||
{
|
||||
return _context;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用延迟初始化
|
||||
[ContextAware(useLazy = true)]
|
||||
public partial class LazyContextClass : IContextAware
|
||||
{
|
||||
private Lazy<IContextAware.Context> _context;
|
||||
|
||||
public IContextAware.Context Context => _context.Value;
|
||||
|
||||
public void SetContext(IContextAware.Context context)
|
||||
{
|
||||
_context = new Lazy<IContextAware.Context>(() => context);
|
||||
}
|
||||
}
|
||||
|
||||
// 带上下文验证
|
||||
[ContextAware(validateContext = true)]
|
||||
public partial class ValidatedContextClass : IContextAware
|
||||
{
|
||||
private IContextAware.Context _context;
|
||||
|
||||
public IContextAware.Context Context =>
|
||||
{
|
||||
get => _context;
|
||||
private set
|
||||
{
|
||||
_context = value;
|
||||
if (_context?.IsInvalid == true)
|
||||
{
|
||||
throw new InvalidOperationException("Context is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 可用的方法
|
||||
|
||||
```csharp
|
||||
// 获取模型
|
||||
var playerModel = Context.GetModel<PlayerModel>();
|
||||
var gameModel = Context.GetModel<GameModel>();
|
||||
|
||||
// 获取系统
|
||||
var combatSystem = Context.GetSystem<CombatSystem>();
|
||||
var audioSystem = Context.GetSystem<AudioSystem>();
|
||||
|
||||
// 获取工具
|
||||
var storageUtility = Context.GetUtility<StorageUtility>();
|
||||
var mathUtility = Context.GetUtility<MathUtility>();
|
||||
|
||||
// 发送事件
|
||||
Context.SendEvent<PlayerDiedEvent>();
|
||||
Context.SendEvent<DamageDealtEvent>(new DamageDealtEvent { Damage = 50 });
|
||||
|
||||
// 发送命令
|
||||
Context.SendCommand(new AttackCommand());
|
||||
var result = Context.SendCommand<AttackResult>(new AttackCommand());
|
||||
|
||||
// 发送查询
|
||||
var canAttack = Context.SendQuery<CanAttackQuery>();
|
||||
var playerData = Context.SendQuery<GetPlayerDataQuery>();
|
||||
```
|
||||
|
||||
## 枚举扩展生成器
|
||||
|
||||
### [GenerateEnumExtensions] 属性
|
||||
|
||||
为枚举类型自动生成扩展方法。
|
||||
|
||||
#### 构造函数参数
|
||||
|
||||
```csharp
|
||||
[GenerateEnumExtensions(
|
||||
bool generateIsMethods = true, // 是否生成 IsX() 方法
|
||||
bool generateHasMethod = true, // 是否生成 HasX() 方法
|
||||
bool generateInMethod = true, // 是否生成 In(params T[]) 方法
|
||||
bool generateTryParseMethod = false, // 是否生成 TryParse() 方法
|
||||
string customPrefix = "Is", // 自定义方法名前缀
|
||||
bool includeToString = false, // 是否生成 ToString 扩展
|
||||
bool generateAllMethod = false, // 是否生成 All() 方法
|
||||
bool generateCountMethod = false, // 是否生成 Count() 方法
|
||||
bool generateDescriptionMethod = false, // 是否生成 Description() 方法
|
||||
bool generateValuesMethod = false, // 是否生成 Values() 方法
|
||||
string customNamespace = null, // 自定义命名空间
|
||||
bool generateExtensionMethods = true, // 是否生成扩展方法
|
||||
bool generateFlagMethods = true, // 是否为位标志枚举生成方法
|
||||
bool generateValidationMethods = false, // 是否生成验证方法
|
||||
bool generateUtilityMethods = false, // 是否生成工具方法
|
||||
bool generateQueryableMethods = false, // 是否生成查询方法
|
||||
string customMethodNameFormat = null, // 自定义方法名格式
|
||||
bool generateDocumentation = false, // 是否生成文档注释
|
||||
bool generateExamples = false, // 是否生成使用示例
|
||||
)]
|
||||
```
|
||||
|
||||
#### 普通枚举生成的代码示例
|
||||
|
||||
```csharp
|
||||
[GenerateEnumExtensions]
|
||||
public enum PlayerState
|
||||
{
|
||||
Idle,
|
||||
Walking,
|
||||
Running,
|
||||
Jumping,
|
||||
Attacking
|
||||
}
|
||||
|
||||
// 生成的扩展方法
|
||||
public static class PlayerStateExtensions
|
||||
{
|
||||
public static bool IsIdle(this PlayerState state) => state == PlayerState.Idle;
|
||||
public static bool IsWalking(this PlayerState state) => state == PlayerState.Walking;
|
||||
public static bool IsRunning(this PlayerState state) => state == PlayerState.Running;
|
||||
public static bool IsJumping(this PlayerState state) => state == PlayerState.Jumping;
|
||||
public static bool IsAttacking(this PlayerState state) => state == PlayerState.Attacking;
|
||||
|
||||
public static bool In(this PlayerState state, params PlayerState[] values)
|
||||
{
|
||||
return values.Contains(state);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 位标志枚举生成的代码示例
|
||||
|
||||
```csharp
|
||||
[GenerateEnumExtensions]
|
||||
[Flags]
|
||||
public enum PlayerPermissions
|
||||
{
|
||||
None = 0,
|
||||
CanMove = 1 << 0,
|
||||
CanAttack = 1 << 1,
|
||||
CanUseItems = 1 << 2,
|
||||
CanChat = 1 << 3,
|
||||
CanTrade = 1 << 4
|
||||
}
|
||||
|
||||
// 生成的扩展方法
|
||||
public static class PlayerPermissionsExtensions
|
||||
{
|
||||
public static bool HasCanMove(this PlayerPermissions permissions) => permissions.HasFlag(PlayerPermissions.CanMove);
|
||||
public static bool HasCanAttack(this PlayerPermissions permissions) => permissions.HasFlag(PlayerPermissions.CanAttack);
|
||||
public static bool HasCanUseItems(this PlayerPermissions permissions) => permissions.HasFlag(PlayerPermissions.CanUseItems);
|
||||
|
||||
public static bool HasAny(this PlayerPermissions permissions, params PlayerPermissions[] flags)
|
||||
{
|
||||
return flags.Any(flag => permissions.HasFlag(flag));
|
||||
}
|
||||
|
||||
public static bool HasAll(this PlayerPermissions permissions, params PlayerPermissions[] flags)
|
||||
{
|
||||
return flags.All(flag => permissions.HasFlag(flag));
|
||||
}
|
||||
|
||||
public static PlayerPermissions Add(this PlayerPermissions permissions, PlayerPermissions other)
|
||||
{
|
||||
return permissions | other;
|
||||
}
|
||||
|
||||
public static PlayerPermissions Remove(this PlayerPermissions permissions, PlayerPermissions other)
|
||||
{
|
||||
return permissions & ~other;
|
||||
}
|
||||
|
||||
public static PlayerPermissions Toggle(this PlayerPermissions permissions, PlayerPermissions flag)
|
||||
{
|
||||
return permissions ^ flag;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 高级功能示例
|
||||
|
||||
```csharp
|
||||
[GenerateEnumExtensions(
|
||||
customPrefix = "Is",
|
||||
includeToString = true,
|
||||
generateDescriptionMethod = true,
|
||||
generateUtilityMethods = true
|
||||
)]
|
||||
public enum GameState
|
||||
{
|
||||
[Description("游戏菜单状态")]
|
||||
Menu,
|
||||
|
||||
[Description("游戏进行中")]
|
||||
Playing,
|
||||
|
||||
[Description("游戏暂停")]
|
||||
Paused,
|
||||
|
||||
[Description("游戏结束")]
|
||||
GameOver
|
||||
}
|
||||
|
||||
// 生成的扩展方法包含更多功能
|
||||
public static class GameStateExtensions
|
||||
{
|
||||
// IsX() 方法
|
||||
public static bool IsMenu(this GameState state) => state == GameState.Menu;
|
||||
public static bool IsPlaying(this GameState state) => state == GameState.Playing;
|
||||
public static bool IsPaused(this GameState state) => state == GameState.Paused;
|
||||
public static bool IsGameOver(this GameState state) => state == GameState.GameOver;
|
||||
|
||||
// ToString() 扩展
|
||||
public static string ToDisplayString(this GameState state)
|
||||
{
|
||||
return state switch
|
||||
{
|
||||
GameState.Menu => "游戏菜单",
|
||||
GameState.Playing => "游戏进行中",
|
||||
GameState.Paused => "游戏暂停",
|
||||
GameState.GameOver => "游戏结束"
|
||||
};
|
||||
}
|
||||
|
||||
// Description() 扩展
|
||||
public static string GetDescription(this GameState state)
|
||||
{
|
||||
return typeof(GameState)
|
||||
.GetMember(state.ToString())
|
||||
?.GetCustomAttribute<DescriptionAttribute>()
|
||||
?.Description ?? state.ToString();
|
||||
}
|
||||
|
||||
// 工具方法
|
||||
public static bool IsFinalState(this GameState state) => state == GameState.GameOver;
|
||||
public static bool IsPlayingState(this GameState state) => state == GameState.Playing;
|
||||
public static bool CanPause(this GameState state) => state == GameState.Playing;
|
||||
|
||||
// 验证方法
|
||||
public static bool IsValidTransition(this GameState from, GameState to)
|
||||
{
|
||||
return (from, to) switch
|
||||
{
|
||||
(GameState.Menu, GameState.Playing) => true,
|
||||
(GameState.Playing, GameState.Paused) => true,
|
||||
(GameState.Paused, GameState.Playing) => true,
|
||||
(GameState.Playing, GameState.GameOver) => true,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 诊断系统
|
||||
|
||||
### GF_Logging_001 - 日志字段名冲突
|
||||
|
||||
当使用 `[Log]` 属性时,如果已存在同名字段或属性,会触发此诊断。
|
||||
|
||||
#### 示例
|
||||
|
||||
```csharp
|
||||
// 错误示例:字段名冲突
|
||||
[Log(fieldName = "Logger")]
|
||||
public partial class MyClass
|
||||
{
|
||||
private readonly ILogger Logger; // ❌ 冲突!
|
||||
}
|
||||
|
||||
// 正确的解决方案
|
||||
[Log(fieldName = "CustomLogger")]
|
||||
public partial class MyClass
|
||||
{
|
||||
private readonly ILogger CustomLogger; // ✅ 使用不同的字段名
|
||||
}
|
||||
```
|
||||
|
||||
#### 诊断消息
|
||||
|
||||
```
|
||||
error GF_Logging_001: Logger field name 'Logger' conflicts with existing field in type 'MyClass'
|
||||
```
|
||||
|
||||
### GF_Rule_001 - 上下文感知接口冲突
|
||||
|
||||
当使用 `[ContextAware]` 属性时,如果类型已经实现了 IContextAware 接口,会触发此诊断。
|
||||
|
||||
#### 示例
|
||||
|
||||
```csharp
|
||||
// 错误示例:接口冲突
|
||||
[ContextAware]
|
||||
public partial class MyClass : IContextAware // ❌ 冲突!
|
||||
{
|
||||
public IContextAware.Context Context { get; set; }
|
||||
public void SetContext(IContextAware.Context context) { }
|
||||
public IContextAware.Context GetContext() { return Context; }
|
||||
}
|
||||
|
||||
// 正确的解决方案:移除手动实现
|
||||
[ContextAware]
|
||||
public partial class MyClass // ✅ 让生成器实现接口
|
||||
{
|
||||
// 移除手动实现的代码
|
||||
}
|
||||
```
|
||||
|
||||
#### 诊断消息
|
||||
|
||||
```
|
||||
error GF_Rule_001: Type 'MyClass' already implements 'IContextAware' interface. Remove the [ContextAware] attribute or manual implementation.
|
||||
```
|
||||
|
||||
## 通用工具
|
||||
|
||||
### TypeHelper
|
||||
|
||||
类型操作的工具类。
|
||||
|
||||
#### 主要方法
|
||||
|
||||
```csharp
|
||||
public static class TypeHelper
|
||||
{
|
||||
// 类型检查
|
||||
public static bool IsNullable(Type type);
|
||||
public static bool IsGenericType(Type type);
|
||||
public static bool IsValueType(Type type);
|
||||
public static bool IsEnum(Type type);
|
||||
|
||||
// 泛型类型信息
|
||||
public static Type GetGenericTypeDefinition(Type type);
|
||||
public static Type[] GetGenericArguments(Type type);
|
||||
public static bool ImplementsInterface(Type type, Type interfaceType);
|
||||
|
||||
// 属性信息
|
||||
public static PropertyInfo[] GetProperties(Type type, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance);
|
||||
public static PropertyInfo GetProperty(Type type, string name, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance);
|
||||
public static bool HasProperty(Type type, string name);
|
||||
|
||||
// 方法信息
|
||||
public static MethodInfo[] GetMethods(Type type, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance);
|
||||
public static MethodInfo GetMethod(Type type, string name, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance);
|
||||
public static bool HasMethod(Type type, string name);
|
||||
|
||||
// 构造函数信息
|
||||
public static ConstructorInfo[] GetConstructors(Type type, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance);
|
||||
public static ConstructorInfo GetConstructor(Type type, Type[] parameterTypes);
|
||||
|
||||
// 可实例化检查
|
||||
public static bool HasParameterlessConstructor(Type type);
|
||||
public static bool HasConstructor(Type type, params Type[] parameterTypes);
|
||||
}
|
||||
```
|
||||
|
||||
### SymbolHelper
|
||||
|
||||
符号操作的工具类。
|
||||
|
||||
#### 主要方法
|
||||
|
||||
```csharp
|
||||
public static class SymbolHelper
|
||||
{
|
||||
// 获取符号信息
|
||||
public static ITypeSymbol GetSymbolInfo(INamedTypeSymbol symbol, Compilation compilation);
|
||||
public static IMethodSymbol GetMethodInfo(IMethodSymbol symbol);
|
||||
public static IPropertySymbol GetPropertyInfo(IPropertySymbol symbol);
|
||||
public static IEventSymbol GetEventInfo(IEventSymbol symbol);
|
||||
|
||||
// 符号比较
|
||||
public static bool IsSameSymbol(ISymbol symbol1, ISymbol symbol2);
|
||||
public static string GetFullyQualifiedName(ISymbol symbol);
|
||||
public static string GetDocumentationCommentXml(ISymbol symbol);
|
||||
|
||||
// 符号查找
|
||||
public static IEnumerable<ISymbol> GetMembers(INamedTypeSymbol symbol);
|
||||
public static ISymbol GetMember(INamedTypeSymbol symbol, string name);
|
||||
public static IEnumerable<AttributeData> GetAttributes(ISymbol symbol);
|
||||
public static T GetAttribute<T>(ISymbol symbol);
|
||||
public static bool HasAttribute<T>(ISymbol symbol);
|
||||
}
|
||||
```
|
||||
|
||||
### CompilationHelper
|
||||
|
||||
编译操作的工具类。
|
||||
|
||||
#### 主要方法
|
||||
|
||||
```csharp
|
||||
public static class CompilationHelper
|
||||
{
|
||||
// 获取编译
|
||||
public static Compilation GetCompilation(Compilation startingCompilation);
|
||||
public static Compilation GetCompilation(SyntaxTree syntaxTree);
|
||||
public static Compilation GetCompilation(IEnumerable<SyntaxTree> syntaxTrees);
|
||||
|
||||
// 获取语义模型
|
||||
public static SemanticModel GetSemanticModel(Compilation compilation);
|
||||
public static SemanticModel GetSemanticModel(SyntaxTree syntaxTree);
|
||||
|
||||
// 符号查找
|
||||
public static INamedTypeSymbol GetDeclaredTypeSymbol(Compilation compilation, string name);
|
||||
public static IMethodSymbol GetDeclaredMethodSymbol(Compilation compilation, string name);
|
||||
public static IPropertySymbol GetDeclaredPropertySymbol(Compilation compilation, string name);
|
||||
|
||||
// 类型解析
|
||||
public static INamedTypeSymbol ResolveType(Compilation compilation, string metadataName);
|
||||
public static ITypeSymbol ResolveType(Compilation compilation, Type type);
|
||||
public static IMethodSymbol ResolveMethod(Compilation compilation, string methodFullName, params ITypeSymbol[] parameterTypes);
|
||||
|
||||
// 编译检查
|
||||
public static bool HasCompilationErrors(Compilation compilation);
|
||||
public static IEnumerable<Diagnostic> GetCompilationDiagnostics(Compilation compilation);
|
||||
public static string GetCompilationErrors(Compilation compilation);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置示例
|
||||
|
||||
### 项目文件配置
|
||||
|
||||
```xml
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="GeWuYou.GFramework.SourceGenerators" Version="1.0.0" />
|
||||
<PackageReference Include="GeWuYou.GFramework.SourceGenerators.Attributes" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="$(CompilerGeneratedFilesOutputPath)/**/*.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
```
|
||||
|
||||
### 编辑器配置
|
||||
|
||||
```json
|
||||
{
|
||||
"sourceGenerators": {
|
||||
"debug": true,
|
||||
"logLevel": "Information",
|
||||
"outputDirectory": "Generated",
|
||||
"enableDocumentation": true,
|
||||
"enablePerformanceLogging": false
|
||||
},
|
||||
"loggingGenerator": {
|
||||
"defaultFieldName": "Logger",
|
||||
"defaultAccessLevel": "Private",
|
||||
"defaultStatic": true,
|
||||
"defaultMinLevel": "None"
|
||||
},
|
||||
"contextAwareGenerator": {
|
||||
"useLazyInit": false,
|
||||
"validateContext": false
|
||||
},
|
||||
"enumExtensionsGenerator": {
|
||||
"generateIsMethods": true,
|
||||
"generateHasMethod": true,
|
||||
"generateInMethod": true,
|
||||
"customPrefix": "Is"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: 1.0.0
|
||||
**更新日期**: 2026-01-12
|
||||
@ -284,23 +284,23 @@ public class PlayerController : IController
|
||||
|
||||
## 包说明
|
||||
|
||||
| 包名 | 职责 | 文档 |
|
||||
|------------------|-----------------|------------------------------------|
|
||||
| **architecture** | 架构核心,管理所有组件生命周期 | [查看](/core/architecture/README.md) |
|
||||
| **constants** | 框架常量定义 | 本文档 |
|
||||
| **model** | 数据模型层,存储状态 | [查看](/core/model/README.md) |
|
||||
| **system** | 业务逻辑层,处理业务规则 | [查看](/core/system/README.md) |
|
||||
| **controller** | 控制器层,连接视图和逻辑 | (在 Abstractions 中) |
|
||||
| **utility** | 工具类层,提供无状态工具 | [查看](/core/utility/README.md) |
|
||||
| **command** | 命令模式,封装写操作 | [查看](/core/command/README.md) |
|
||||
| **query** | 查询模式,封装读操作 | [查看](/core/query/README.md) |
|
||||
| **events** | 事件系统,组件间通信 | [查看](/core/events/README.md) |
|
||||
| **property** | 可绑定属性,响应式编程 | [查看](/core/property/README.md) |
|
||||
| **ioc** | IoC 容器,依赖注入 | [查看](/core/ioc/README.md) |
|
||||
| **rule** | 规则接口,定义组件约束 | [查看](/core/rule/README.md) |
|
||||
| **extensions** | 扩展方法,简化 API 调用 | [查看](/core/extensions/README.md) |
|
||||
| **logging** | 日志系统,记录运行日志 | [查看](/core/logging/README.md) |
|
||||
| **environment** | 环境接口,提供运行环境信息 | [查看](/core/environment/README.md) |
|
||||
| 包名 | 职责 | 文档 |
|
||||
|------------------|-----------------|----------------------|
|
||||
| **architecture** | 架构核心,管理所有组件生命周期 | [查看](./architecture) |
|
||||
| **constants** | 框架常量定义 | 本文档 |
|
||||
| **model** | 数据模型层,存储状态 | [查看](./model) |
|
||||
| **system** | 业务逻辑层,处理业务规则 | [查看](./system) |
|
||||
| **controller** | 控制器层,连接视图和逻辑 | (在 Abstractions 中) |
|
||||
| **utility** | 工具类层,提供无状态工具 | [查看](./utility) |
|
||||
| **command** | 命令模式,封装写操作 | [查看](./command) |
|
||||
| **query** | 查询模式,封装读操作 | [查看](./query) |
|
||||
| **events** | 事件系统,组件间通信 | [查看](./events) |
|
||||
| **property** | 可绑定属性,响应式编程 | [查看](./property) |
|
||||
| **ioc** | IoC 容器,依赖注入 | [查看](./ioc) |
|
||||
| **rule** | 规则接口,定义组件约束 | [查看](./rule) |
|
||||
| **extensions** | 扩展方法,简化 API 调用 | [查看](./extensions) |
|
||||
| **logging** | 日志系统,记录运行日志 | [查看](./logging) |
|
||||
| **environment** | 环境接口,提供运行环境信息 | [查看](./environment) |
|
||||
|
||||
## 组件联动
|
||||
|
||||
503
docs/zh-CN/game/scene-management.md
Normal file
503
docs/zh-CN/game/scene-management.md
Normal file
@ -0,0 +1,503 @@
|
||||
# 场景管理
|
||||
|
||||
> GFramework.Game 模块提供的场景管理功能,实现游戏场景的加载、切换和状态管理
|
||||
|
||||
## 概述
|
||||
|
||||
GFramework.Game 提供了统一的场景管理系统,支持场景的异步加载、切换动画、状态保持等功能。通过场景管理,您可以优雅地处理游戏中的各种场景转换,如主菜单、游戏界面、设置菜单等。
|
||||
|
||||
## 核心特性
|
||||
|
||||
- **异步加载**:支持后台异步加载场景,避免卡顿
|
||||
- **场景切换动画**:内置淡入淡出等切换效果
|
||||
- **状态保持**:场景切换时保持必要的游戏状态
|
||||
- **场景栈**:支持场景叠加(如弹出菜单)
|
||||
- **资源管理**:自动管理场景资源的加载和卸载
|
||||
|
||||
## 基本用法
|
||||
|
||||
### 定义场景
|
||||
|
||||
```csharp
|
||||
using GFramework.Game.scene;
|
||||
|
||||
public class GameScene : GameSceneBase
|
||||
{
|
||||
protected override void OnLoad()
|
||||
{
|
||||
// 场景加载时的初始化
|
||||
}
|
||||
|
||||
protected override void OnUnload()
|
||||
{
|
||||
// 场景卸载时的清理
|
||||
}
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
// 进入场景
|
||||
}
|
||||
|
||||
public override void OnExit()
|
||||
{
|
||||
// 退出场景
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 场景管理器
|
||||
|
||||
```csharp
|
||||
using GFramework.Game.scene;
|
||||
|
||||
[ContextAware]
|
||||
public partial class SceneManager : Node
|
||||
{
|
||||
private ISceneManager _sceneManager;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_sceneManager = Context.GetSystem<ISceneManager>();
|
||||
|
||||
// 初始化场景管理器
|
||||
_sceneManager.Initialize();
|
||||
}
|
||||
|
||||
public async Task SwitchToGameScene()
|
||||
{
|
||||
await _sceneManager.SwitchSceneAsync<GameScene>();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 场景加载
|
||||
|
||||
### 同步加载
|
||||
|
||||
适用于小场景的快速切换:
|
||||
|
||||
```csharp
|
||||
public void LoadMainMenu()
|
||||
{
|
||||
_sceneManager.SwitchScene<MainMenuScene>();
|
||||
}
|
||||
```
|
||||
|
||||
### 异步加载
|
||||
|
||||
大场景建议使用异步加载:
|
||||
|
||||
```csharp
|
||||
public async Task LoadGameLevel(string levelName)
|
||||
{
|
||||
// 显示加载界面
|
||||
loadingUI.Show();
|
||||
|
||||
try
|
||||
{
|
||||
// 异步加载场景
|
||||
await _sceneManager.SwitchSceneAsync<GameLevelScene>(scene =>
|
||||
{
|
||||
// 可以在这里传递场景参数
|
||||
var gameScene = scene as GameLevelScene;
|
||||
gameScene.LevelName = levelName;
|
||||
});
|
||||
|
||||
GD.Print("场景加载完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GD.PrintErr($"场景加载失败: {ex.Message}");
|
||||
loadingUI.ShowError();
|
||||
}
|
||||
finally
|
||||
{
|
||||
loadingUI.Hide();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 加载进度
|
||||
|
||||
监听加载进度:
|
||||
|
||||
```csharp
|
||||
public async Task LoadSceneWithProgress<TScene>() where TScene : IScene
|
||||
{
|
||||
loadingUI.Show();
|
||||
|
||||
var progress = new Progress<float>(value =>
|
||||
{
|
||||
loadingUI.UpdateProgress(value * 100);
|
||||
});
|
||||
|
||||
await _sceneManager.SwitchSceneAsync<TScene>(progress: progress);
|
||||
|
||||
loadingUI.Hide();
|
||||
}
|
||||
```
|
||||
|
||||
## 场景切换动画
|
||||
|
||||
### 内置切换效果
|
||||
|
||||
```csharp
|
||||
public async Task SwitchWithFade()
|
||||
{
|
||||
// 使用淡入淡出效果
|
||||
await _sceneManager.SwitchSceneAsync<GameScene>(
|
||||
transition: new FadeTransition(
|
||||
duration: 0.5f,
|
||||
fadeColor: Colors.Black
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public async Task SlideTransition()
|
||||
{
|
||||
// 使用滑动效果
|
||||
await _sceneManager.SwitchSceneAsync<GameScene>(
|
||||
transition: new SlideTransition(
|
||||
direction: Vector2.Left,
|
||||
duration: 0.3f
|
||||
)
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 自定义切换动画
|
||||
|
||||
```csharp
|
||||
public class CustomTransition : ISceneTransition
|
||||
{
|
||||
public float Duration { get; } = 1.0f;
|
||||
|
||||
public async Task PlayAsync(Node fromScene, Node toScene)
|
||||
{
|
||||
// 自定义动画逻辑
|
||||
var tween = CreateTween();
|
||||
|
||||
// 旧场景缩小消失
|
||||
tween.TweenProperty(fromScene, "scale", Vector2.Zero, Duration / 2)
|
||||
.SetTrans(Tween.TransitionType.BackIn);
|
||||
|
||||
await ToSignal(tween, Tween.SignalName.Finished);
|
||||
|
||||
fromScene.Visible = false;
|
||||
toScene.Visible = true;
|
||||
toScene.Scale = Vector2.Zero;
|
||||
|
||||
// 新场景放大出现
|
||||
tween = CreateTween();
|
||||
tween.TweenProperty(toScene, "scale", Vector2.One, Duration / 2)
|
||||
.SetTrans(Tween.TransitionType.BackOut);
|
||||
|
||||
await ToSignal(tween, Tween.SignalName.Finished);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 场景栈
|
||||
|
||||
### 推送场景
|
||||
|
||||
将新场景推入栈中:
|
||||
|
||||
```csharp
|
||||
public void PushPauseMenu()
|
||||
{
|
||||
_sceneManager.PushScene<PauseMenuScene>();
|
||||
}
|
||||
```
|
||||
|
||||
### 弹出场景
|
||||
|
||||
弹出栈顶场景:
|
||||
|
||||
```csharp
|
||||
public void PopScene()
|
||||
{
|
||||
_sceneManager.PopScene();
|
||||
}
|
||||
```
|
||||
|
||||
### 示例:带返回的导航
|
||||
|
||||
```csharp
|
||||
public async Task NavigateToSettings()
|
||||
{
|
||||
// 保存当前场景引用
|
||||
var previousScene = _sceneManager.CurrentScene;
|
||||
|
||||
// 推入设置场景
|
||||
await _sceneManager.PushSceneAsync<SettingsScene>();
|
||||
|
||||
// 设置场景有返回按钮
|
||||
await _sceneManager.PushSceneAsync<ConfirmDialog>(
|
||||
data: new ConfirmData
|
||||
{
|
||||
Message = "是否保存设置?",
|
||||
OnConfirm = () => _sceneManager.PopScene(), // 不保存,直接返回
|
||||
OnCancel = () =>
|
||||
{
|
||||
// 保存设置后返回
|
||||
SaveSettings();
|
||||
_sceneManager.PopScene();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 场景状态管理
|
||||
|
||||
### 保存状态
|
||||
|
||||
```csharp
|
||||
public class GameScene : GameSceneBase
|
||||
{
|
||||
private GameState _state;
|
||||
|
||||
protected override void OnLoad()
|
||||
{
|
||||
// 从存档加载状态
|
||||
_state = LoadGameState();
|
||||
}
|
||||
|
||||
protected override void OnUnload()
|
||||
{
|
||||
// 保存状态
|
||||
SaveGameState(_state);
|
||||
}
|
||||
|
||||
public override void OnExit()
|
||||
{
|
||||
// 清理工作
|
||||
Cleanup();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 跨场景数据传递
|
||||
|
||||
```csharp
|
||||
// 传递数据到新场景
|
||||
await _sceneManager.SwitchSceneAsync<GameScene>(data: new GameData
|
||||
{
|
||||
Level = 5,
|
||||
Difficulty = Difficulty.Hard,
|
||||
ContinueToken = saveToken
|
||||
});
|
||||
|
||||
// 在目标场景中接收数据
|
||||
public class GameScene : GameSceneBase
|
||||
{
|
||||
public override void OnEnter(object data)
|
||||
{
|
||||
var gameData = data as GameData;
|
||||
InitializeLevel(gameData.Level, gameData.Difficulty);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 预加载策略
|
||||
|
||||
### 预加载资源
|
||||
|
||||
```csharp
|
||||
public void PreloadCommonResources()
|
||||
{
|
||||
_sceneManager.PreloadScene<MainMenuScene>();
|
||||
_sceneManager.PreloadScene<GameLevelScene>(count: 3);
|
||||
}
|
||||
```
|
||||
|
||||
### 预加载配置
|
||||
|
||||
```csharp
|
||||
var config = new ScenePreloadConfig
|
||||
{
|
||||
PreloadCount = 5,
|
||||
Priority = ResourceLoader.CacheMode.Cache,
|
||||
Timeout = 30.0f
|
||||
};
|
||||
|
||||
_sceneManager.ConfigurePreload(config);
|
||||
```
|
||||
|
||||
## 资源管理
|
||||
|
||||
### 自动卸载
|
||||
|
||||
```csharp
|
||||
// 配置自动卸载策略
|
||||
var unloadConfig = new SceneUnloadConfig
|
||||
{
|
||||
UnloadDelay = 30.0f, // 30秒后卸载
|
||||
KeepReferences = true, // 保持引用
|
||||
ForceUnloadOnMemoryPressure = true // 内存紧张时强制卸载
|
||||
};
|
||||
|
||||
_sceneManager.ConfigureUnload(unloadConfig);
|
||||
```
|
||||
|
||||
### 手动卸载
|
||||
|
||||
```csharp
|
||||
// 卸载指定场景
|
||||
_sceneManager.UnloadScene<MainMenuScene>();
|
||||
|
||||
// 卸载所有场景
|
||||
_sceneManager.UnloadAllScenes();
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 场景设计原则
|
||||
|
||||
```csharp
|
||||
// 推荐:每个场景职责单一
|
||||
public class MainMenuScene : GameSceneBase { /* 主菜单 */ }
|
||||
public class SettingsScene : GameSceneBase { /* 设置菜单 */ }
|
||||
public class GameHUDScene : GameSceneBase { /* 游戏HUD */ }
|
||||
|
||||
// 避免:场景职责过多
|
||||
public class MegaScene : GameSceneBase
|
||||
{
|
||||
/* 包含菜单、设置、HUD、存档管理... 不要这样设计 */
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 场景切换优化
|
||||
|
||||
```csharp
|
||||
// 推荐:使用异步加载
|
||||
public async Task LoadGame()
|
||||
{
|
||||
loadingUI.Show("正在加载游戏...");
|
||||
await _sceneManager.SwitchSceneAsync<GameScene>();
|
||||
}
|
||||
|
||||
// 避免:同步加载大场景
|
||||
public void LoadGame()
|
||||
{
|
||||
// 这会导致游戏卡顿
|
||||
_sceneManager.SwitchScene<GameScene>();
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 内存管理
|
||||
|
||||
```csharp
|
||||
public class GameScene : GameSceneBase
|
||||
{
|
||||
private Texture2D[] _largeTextures;
|
||||
|
||||
protected override void OnLoad()
|
||||
{
|
||||
// 加载资源
|
||||
_largeTextures = LoadLargeTextures();
|
||||
}
|
||||
|
||||
protected override void OnUnload()
|
||||
{
|
||||
// 及时释放大资源
|
||||
foreach (var texture in _largeTextures)
|
||||
{
|
||||
texture.Dispose();
|
||||
}
|
||||
_largeTextures = null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 错误处理
|
||||
|
||||
```csharp
|
||||
public async Task SafeLoadScene<TScene>() where TScene : IScene
|
||||
{
|
||||
try
|
||||
{
|
||||
await _sceneManager.SwitchSceneAsync<TScene>();
|
||||
}
|
||||
catch (SceneNotFoundException)
|
||||
{
|
||||
Logger.Error($"场景 {typeof(TScene)} 未找到");
|
||||
// 回退到默认场景
|
||||
await _sceneManager.SwitchSceneAsync<FallbackScene>();
|
||||
}
|
||||
catch (ResourceLoadException ex)
|
||||
{
|
||||
Logger.Error($"资源加载失败: {ex.Message}");
|
||||
await ShowRetryDialog();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 与其他模块集成
|
||||
|
||||
### 与 Game 模块集成
|
||||
|
||||
```csharp
|
||||
public class GameLevelScene : GameSceneBase
|
||||
{
|
||||
private GameManager _gameManager;
|
||||
|
||||
public override void OnEnter()
|
||||
{
|
||||
// 初始化游戏管理器
|
||||
_gameManager = Context.GetSystem<GameManager>();
|
||||
_gameManager.StartGame();
|
||||
}
|
||||
|
||||
public override void OnExit()
|
||||
{
|
||||
_gameManager.EndGame();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 与存档系统集成
|
||||
|
||||
```csharp
|
||||
public class GameScene : GameSceneBase
|
||||
{
|
||||
private ISaveSystem _saveSystem;
|
||||
|
||||
protected override void OnLoad()
|
||||
{
|
||||
_saveSystem = Context.GetUtility<ISaveSystem>();
|
||||
|
||||
// 检查是否有自动存档
|
||||
if (_saveSystem.HasAutoSave())
|
||||
{
|
||||
var dialog = Context.GetSystem<IDialogSystem>();
|
||||
await dialog.ShowAsync("发现自动存档,是否继续?",
|
||||
onConfirm: () => LoadAutoSave(),
|
||||
onCancel: () => StartNewGame()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadAutoSave()
|
||||
{
|
||||
var saveData = _saveSystem.LoadAutoSave();
|
||||
RestoreGameState(saveData);
|
||||
}
|
||||
|
||||
public override void OnExit()
|
||||
{
|
||||
// 自动保存
|
||||
_saveSystem.SaveAutoSave(CreateSaveData());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**相关文档**:
|
||||
|
||||
- [Game 概述](./overview)
|
||||
- [游戏设置](./setting)
|
||||
- [存储系统](./storage)
|
||||
- [存档系统](../game/storage)
|
||||
@ -348,7 +348,7 @@ public class PlayerManager
|
||||
|
||||
## 下一步学习
|
||||
|
||||
- [深入了解 Architecture 组件](/core/architecture/architecture)
|
||||
- [掌握事件系统](/core/events/event-bus)
|
||||
- [学习命令查询模式](/core/command-query/commands)
|
||||
- [探索属性系统](/core/property/bindable-property)
|
||||
- [深入了解 Architecture 组件](./core/architecture)
|
||||
- [掌握事件系统](./core/events)
|
||||
- [学习命令查询模式](./core/command)
|
||||
- [探索属性系统](./core/property)
|
||||
@ -182,6 +182,6 @@ dotnet build
|
||||
|
||||
安装完成后,建议:
|
||||
|
||||
1. [快速开始](/getting-started/quick-start) - 构建第一个应用
|
||||
2. [架构概览](/getting-started/architecture-overview) - 了解核心概念
|
||||
3. [Core 模块文档](/core/overview) - 深入学习核心功能
|
||||
1. [快速开始](./getting-started/quick-start) - 构建第一个应用
|
||||
2. [架构概览](./getting-started/architecture-overview) - 了解核心概念
|
||||
3. [Core 模块文档](./core) - 深入学习核心功能
|
||||
@ -321,7 +321,7 @@ Press any key to exit...
|
||||
|
||||
接下来您可以:
|
||||
|
||||
- [深入了解架构组件](/core/architecture/architecture)
|
||||
- [学习事件系统](/core/events/event-bus)
|
||||
- [探索 Godot 集成](/godot/overview)(如果您使用 Godot)
|
||||
- [查看完整教程](/tutorials/basic-tutorial)
|
||||
- [深入了解架构组件](./core/architecture)
|
||||
- [学习事件系统](./core/events)
|
||||
- [探索 Godot 集成](./godot/overview)
|
||||
- [查看完整教程](./tutorials/basic-tutorial)
|
||||
406
docs/zh-CN/godot/coroutine.md
Normal file
406
docs/zh-CN/godot/coroutine.md
Normal file
@ -0,0 +1,406 @@
|
||||
# Godot 协程系统
|
||||
|
||||
> GFramework 在 Godot 引擎中的协程支持,实现异步操作的优雅管理
|
||||
|
||||
## 概述
|
||||
|
||||
GFramework.Godot 提供了与 Godot 引擎深度集成的协程系统,让异步编程变得简单直观。通过协程,您可以暂停执行、等待条件满足、或延迟执行操作,而不会阻塞主线程。
|
||||
|
||||
## 核心特性
|
||||
|
||||
- **无缝集成**:与 Godot 的 `_Process`、`_Ready` 等生命周期方法完美配合
|
||||
- **类型安全**:强类型的协程返回结果处理
|
||||
- **自动清理**:协程与节点生命周期自动绑定,避免内存泄漏
|
||||
- **丰富的等待条件**:支持等待信号、时间延迟、帧结束等多种条件
|
||||
|
||||
## 基本用法
|
||||
|
||||
### 创建协程
|
||||
|
||||
使用 `StartCoroutine` 方法启动协程:
|
||||
|
||||
```csharp
|
||||
using GFramework.Godot.coroutine;
|
||||
|
||||
[ContextAware]
|
||||
public partial class MyNode : Node
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
// 启动协程
|
||||
this.StartCoroutine(DoSomethingAsync());
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator DoSomethingAsync()
|
||||
{
|
||||
GD.Print("开始执行");
|
||||
|
||||
// 等待 2 秒
|
||||
yield return new WaitForSeconds(2.0f);
|
||||
|
||||
GD.Print("2 秒后继续执行");
|
||||
|
||||
// 等待下一帧
|
||||
yield return new WaitForEndOfFrame();
|
||||
|
||||
GD.Print("下一帧继续");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 等待信号
|
||||
|
||||
协程可以等待 Godot 信号:
|
||||
|
||||
```csharp
|
||||
private System.Collections.IEnumerator WaitForSignalExample()
|
||||
{
|
||||
GD.Print("等待按钮点击");
|
||||
|
||||
// 等待按钮被点击
|
||||
var button = GetNode<Button>("Button");
|
||||
yield return new WaitSignal(button, Button.SignalName.Pressed);
|
||||
|
||||
GD.Print("按钮被点击了!");
|
||||
}
|
||||
```
|
||||
|
||||
### 等待条件
|
||||
|
||||
等待自定义条件满足:
|
||||
|
||||
```csharp
|
||||
private System.Collections.IEnumerator WaitUntilCondition()
|
||||
{
|
||||
GD.Print("等待生命值恢复");
|
||||
|
||||
// 等待生命值大于 50
|
||||
var playerModel = Context.GetModel<PlayerModel>();
|
||||
yield return new WaitUntil(() => playerModel.Health.Value > 50);
|
||||
|
||||
GD.Print("生命值已恢复!");
|
||||
}
|
||||
```
|
||||
|
||||
## 等待类型
|
||||
|
||||
### WaitForSeconds
|
||||
|
||||
等待指定时间(秒):
|
||||
|
||||
```csharp
|
||||
private System.Collections.IEnumerator DelayExample()
|
||||
{
|
||||
GD.Print("开始倒计时");
|
||||
|
||||
yield return new WaitForSeconds(1.0f);
|
||||
GD.Print("1 秒过去了");
|
||||
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
GD.Print("又过去了 0.5 秒");
|
||||
}
|
||||
```
|
||||
|
||||
### WaitForSecondsRealtime
|
||||
|
||||
等待实时时间(不受游戏暂停影响):
|
||||
|
||||
```csharp
|
||||
private System.Collections.IEnumerator RealTimeDelay()
|
||||
{
|
||||
// 暂停游戏时也会继续计时
|
||||
yield return new WaitForSecondsRealtime(5.0f);
|
||||
|
||||
GD.Print("5 秒真实时间已过");
|
||||
}
|
||||
```
|
||||
|
||||
### WaitForEndOfFrame
|
||||
|
||||
等待当前帧结束:
|
||||
|
||||
```csharp
|
||||
private System.Collections.IEnumerator EndOfFrameExample()
|
||||
{
|
||||
// 修改数据
|
||||
someData.Value = 100;
|
||||
|
||||
// 等待帧结束后再执行渲染相关操作
|
||||
yield return new WaitForEndOfFrame();
|
||||
|
||||
// 现在可以安全地执行渲染操作
|
||||
UpdateRendering();
|
||||
}
|
||||
```
|
||||
|
||||
### WaitUntil
|
||||
|
||||
等待条件满足:
|
||||
|
||||
```csharp
|
||||
private System.Collections.IEnumerator WaitUntilExample()
|
||||
{
|
||||
var health = Context.GetModel<PlayerModel>().Health;
|
||||
|
||||
// 持续等待直到条件满足
|
||||
yield return new WaitUntil(() => health.Value > 0);
|
||||
|
||||
GD.Print("玩家复活了!");
|
||||
}
|
||||
```
|
||||
|
||||
### WaitWhile
|
||||
|
||||
等待条件不再满足:
|
||||
|
||||
```csharp
|
||||
private System.Collections.IEnumerator WaitWhileExample()
|
||||
{
|
||||
var gameState = Context.GetModel<GameModel>();
|
||||
|
||||
// 等待游戏不再暂停
|
||||
yield return new WaitWhile(() => gameState.IsPaused.Value);
|
||||
|
||||
GD.Print("游戏继续");
|
||||
}
|
||||
```
|
||||
|
||||
## 进阶用法
|
||||
|
||||
### 组合等待
|
||||
|
||||
可以组合多种等待条件:
|
||||
|
||||
```csharp
|
||||
private System.Collections.IEnumerator CombinedWait()
|
||||
{
|
||||
var health = Context.GetModel<PlayerModel>().Health;
|
||||
var button = GetNode<Button>("Button");
|
||||
|
||||
// 等待生命值恢复或按钮点击(任一条件满足即可)
|
||||
yield return new WaitAny(
|
||||
new WaitUntil(() => health.Value > 50),
|
||||
new WaitSignal(button, Button.SignalName.Pressed)
|
||||
);
|
||||
|
||||
GD.Print("条件满足,继续执行");
|
||||
}
|
||||
```
|
||||
|
||||
### 超时处理
|
||||
|
||||
为等待添加超时:
|
||||
|
||||
```csharp
|
||||
private System.Collections.IEnumerator WithTimeout()
|
||||
{
|
||||
var task = new WaitForSeconds(5.0f);
|
||||
var timeout = new WaitForSeconds(5.0f);
|
||||
|
||||
// 等待任务完成,最多等 5 秒
|
||||
bool completed = yield return new WaitRace(task, timeout);
|
||||
|
||||
if (completed)
|
||||
{
|
||||
GD.Print("任务完成");
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.Print("任务超时");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 协程取消
|
||||
|
||||
支持取消正在执行的协程:
|
||||
|
||||
```csharp
|
||||
private CoroutineHandle _coroutine;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_coroutine = this.StartCoroutine(LongRunningTask());
|
||||
}
|
||||
|
||||
public void CancelTask()
|
||||
{
|
||||
_coroutine?.Cancel();
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator LongRunningTask()
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
GD.Print($"进度: {i}%");
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
}
|
||||
}
|
||||
catch (CoroutineCancelledException)
|
||||
{
|
||||
GD.Print("协程被取消");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 自动生命周期管理
|
||||
|
||||
使用 `[ContextAware]` 特性确保协程在节点离开场景树时自动取消:
|
||||
|
||||
```csharp
|
||||
[ContextAware]
|
||||
public partial class MyController : Node
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
// 当节点离开场景树时,协程会自动取消
|
||||
this.StartCoroutine(AutoCleanupCoroutine());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 避免在协程中直接修改 UI
|
||||
|
||||
```csharp
|
||||
// 不推荐:直接在协程中频繁更新 UI
|
||||
private System.Collections.IEnumerator BadExample()
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
label.Text = $"进度: {i}"; // 可能导致性能问题
|
||||
yield return new WaitForEndOfFrame();
|
||||
}
|
||||
}
|
||||
|
||||
// 推荐:使用 BindableProperty 自动更新
|
||||
private System.Collections.IEnumerator GoodExample()
|
||||
{
|
||||
var progress = new BindableProperty<int>(0);
|
||||
|
||||
// 使用 BindableProperty 注册 UI 更新
|
||||
progress.Register(value => label.Text = $"进度: {value}")
|
||||
.UnRegisterWhenNodeExitTree(this);
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
progress.Value = i; // 自动更新 UI
|
||||
yield return new WaitForEndOfFrame();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 使用协程进行资源加载
|
||||
|
||||
```csharp
|
||||
private System.Collections.IEnumerator LoadResourcesAsync()
|
||||
{
|
||||
GD.Print("开始加载资源");
|
||||
|
||||
// 显示加载界面
|
||||
loadingScreen.Visible = true;
|
||||
|
||||
// 异步加载资源
|
||||
var textures = new List<Texture2D>();
|
||||
foreach (var path in resourcePaths)
|
||||
{
|
||||
var texture = ResourceLoader.LoadThreadedGet<Texture2D>(path);
|
||||
|
||||
// 等待每张图片加载完成
|
||||
yield return new WaitUntil(() => texture.GetLoadingStatus() == ResourceLoader.Loaded);
|
||||
|
||||
textures.Add(texture);
|
||||
|
||||
// 更新加载进度
|
||||
UpdateProgress(textures.Count, resourcePaths.Length);
|
||||
}
|
||||
|
||||
// 加载完成
|
||||
loadingScreen.Visible = false;
|
||||
OnResourcesLoaded(textures);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 场景切换处理
|
||||
|
||||
```csharp
|
||||
private System.Collections.IEnumerator SceneTransitionAsync()
|
||||
{
|
||||
GD.Print("开始场景切换");
|
||||
|
||||
// 淡出当前场景
|
||||
fadeAnimation.Play("FadeOut");
|
||||
yield return new WaitSignal(fadeAnimation, AnimationPlayer.SignalName.AnimationFinished);
|
||||
|
||||
// 卸载当前场景
|
||||
GetTree().CurrentScene.QueueFree();
|
||||
|
||||
// 加载新场景
|
||||
var nextScene = ResourceLoader.Load<PackedScene>("res://scenes/NextScene.tscn");
|
||||
var instance = nextScene.Instantiate();
|
||||
GetTree().Root.AddChild(instance);
|
||||
|
||||
// 淡入新场景
|
||||
fadeAnimation.Play("FadeIn");
|
||||
yield return new WaitSignal(fadeAnimation, AnimationPlayer.SignalName.AnimationFinished);
|
||||
|
||||
GD.Print("场景切换完成");
|
||||
}
|
||||
```
|
||||
|
||||
## 与 Source Generators 集成
|
||||
|
||||
GFramework.SourceGenerators 可以自动为您的节点生成协程相关代码:
|
||||
|
||||
```csharp
|
||||
[Log]
|
||||
[ContextAware]
|
||||
public partial class MyNode : Node
|
||||
{
|
||||
// Source Generator 会自动生成 Logger 字段
|
||||
// 无需手动编写日志代码
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Logger.Info("节点已准备就绪");
|
||||
|
||||
this.StartCoroutine(ComplexAsyncOperation());
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator ComplexAsyncOperation()
|
||||
{
|
||||
Logger.Debug("开始复杂异步操作");
|
||||
|
||||
yield return new WaitForSeconds(1.0f);
|
||||
|
||||
Logger.Debug("操作完成");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 协程会在游戏暂停时继续执行吗?
|
||||
|
||||
A: 默认情况下,`WaitForSeconds` 会受到游戏暂停的影响。如果您需要在暂停时继续计时,请使用 `WaitForSecondsRealtime`。
|
||||
|
||||
### Q: 如何调试协程?
|
||||
|
||||
A: 您可以在协程内部使用 `GD.Print()` 或 `Logger.Debug()` 来输出调试信息。VS Code 和 Rider 也支持在协程中设置断点。
|
||||
|
||||
### Q: 协程中出现异常会怎样?
|
||||
|
||||
A: 未捕获的异常会导致协程停止执行,并可能传播到调用方。建议使用 try-catch 包装可能抛出异常的代码。
|
||||
|
||||
---
|
||||
|
||||
**相关文档**:
|
||||
|
||||
- [Godot 概述](./overview)
|
||||
- [Node 扩展方法](./extensions)
|
||||
- [信号系统](./signal)
|
||||
- [事件系统](../core/events)
|
||||
@ -16,9 +16,6 @@ hero:
|
||||
- theme: alt
|
||||
text: 架构概览
|
||||
link: /getting-started/architecture-overview
|
||||
- theme: alt
|
||||
text: API 参考
|
||||
link: /api-reference/core-api
|
||||
|
||||
features:
|
||||
- title: 🏗️ 清洁架构
|
||||
|
||||
174
docs/zh-CN/source-generators/enum-generator.md
Normal file
174
docs/zh-CN/source-generators/enum-generator.md
Normal file
@ -0,0 +1,174 @@
|
||||
# 枚举扩展生成器
|
||||
|
||||
> GFramework.SourceGenerators 自动生成枚举扩展方法
|
||||
|
||||
## 概述
|
||||
|
||||
枚举扩展生成器为枚举类型自动生成常用的扩展方法,如获取描述、转换为字符串、解析等。这大大简化了枚举的操作。
|
||||
|
||||
## 基本用法
|
||||
|
||||
### 标记枚举
|
||||
|
||||
```csharp
|
||||
using GFramework.SourceGenerators.Attributes;
|
||||
|
||||
[EnumExtensions]
|
||||
public enum PlayerState
|
||||
{
|
||||
Idle,
|
||||
Running,
|
||||
Jumping,
|
||||
Attacking
|
||||
}
|
||||
```
|
||||
|
||||
### 生成的方法
|
||||
|
||||
上面的代码会被转换为:
|
||||
|
||||
```csharp
|
||||
public static class PlayerStateExtensions
|
||||
{
|
||||
public static string GetDescription(this PlayerState value)
|
||||
{
|
||||
// 返回枚举的描述
|
||||
}
|
||||
|
||||
public static bool HasFlag(this PlayerState value, PlayerState flag)
|
||||
{
|
||||
// 检查是否包含标志
|
||||
}
|
||||
|
||||
public static PlayerState FromString(string value)
|
||||
{
|
||||
// 从字符串解析枚举
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 常用方法
|
||||
|
||||
### 获取描述
|
||||
|
||||
```csharp
|
||||
[EnumExtensions]
|
||||
public enum ItemQuality
|
||||
{
|
||||
[Description("普通")]
|
||||
Common,
|
||||
|
||||
[Description("稀有")]
|
||||
Rare,
|
||||
|
||||
[Description("史诗")]
|
||||
Epic
|
||||
}
|
||||
|
||||
public void PrintQuality(ItemQuality quality)
|
||||
{
|
||||
// 获取描述文本
|
||||
Console.WriteLine(quality.GetDescription());
|
||||
// 输出: "普通" / "稀有" / "史诗"
|
||||
}
|
||||
```
|
||||
|
||||
### 安全解析
|
||||
|
||||
```csharp
|
||||
public void ParseState(string input)
|
||||
{
|
||||
// 安全地解析字符串为枚举
|
||||
if (PlayerState.Running.TryParse(input, out var state))
|
||||
{
|
||||
Console.WriteLine($"状态: {state}");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 获取所有值
|
||||
|
||||
```csharp
|
||||
public void ListAllStates()
|
||||
{
|
||||
// 获取所有枚举值
|
||||
foreach (var state in PlayerState.GetAllValues())
|
||||
{
|
||||
Console.WriteLine(state);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 标志枚举
|
||||
|
||||
对于使用 `[Flags]` 特性的枚举:
|
||||
|
||||
```csharp
|
||||
[EnumExtensions]
|
||||
[Flags]
|
||||
public enum PlayerPermissions
|
||||
{
|
||||
None = 0,
|
||||
Read = 1,
|
||||
Write = 2,
|
||||
Execute = 4,
|
||||
All = Read | Write | Execute
|
||||
}
|
||||
|
||||
public void CheckPermissions()
|
||||
{
|
||||
var permissions = PlayerPermissions.Read | PlayerPermissions.Write;
|
||||
|
||||
// 检查是否包含特定权限
|
||||
if (permissions.HasFlag(PlayerPermissions.Write))
|
||||
{
|
||||
Console.WriteLine("有写入权限");
|
||||
}
|
||||
|
||||
// 获取所有设置的标志
|
||||
foreach (var flag in permissions.GetFlags())
|
||||
{
|
||||
Console.WriteLine($"权限: {flag}");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 自定义行为
|
||||
|
||||
### 忽略某些值
|
||||
|
||||
```csharp
|
||||
[EnumExtensions(IgnoreValues = new[] { ItemQuality.Undefined })]
|
||||
public enum ItemQuality
|
||||
{
|
||||
Undefined,
|
||||
Common,
|
||||
Rare,
|
||||
Epic
|
||||
}
|
||||
|
||||
// GetAllValues() 不会返回 Undefined
|
||||
```
|
||||
|
||||
### 自定义转换
|
||||
|
||||
```csharp
|
||||
[EnumExtensions(CaseSensitive = false)]
|
||||
public enum Difficulty
|
||||
{
|
||||
Easy,
|
||||
Medium,
|
||||
Hard
|
||||
}
|
||||
|
||||
// FromString("EASY") 也能正确解析
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**相关文档**:
|
||||
|
||||
- [Source Generators 概述](./overview)
|
||||
- [日志生成器](./logging-generator)
|
||||
- [规则生成器](./rule-generator)
|
||||
- [API 参考](../api-reference/source-generators-api)
|
||||
161
docs/zh-CN/source-generators/logging-generator.md
Normal file
161
docs/zh-CN/source-generators/logging-generator.md
Normal file
@ -0,0 +1,161 @@
|
||||
# 日志生成器
|
||||
|
||||
> GFramework.SourceGenerators 自动生成日志代码,减少样板代码
|
||||
|
||||
## 概述
|
||||
|
||||
日志生成器是一个 Source Generator,它会自动为标记了 `[Log]` 特性的类生成 Logger 字段和日志方法调用。这消除了手动编写日志代码的需要,让开发者专注于业务逻辑。
|
||||
|
||||
## 基本用法
|
||||
|
||||
### 标记类
|
||||
|
||||
```csharp
|
||||
using GFramework.SourceGenerators.Attributes;
|
||||
|
||||
[Log]
|
||||
public partial class MyService
|
||||
{
|
||||
public void DoSomething()
|
||||
{
|
||||
// 自动生成 Logger 字段
|
||||
// 自动生成日志调用
|
||||
Logger.Info("执行操作");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 生成代码
|
||||
|
||||
上面的代码会被编译时转换为:
|
||||
|
||||
```csharp
|
||||
public partial class MyService
|
||||
{
|
||||
// 自动生成的字段
|
||||
[CompilerGenerated]
|
||||
private ILogger _logger;
|
||||
|
||||
// 自动生成的属性
|
||||
[CompilerGenerated]
|
||||
public ILogger Logger
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_logger == null)
|
||||
{
|
||||
_logger = LoggerFactory.CreateLogger<MyService>();
|
||||
}
|
||||
return _logger;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 日志级别
|
||||
|
||||
生成的日志方法支持多种级别:
|
||||
|
||||
```csharp
|
||||
[Log]
|
||||
public partial class MyClass
|
||||
{
|
||||
public void Example()
|
||||
{
|
||||
// 调试信息
|
||||
Logger.Debug($"调试信息: {value}");
|
||||
|
||||
// 普通信息
|
||||
Logger.Info("操作成功");
|
||||
|
||||
// 警告
|
||||
Logger.Warning($"警告: {message}");
|
||||
|
||||
// 错误
|
||||
Logger.Error($"错误: {ex.Message}");
|
||||
|
||||
// 严重错误
|
||||
Logger.Critical("系统故障");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 自定义日志类别
|
||||
|
||||
```csharp
|
||||
[Log(LogCategory.Gameplay)]
|
||||
public partial class GameplaySystem
|
||||
{
|
||||
// 日志会标记为 Gameplay 类别
|
||||
public void Update()
|
||||
{
|
||||
Logger.Info("游戏逻辑更新");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 与其他模块集成
|
||||
|
||||
### 与 Godot 集成
|
||||
|
||||
```csharp
|
||||
[Log]
|
||||
[ContextAware]
|
||||
public partial class GodotController : Node
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
Logger.Info("控制器已准备就绪");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 与架构集成
|
||||
|
||||
```csharp
|
||||
[Log]
|
||||
public partial class MySystem : AbstractSystem
|
||||
{
|
||||
protected override void OnInit()
|
||||
{
|
||||
Logger.Info("系统初始化");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 配置选项
|
||||
|
||||
### 禁用自动生成
|
||||
|
||||
```csharp
|
||||
// 禁用自动日志调用生成
|
||||
[Log(AutoLog = false)]
|
||||
public partial class MyClass
|
||||
{
|
||||
// 仍会生成 Logger 字段,但不会自动生成日志调用
|
||||
public void DoSomething()
|
||||
{
|
||||
// 需要手动调用 Logger
|
||||
Logger.Info("手动日志");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 自定义字段名称
|
||||
|
||||
```csharp
|
||||
[Log(FieldName = "_customLogger")]
|
||||
public partial class MyClass
|
||||
{
|
||||
// Logger 字段名称为 _customLogger
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**相关文档**:
|
||||
|
||||
- [Source Generators 概述](./overview)
|
||||
- [枚举扩展生成器](./enum-generator)
|
||||
- [规则生成器](./rule-generator)
|
||||
- [API 参考](../api-reference/source-generators-api)
|
||||
164
docs/zh-CN/source-generators/rule-generator.md
Normal file
164
docs/zh-CN/source-generators/rule-generator.md
Normal file
@ -0,0 +1,164 @@
|
||||
# 规则生成器
|
||||
|
||||
> GFramework.SourceGenerators 自动生成规则验证代码
|
||||
|
||||
## 概述
|
||||
|
||||
规则生成器为实现了规则接口的类型自动生成验证方法。这使得规则定义更加简洁,并确保规则的一致性。
|
||||
|
||||
## 基本用法
|
||||
|
||||
### 定义规则
|
||||
|
||||
```csharp
|
||||
using GFramework.SourceGenerators.Attributes;
|
||||
|
||||
[RuleFor(typeof(Player))]
|
||||
public class PlayerRule : IRule<Player>
|
||||
{
|
||||
public RuleResult Validate(Player player)
|
||||
{
|
||||
if (player.Health <= 0)
|
||||
{
|
||||
return RuleResult.Invalid("玩家生命值不能为零或负数");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(player.Name))
|
||||
{
|
||||
return RuleResult.Invalid("玩家名称不能为空");
|
||||
}
|
||||
|
||||
return RuleResult.Valid();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 使用生成的验证器
|
||||
|
||||
```csharp
|
||||
public class PlayerValidator
|
||||
{
|
||||
// 自动生成 Validate 方法
|
||||
public void ValidatePlayer(Player player)
|
||||
{
|
||||
var result = PlayerRuleValidator.Validate(player);
|
||||
|
||||
if (!result.IsValid)
|
||||
{
|
||||
Console.WriteLine($"验证失败: {result.ErrorMessage}");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 组合规则
|
||||
|
||||
### 多规则组合
|
||||
|
||||
```csharp
|
||||
[RuleFor(typeof(Player), RuleCombinationType.And)]
|
||||
public class PlayerHealthRule : IRule<Player>
|
||||
{
|
||||
public RuleResult Validate(Player player)
|
||||
{
|
||||
if (player.Health <= 0)
|
||||
return RuleResult.Invalid("生命值必须大于0");
|
||||
return RuleResult.Valid();
|
||||
}
|
||||
}
|
||||
|
||||
[RuleFor(typeof(Player), RuleCombinationType.And)]
|
||||
public class PlayerNameRule : IRule<Player>
|
||||
{
|
||||
public RuleResult Validate(Player player)
|
||||
{
|
||||
if (string.IsNullOrEmpty(player.Name))
|
||||
return RuleResult.Invalid("名称不能为空");
|
||||
return RuleResult.Valid();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 验证所有规则
|
||||
|
||||
```csharp
|
||||
public void ValidateAll(Player player)
|
||||
{
|
||||
var results = PlayerRuleValidator.ValidateAll(player);
|
||||
|
||||
foreach (var result in results)
|
||||
{
|
||||
if (!result.IsValid)
|
||||
{
|
||||
Console.WriteLine(result.ErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 异步规则
|
||||
|
||||
```csharp
|
||||
[RuleFor(typeof(Player), IsAsync = true)]
|
||||
public class AsyncPlayerRule : IAsyncRule<Player>
|
||||
{
|
||||
public async Task<RuleResult> ValidateAsync(Player player)
|
||||
{
|
||||
// 异步验证,如检查服务器
|
||||
var isBanned = await CheckBanStatus(player.Id);
|
||||
|
||||
if (isBanned)
|
||||
{
|
||||
return RuleResult.Invalid("玩家已被封禁");
|
||||
}
|
||||
|
||||
return RuleResult.Valid();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 单一职责
|
||||
|
||||
```csharp
|
||||
// 推荐:每个规则只验证一个方面
|
||||
[RuleFor(typeof(Player))]
|
||||
public class PlayerHealthRule : IRule<Player> { }
|
||||
|
||||
[RuleFor(typeof(Player))]
|
||||
public class PlayerNameRule : IRule<Player> { }
|
||||
|
||||
// 避免:在一个规则中验证多个方面
|
||||
[RuleFor(typeof(Player))]
|
||||
public class PlayerMegaRule : IRule<Player>
|
||||
{
|
||||
public RuleResult Validate(Player player)
|
||||
{
|
||||
// 验证健康、名称、等级...
|
||||
// 不要这样设计
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 清晰的错误信息
|
||||
|
||||
```csharp
|
||||
public RuleResult Validate(Player player)
|
||||
{
|
||||
// 推荐:具体的错误信息
|
||||
return RuleResult.Invalid($"玩家 {player.Name} 的生命值 {player.Health} 不能小于 1");
|
||||
|
||||
// 避免:模糊的错误信息
|
||||
return RuleResult.Invalid("无效的玩家");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**相关文档**:
|
||||
|
||||
- [Source Generators 概述](./overview)
|
||||
- [日志生成器](./logging-generator)
|
||||
- [枚举扩展生成器](./enum-generator)
|
||||
- [API 参考](../api-reference/source-generators-api)
|
||||
@ -437,9 +437,9 @@ dotnet test
|
||||
|
||||
### 学习资源
|
||||
|
||||
- [GFramework 主文档](/)
|
||||
- [Core 模块文档](/core/overview)
|
||||
- [Godot 集成文档](/godot/overview)
|
||||
- [API 参考](/api-reference/core-api)
|
||||
- [GFramework 主文档](../)
|
||||
- [Core 模块文档](../core)
|
||||
- [Godot 集成文档](../godot/overview)
|
||||
- [API 参考](../api-reference/core-api)
|
||||
|
||||
享受游戏开发的乐趣吧!🎮
|
||||
Loading…
x
Reference in New Issue
Block a user