mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
Merge pull request #89 from GeWuYou/refactor/extract-ecs-to-independent-module
Refactor/extract ecs to independent module
This commit is contained in:
commit
05d7557fa1
9
.github/workflows/ci.yml
vendored
9
.github/workflows/ci.yml
vendored
@ -125,6 +125,15 @@ jobs:
|
||||
--no-build \
|
||||
--logger "trx;LogFileName=sg-$RANDOM.trx" \
|
||||
--results-directory TestResults
|
||||
|
||||
- name: Test - GFramework.Ecs.Arch.Tests
|
||||
run: |
|
||||
dotnet test GFramework.Ecs.Arch.Tests \
|
||||
-c Release \
|
||||
--no-build \
|
||||
--logger "trx;LogFileName=ecs-arch-$RANDOM.trx" \
|
||||
--results-directory TestResults
|
||||
|
||||
- name: Generate CTRF report
|
||||
run: |
|
||||
mkdir -p ctrf
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace GFramework.Core.Abstractions.architecture;
|
||||
|
||||
/// <summary>
|
||||
/// 架构模块注册表 - 用于外部模块的自动注册
|
||||
/// </summary>
|
||||
public static class ArchitectureModuleRegistry
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, Func<IServiceModule>> _factories = new();
|
||||
|
||||
/// <summary>
|
||||
/// 注册模块工厂(幂等操作,相同模块名只会注册一次)
|
||||
/// </summary>
|
||||
/// <param name="factory">模块工厂函数</param>
|
||||
public static void Register(Func<IServiceModule> factory)
|
||||
{
|
||||
// 创建临时实例以获取模块名(用于幂等性检查)
|
||||
var tempModule = factory();
|
||||
var moduleName = tempModule.ModuleName;
|
||||
|
||||
// 幂等注册:相同模块名只注册一次
|
||||
_factories.TryAdd(moduleName, factory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建所有已注册的模块实例
|
||||
/// </summary>
|
||||
/// <returns>模块实例集合</returns>
|
||||
public static IEnumerable<IServiceModule> CreateModules()
|
||||
{
|
||||
return _factories.Values.Select(f => f());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空注册表(主要用于测试)
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
_factories.Clear();
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
using GFramework.Core.Abstractions.ioc;
|
||||
using GFramework.Core.Abstractions.properties;
|
||||
|
||||
namespace GFramework.Core.Abstractions.architecture;
|
||||
|
||||
@ -18,8 +17,7 @@ public interface IServiceModuleManager
|
||||
/// 注册内置的服务模块。
|
||||
/// </summary>
|
||||
/// <param name="container">IoC容器实例,用于解析依赖。</param>
|
||||
/// <param name="properties">架构属性配置,用于模块初始化。</param>
|
||||
void RegisterBuiltInModules(IIocContainer container, ArchitectureProperties properties);
|
||||
void RegisterBuiltInModules(IIocContainer container);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有已注册的服务模块。
|
||||
|
||||
@ -17,10 +17,4 @@ public sealed class ArchitectureProperties
|
||||
/// 默认值为 false,表示不启用严格验证。
|
||||
/// </summary>
|
||||
public bool StrictPhaseValidation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启用 ECS(Entity Component System)功能的开关。
|
||||
/// 当设置为 true 时,架构将启用 ECS 相关功能。
|
||||
/// </summary>
|
||||
public bool EnableEcs { get; set; }
|
||||
}
|
||||
@ -1,9 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TargetFrameworks>net10.0;net8.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mediator.Abstractions" Version="3.0.1"/>
|
||||
|
||||
@ -4,7 +4,6 @@ using GFramework.Core.Abstractions.environment;
|
||||
using GFramework.Core.Abstractions.events;
|
||||
using GFramework.Core.Abstractions.ioc;
|
||||
using GFramework.Core.Abstractions.model;
|
||||
using GFramework.Core.Abstractions.properties;
|
||||
using GFramework.Core.Abstractions.query;
|
||||
using GFramework.Core.Abstractions.system;
|
||||
using GFramework.Core.Abstractions.utility;
|
||||
@ -15,7 +14,6 @@ using GFramework.Core.events;
|
||||
using GFramework.Core.ioc;
|
||||
using GFramework.Core.query;
|
||||
using Mediator;
|
||||
using NUnit.Framework;
|
||||
using ICommand = GFramework.Core.Abstractions.command.ICommand;
|
||||
|
||||
namespace GFramework.Core.Tests.architecture;
|
||||
@ -48,8 +46,7 @@ public class ArchitectureServicesTests
|
||||
|
||||
private void RegisterBuiltInServices()
|
||||
{
|
||||
var properties = new ArchitectureProperties();
|
||||
_services!.ModuleManager.RegisterBuiltInModules(_services.Container, properties);
|
||||
_services!.ModuleManager.RegisterBuiltInModules(_services.Container);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -216,13 +213,11 @@ public class ArchitectureServicesTests
|
||||
[Test]
|
||||
public void Multiple_Instances_Should_Have_Independent_EventBus()
|
||||
{
|
||||
var properties = new ArchitectureProperties();
|
||||
|
||||
var services1 = new ArchitectureServices();
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container, properties);
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container);
|
||||
|
||||
var services2 = new ArchitectureServices();
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container, properties);
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container);
|
||||
|
||||
Assert.That(services1.EventBus, Is.Not.SameAs(services2.EventBus));
|
||||
}
|
||||
@ -233,13 +228,11 @@ public class ArchitectureServicesTests
|
||||
[Test]
|
||||
public void Multiple_Instances_Should_Have_Independent_CommandBus()
|
||||
{
|
||||
var properties = new ArchitectureProperties();
|
||||
|
||||
var services1 = new ArchitectureServices();
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container, properties);
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container);
|
||||
|
||||
var services2 = new ArchitectureServices();
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container, properties);
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container);
|
||||
|
||||
Assert.That(services1.CommandExecutor, Is.Not.SameAs(services2.CommandExecutor));
|
||||
}
|
||||
@ -250,13 +243,11 @@ public class ArchitectureServicesTests
|
||||
[Test]
|
||||
public void Multiple_Instances_Should_Have_Independent_QueryBus()
|
||||
{
|
||||
var properties = new ArchitectureProperties();
|
||||
|
||||
var services1 = new ArchitectureServices();
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container, properties);
|
||||
services1.ModuleManager.RegisterBuiltInModules(services1.Container);
|
||||
|
||||
var services2 = new ArchitectureServices();
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container, properties);
|
||||
services2.ModuleManager.RegisterBuiltInModules(services2.Container);
|
||||
|
||||
Assert.That(services1.QueryExecutor, Is.Not.SameAs(services2.QueryExecutor));
|
||||
}
|
||||
@ -269,27 +260,6 @@ public class ArchitectureServicesTests
|
||||
{
|
||||
Assert.That(_services!.ModuleManager, Is.Not.Null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试EnableEcs配置开关
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void EnableEcs_Should_Control_Ecs_Module_Registration()
|
||||
{
|
||||
var propertiesWithEcs = new ArchitectureProperties { EnableEcs = true };
|
||||
var propertiesWithoutEcs = new ArchitectureProperties { EnableEcs = false };
|
||||
|
||||
var servicesWithEcs = new ArchitectureServices();
|
||||
servicesWithEcs.ModuleManager.RegisterBuiltInModules(servicesWithEcs.Container, propertiesWithEcs);
|
||||
|
||||
var servicesWithoutEcs = new ArchitectureServices();
|
||||
servicesWithoutEcs.ModuleManager.RegisterBuiltInModules(servicesWithoutEcs.Container, propertiesWithoutEcs);
|
||||
|
||||
var modulesWithEcs = servicesWithEcs.ModuleManager.GetModules();
|
||||
var modulesWithoutEcs = servicesWithoutEcs.ModuleManager.GetModules();
|
||||
|
||||
Assert.That(modulesWithEcs.Count, Is.GreaterThan(modulesWithoutEcs.Count));
|
||||
}
|
||||
}
|
||||
|
||||
#region Test Classes
|
||||
|
||||
@ -13,7 +13,5 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.3"/>
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0"/>
|
||||
<PackageReference Include="Arch" Version="2.1.0"/>
|
||||
<PackageReference Include="Arch.System" Version="1.1.0"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@ -641,8 +641,8 @@ public abstract class Architecture(
|
||||
_logger = LoggerFactoryResolver.Provider.CreateLogger(GetType().Name);
|
||||
Environment.Initialize();
|
||||
|
||||
// 注册内置服务模块(根据配置)
|
||||
Services.ModuleManager.RegisterBuiltInModules(Container, Configuration.ArchitectureProperties);
|
||||
// 注册内置服务模块
|
||||
Services.ModuleManager.RegisterBuiltInModules(Container);
|
||||
|
||||
// 将 Environment 注册到容器(如果尚未注册)
|
||||
if (!Container.Contains<IEnvironment>())
|
||||
|
||||
@ -2,8 +2,6 @@ using GFramework.Core.Abstractions.architecture;
|
||||
using GFramework.Core.Abstractions.ioc;
|
||||
using GFramework.Core.Abstractions.lifecycle;
|
||||
using GFramework.Core.Abstractions.logging;
|
||||
using GFramework.Core.Abstractions.properties;
|
||||
using GFramework.Core.ecs;
|
||||
using GFramework.Core.logging;
|
||||
using GFramework.Core.services.modules;
|
||||
|
||||
@ -44,12 +42,11 @@ public sealed class ServiceModuleManager : IServiceModuleManager
|
||||
|
||||
/// <summary>
|
||||
/// 注册内置服务模块,并根据优先级排序后完成服务注册。
|
||||
/// 内置模块包括事件总线、命令执行器、查询执行器等核心模块,
|
||||
/// 并根据配置决定是否启用ECS模块。
|
||||
/// 内置模块包括事件总线、命令执行器、查询执行器等核心模块。
|
||||
/// 同时注册通过 ArchitectureModuleRegistry 自动注册的外部模块。
|
||||
/// </summary>
|
||||
/// <param name="container">IoC容器实例,用于模块服务注册。</param>
|
||||
/// <param name="properties">架构属性配置,用于判断是否启用ECS模块。</param>
|
||||
public void RegisterBuiltInModules(IIocContainer container, ArchitectureProperties properties)
|
||||
public void RegisterBuiltInModules(IIocContainer container)
|
||||
{
|
||||
if (_builtInModulesRegistered)
|
||||
{
|
||||
@ -57,21 +54,25 @@ public sealed class ServiceModuleManager : IServiceModuleManager
|
||||
return;
|
||||
}
|
||||
|
||||
// 注册内置模块
|
||||
RegisterModule(new EventBusModule());
|
||||
RegisterModule(new CommandExecutorModule());
|
||||
RegisterModule(new QueryExecutorModule());
|
||||
RegisterModule(new AsyncQueryExecutorModule());
|
||||
|
||||
if (properties.EnableEcs)
|
||||
// 注册外部模块(通过 ArchitectureModuleRegistry 自动注册)
|
||||
foreach (var module in ArchitectureModuleRegistry.CreateModules())
|
||||
{
|
||||
RegisterModule(new ArchEcsModule(enabled: true));
|
||||
_logger.Info("ECS module enabled via configuration");
|
||||
RegisterModule(module);
|
||||
_logger.Info($"External module registered: {module.ModuleName}");
|
||||
}
|
||||
|
||||
// 按优先级排序
|
||||
var sortedModules = _modules.OrderBy(m => m.Priority).ToList();
|
||||
_modules.Clear();
|
||||
_modules.AddRange(sortedModules);
|
||||
|
||||
// 注册服务
|
||||
foreach (var module in _modules.Where(module => module.IsEnabled))
|
||||
{
|
||||
_logger.Debug($"Registering services for module: {module.ModuleName}");
|
||||
@ -79,7 +80,7 @@ public sealed class ServiceModuleManager : IServiceModuleManager
|
||||
}
|
||||
|
||||
_builtInModulesRegistered = true;
|
||||
_logger.Info($"Registered {_modules.Count} built-in service modules");
|
||||
_logger.Info($"Registered {_modules.Count} service modules");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
22
GFramework.Ecs.Arch.Abstractions/ArchOptions.cs
Normal file
22
GFramework.Ecs.Arch.Abstractions/ArchOptions.cs
Normal file
@ -0,0 +1,22 @@
|
||||
namespace GFramework.Ecs.Arch.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Arch ECS 配置选项
|
||||
/// </summary>
|
||||
public sealed class ArchOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// World 初始容量
|
||||
/// </summary>
|
||||
public int WorldCapacity { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用统计信息
|
||||
/// </summary>
|
||||
public bool EnableStatistics { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模块优先级
|
||||
/// </summary>
|
||||
public int Priority { get; set; } = 50;
|
||||
}
|
||||
18
GFramework.Ecs.Arch.Abstractions/Directory.Build.props
Normal file
18
GFramework.Ecs.Arch.Abstractions/Directory.Build.props
Normal file
@ -0,0 +1,18 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||
<LangVersion>preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.264">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Meziantou.Polyfill" Version="1.0.71">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>GeWuYou.$(AssemblyName)</PackageId>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GFramework.Core.Abstractions\GFramework.Core.Abstractions.csproj" PrivateAssets="all"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
3
GFramework.Ecs.Arch.Abstractions/GlobalUsings.cs
Normal file
3
GFramework.Ecs.Arch.Abstractions/GlobalUsings.cs
Normal file
@ -0,0 +1,3 @@
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Threading.Tasks;
|
||||
15
GFramework.Ecs.Arch.Abstractions/IArchEcsModule.cs
Normal file
15
GFramework.Ecs.Arch.Abstractions/IArchEcsModule.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using GFramework.Core.Abstractions.architecture;
|
||||
|
||||
namespace GFramework.Ecs.Arch.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Arch ECS 模块接口 - 定义 ECS 模块的核心契约
|
||||
/// </summary>
|
||||
public interface IArchEcsModule : IServiceModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 更新所有 ECS 系统
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">帧间隔时间</param>
|
||||
void Update(float deltaTime);
|
||||
}
|
||||
16
GFramework.Ecs.Arch.Abstractions/IArchSystemAdapter.cs
Normal file
16
GFramework.Ecs.Arch.Abstractions/IArchSystemAdapter.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using GFramework.Core.Abstractions.system;
|
||||
|
||||
namespace GFramework.Ecs.Arch.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Arch 系统适配器接口 - 桥接 Arch.System.ISystem<T> 到框架上下文
|
||||
/// </summary>
|
||||
/// <typeparam name="T">系统数据类型(通常是 float 表示 deltaTime)</typeparam>
|
||||
public interface IArchSystemAdapter<T> : ISystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 更新系统
|
||||
/// </summary>
|
||||
/// <param name="t">系统数据参数(通常是 deltaTime)</param>
|
||||
void Update(in T t);
|
||||
}
|
||||
25
GFramework.Ecs.Arch.Tests/GFramework.Ecs.Arch.Tests.csproj
Normal file
25
GFramework.Ecs.Arch.Tests/GFramework.Ecs.Arch.Tests.csproj
Normal file
@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0"/>
|
||||
<PackageReference Include="Moq" Version="4.20.72"/>
|
||||
<PackageReference Include="NUnit" Version="4.5.0"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GFramework.Ecs.Arch\GFramework.Ecs.Arch.csproj"/>
|
||||
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
5
GFramework.Ecs.Arch.Tests/GlobalUsings.cs
Normal file
5
GFramework.Ecs.Arch.Tests/GlobalUsings.cs
Normal file
@ -0,0 +1,5 @@
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Threading.Tasks;
|
||||
global using NUnit.Framework;
|
||||
global using GFramework.Ecs.Arch;
|
||||
@ -2,13 +2,11 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using Arch.Core;
|
||||
using GFramework.Core.Abstractions.rule;
|
||||
using GFramework.Core.architecture;
|
||||
using GFramework.Core.ecs;
|
||||
using GFramework.Core.ecs.components;
|
||||
using GFramework.Core.ecs.systems;
|
||||
using GFramework.Core.ioc;
|
||||
using NUnit.Framework;
|
||||
using GFramework.Ecs.Arch.components;
|
||||
using GFramework.Ecs.Arch.systems;
|
||||
|
||||
namespace GFramework.Core.Tests.ecs;
|
||||
namespace GFramework.Ecs.Arch.Tests.ecs;
|
||||
|
||||
/// <summary>
|
||||
/// ECS 高级功能测试类 - 使用 Arch 原生 API
|
||||
@ -2,13 +2,11 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using Arch.Core;
|
||||
using GFramework.Core.Abstractions.rule;
|
||||
using GFramework.Core.architecture;
|
||||
using GFramework.Core.ecs;
|
||||
using GFramework.Core.ecs.components;
|
||||
using GFramework.Core.ecs.systems;
|
||||
using GFramework.Core.ioc;
|
||||
using NUnit.Framework;
|
||||
using GFramework.Ecs.Arch.components;
|
||||
using GFramework.Ecs.Arch.systems;
|
||||
|
||||
namespace GFramework.Core.Tests.ecs;
|
||||
namespace GFramework.Ecs.Arch.Tests.ecs;
|
||||
|
||||
/// <summary>
|
||||
/// ECS 基础功能测试类 - 使用 Arch 原生 API
|
||||
@ -2,13 +2,11 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using Arch.Core;
|
||||
using GFramework.Core.Abstractions.rule;
|
||||
using GFramework.Core.architecture;
|
||||
using GFramework.Core.ecs;
|
||||
using GFramework.Core.ecs.components;
|
||||
using GFramework.Core.ecs.systems;
|
||||
using GFramework.Core.ioc;
|
||||
using NUnit.Framework;
|
||||
using GFramework.Ecs.Arch.components;
|
||||
using GFramework.Ecs.Arch.systems;
|
||||
|
||||
namespace GFramework.Core.Tests.ecs;
|
||||
namespace GFramework.Ecs.Arch.Tests.ecs;
|
||||
|
||||
/// <summary>
|
||||
/// ECS 集成测试类 - 使用 Arch 原生 API
|
||||
@ -0,0 +1,135 @@
|
||||
using Arch.Core;
|
||||
using GFramework.Core.Abstractions.architecture;
|
||||
using GFramework.Core.architecture;
|
||||
using GFramework.Core.ioc;
|
||||
using GFramework.Ecs.Arch.Abstractions;
|
||||
using GFramework.Ecs.Arch.extensions;
|
||||
|
||||
namespace GFramework.Ecs.Arch.Tests.integration;
|
||||
|
||||
/// <summary>
|
||||
/// 显式注册集成测试
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ExplicitRegistrationTests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_container = new MicrosoftDiContainer();
|
||||
_context = new ArchitectureContext(_container);
|
||||
|
||||
// 清空注册表,确保测试隔离
|
||||
ArchitectureModuleRegistry.Clear();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
_container?.Clear();
|
||||
_context = null;
|
||||
ArchitectureModuleRegistry.Clear();
|
||||
GameContext.Clear();
|
||||
}
|
||||
|
||||
private MicrosoftDiContainer? _container;
|
||||
private ArchitectureContext? _context;
|
||||
|
||||
/// <summary>
|
||||
/// 测试 Arch ECS 模块显式注册
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ArchEcsModule_Should_Be_Explicitly_Registered()
|
||||
{
|
||||
// Arrange
|
||||
var architecture = new TestArchitecture();
|
||||
|
||||
// Act - 显式注册
|
||||
architecture.UseArch();
|
||||
architecture.Initialize();
|
||||
|
||||
// Assert - 验证 World 已注册(由 ArchEcsModule 注册)
|
||||
var world = architecture.Context.GetService<World>();
|
||||
Assert.That(world, Is.Not.Null, "World should be registered by ArchEcsModule");
|
||||
|
||||
// 验证 IArchEcsModule 已注册
|
||||
var ecsModule = architecture.Context.GetService<IArchEcsModule>();
|
||||
Assert.That(ecsModule, Is.Not.Null, "IArchEcsModule should be registered");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试 World 是否正确注册到容器
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void World_Should_Be_Registered_In_Container()
|
||||
{
|
||||
// Arrange
|
||||
var architecture = new TestArchitecture();
|
||||
|
||||
// Act - 显式注册
|
||||
architecture.UseArch();
|
||||
architecture.Initialize();
|
||||
|
||||
// Assert
|
||||
var world = architecture.Context.GetService<World>();
|
||||
Assert.That(world, Is.Not.Null, "World should be registered in container");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试带配置的注册
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void UseArch_Should_Accept_Configuration()
|
||||
{
|
||||
// Arrange
|
||||
var architecture = new TestArchitecture();
|
||||
var configCalled = false;
|
||||
|
||||
// Act
|
||||
architecture.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2000;
|
||||
options.EnableStatistics = true;
|
||||
configCalled = true;
|
||||
});
|
||||
|
||||
// Assert
|
||||
Assert.That(configCalled, Is.True, "Configuration delegate should be called");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试链式调用
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void UseArch_Should_Support_Chaining()
|
||||
{
|
||||
// Arrange & Act
|
||||
var architecture = new TestArchitecture()
|
||||
.UseArch()
|
||||
.UseArch(options => options.WorldCapacity = 2000);
|
||||
|
||||
architecture.Initialize();
|
||||
|
||||
// Assert - 验证模块已注册
|
||||
var world = architecture.Context.GetService<World>();
|
||||
Assert.That(world, Is.Not.Null, "World should be registered");
|
||||
|
||||
var ecsModule = architecture.Context.GetService<IArchEcsModule>();
|
||||
Assert.That(ecsModule, Is.Not.Null, "IArchEcsModule should be registered");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试架构类,用于测试
|
||||
/// </summary>
|
||||
private class TestArchitecture : Architecture
|
||||
{
|
||||
public TestArchitecture() : base(new ArchitectureConfiguration())
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
// 测试架构,无需额外初始化
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,25 +1,27 @@
|
||||
using Arch.Core;
|
||||
using GFramework.Core.Abstractions.architecture;
|
||||
using GFramework.Core.Abstractions.ioc;
|
||||
|
||||
namespace GFramework.Core.ecs;
|
||||
namespace GFramework.Ecs.Arch;
|
||||
|
||||
/// <summary>
|
||||
/// Arch ECS 模块 - 核心适配器,桥接 Arch 到框架生命周期
|
||||
/// </summary>
|
||||
public sealed class ArchEcsModule : IServiceModule
|
||||
public sealed class ArchEcsModule : IArchEcsModule
|
||||
{
|
||||
private readonly List<ArchSystemAdapter<float>> _systems = [];
|
||||
private readonly ArchOptions _options;
|
||||
private IIocContainer? _container;
|
||||
private bool _isInitialized;
|
||||
private IReadOnlyList<ArchSystemAdapter<float>> _systems = [];
|
||||
private World? _world;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="options">配置选项</param>
|
||||
/// <param name="enabled">是否启用模块</param>
|
||||
public ArchEcsModule(bool enabled = true)
|
||||
public ArchEcsModule(ArchOptions? options = null, bool enabled = true)
|
||||
{
|
||||
_options = options ?? new ArchOptions();
|
||||
IsEnabled = enabled;
|
||||
}
|
||||
|
||||
@ -31,7 +33,7 @@ public sealed class ArchEcsModule : IServiceModule
|
||||
/// <summary>
|
||||
/// 模块优先级
|
||||
/// </summary>
|
||||
public int Priority => 50;
|
||||
public int Priority => _options.Priority;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
@ -47,8 +49,11 @@ public sealed class ArchEcsModule : IServiceModule
|
||||
|
||||
_container = container;
|
||||
|
||||
// 创建并注册 World
|
||||
_world = World.Create();
|
||||
// 注册模块自身
|
||||
container.RegisterPlurality(this);
|
||||
|
||||
// 创建并注册 World(使用配置的容量)
|
||||
_world = World.Create(_options.WorldCapacity);
|
||||
container.Register(_world);
|
||||
}
|
||||
|
||||
@ -65,18 +70,14 @@ public sealed class ArchEcsModule : IServiceModule
|
||||
return;
|
||||
}
|
||||
|
||||
// 从容器获取所有适配器
|
||||
var adapters = _container.GetAll<ArchSystemAdapter<float>>();
|
||||
if (adapters.Count > 0)
|
||||
{
|
||||
_systems.AddRange(adapters);
|
||||
// 从容器按优先级获取所有适配器
|
||||
_systems = _container.GetAllByPriority<ArchSystemAdapter<float>>();
|
||||
|
||||
// 初始化所有系统(会调用 Arch 系统的 Initialize)
|
||||
foreach (var system in _systems)
|
||||
{
|
||||
system.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
_isInitialized = true;
|
||||
}
|
||||
@ -97,7 +98,7 @@ public sealed class ArchEcsModule : IServiceModule
|
||||
system.Destroy();
|
||||
}
|
||||
|
||||
_systems.Clear();
|
||||
_systems = [];
|
||||
|
||||
// 销毁 World
|
||||
if (_world != null)
|
||||
22
GFramework.Ecs.Arch/ArchOptions.cs
Normal file
22
GFramework.Ecs.Arch/ArchOptions.cs
Normal file
@ -0,0 +1,22 @@
|
||||
namespace GFramework.Ecs.Arch;
|
||||
|
||||
/// <summary>
|
||||
/// Arch ECS 模块配置选项
|
||||
/// </summary>
|
||||
public sealed class ArchOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// World 初始容量(默认:1000)
|
||||
/// </summary>
|
||||
public int WorldCapacity { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用统计信息(默认:false)
|
||||
/// </summary>
|
||||
public bool EnableStatistics { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 模块优先级(默认:50)
|
||||
/// </summary>
|
||||
public int Priority { get; set; } = 50;
|
||||
}
|
||||
@ -3,19 +3,29 @@ using GFramework.Core.extensions;
|
||||
using GFramework.Core.system;
|
||||
using ArchSys = Arch.System;
|
||||
|
||||
namespace GFramework.Core.ecs;
|
||||
namespace GFramework.Ecs.Arch;
|
||||
|
||||
/// <summary>
|
||||
/// Arch 系统适配器 - 桥接 Arch.System.ISystem<T> 到框架上下文
|
||||
/// </summary>
|
||||
/// <typeparam name="T">系统数据类型(通常是 float 表示 deltaTime)</typeparam>
|
||||
public abstract class ArchSystemAdapter<T> : AbstractSystem, ArchSys.ISystem<T>
|
||||
public abstract class ArchSystemAdapter<T> : AbstractSystem, IArchSystemAdapter<T>, ArchSys.ISystem<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置 Arch ECS 世界的实例
|
||||
/// </summary>
|
||||
public World World { get; private set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 显式实现 Arch.System.ISystem<T> 的主更新方法
|
||||
/// 调用受保护的虚方法 OnUpdate 以强制子类实现核心更新逻辑
|
||||
/// </summary>
|
||||
/// <param name="t">系统数据参数(通常是 deltaTime)</param>
|
||||
public void Update(in T t)
|
||||
{
|
||||
OnUpdate(in t);
|
||||
}
|
||||
|
||||
// ===== Arch 显式接口实现 =====
|
||||
|
||||
/// <summary>
|
||||
@ -37,16 +47,6 @@ public abstract class ArchSystemAdapter<T> : AbstractSystem, ArchSys.ISystem<T>
|
||||
OnBeforeUpdate(in t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显式实现 Arch.System.ISystem<T> 的主更新方法
|
||||
/// 调用受保护的虚方法 OnUpdate 以强制子类实现核心更新逻辑
|
||||
/// </summary>
|
||||
/// <param name="t">系统数据参数(通常是 deltaTime)</param>
|
||||
public void Update(in T t)
|
||||
{
|
||||
OnUpdate(in t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显式实现 Arch.System.ISystem<T> 的更新后回调方法
|
||||
/// 调用受保护的虚方法 OnAfterUpdate 以允许子类自定义后处理逻辑
|
||||
23
GFramework.Ecs.Arch/GFramework.Ecs.Arch.csproj
Normal file
23
GFramework.Ecs.Arch/GFramework.Ecs.Arch.csproj
Normal file
@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>GeWuYou.$(AssemblyName)</PackageId>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj"
|
||||
PrivateAssets="all"/>
|
||||
<ProjectReference Include="..\GFramework.Ecs.Arch.Abstractions\GFramework.Ecs.Arch.Abstractions.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Arch" Version="2.1.0"/>
|
||||
<PackageReference Include="Arch.System" Version="1.1.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
5
GFramework.Ecs.Arch/GlobalUsings.cs
Normal file
5
GFramework.Ecs.Arch/GlobalUsings.cs
Normal file
@ -0,0 +1,5 @@
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Threading.Tasks;
|
||||
global using GFramework.Core.Abstractions;
|
||||
global using GFramework.Ecs.Arch.Abstractions;
|
||||
192
GFramework.Ecs.Arch/README.md
Normal file
192
GFramework.Ecs.Arch/README.md
Normal file
@ -0,0 +1,192 @@
|
||||
# GFramework.Ecs.Arch
|
||||
|
||||
GFramework 的 Arch ECS 集成包,提供开箱即用的 ECS(Entity Component System)支持。
|
||||
|
||||
## 特性
|
||||
|
||||
- 🎯 **显式集成** - 符合 .NET 生态习惯的显式注册方式
|
||||
- 🔌 **零依赖** - 不使用时,Core 包无 Arch 依赖
|
||||
- 🎯 **类型安全** - 完整的类型系统和编译时检查
|
||||
- ⚡ **高性能** - 基于 Arch ECS 的高性能实现
|
||||
- 🔧 **易扩展** - 简单的系统适配器模式
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 安装包
|
||||
|
||||
```bash
|
||||
dotnet add package GeWuYou.GFramework.Ecs.Arch
|
||||
```
|
||||
|
||||
### 2. 注册 ECS 模块
|
||||
|
||||
```csharp
|
||||
// 在架构初始化时添加 Arch ECS 支持
|
||||
var architecture = new GameArchitecture(config)
|
||||
.UseArch(); // 添加 ECS 支持
|
||||
|
||||
architecture.Initialize();
|
||||
```
|
||||
|
||||
### 3. 带配置的注册
|
||||
|
||||
```csharp
|
||||
var architecture = new GameArchitecture(config)
|
||||
.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2000;
|
||||
options.EnableStatistics = true;
|
||||
options.Priority = 50;
|
||||
});
|
||||
|
||||
architecture.Initialize();
|
||||
```
|
||||
|
||||
```csharp
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Position(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Velocity(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 创建系统
|
||||
|
||||
```csharp
|
||||
using Arch.Core;
|
||||
using GFramework.Ecs.Arch;
|
||||
|
||||
public sealed class MovementSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
private QueryDescription _query;
|
||||
|
||||
protected override void OnArchInitialize()
|
||||
{
|
||||
_query = new QueryDescription()
|
||||
.WithAll<Position, Velocity>();
|
||||
}
|
||||
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
World.Query(in _query, (ref Position pos, ref Velocity vel) =>
|
||||
{
|
||||
pos.X += vel.X * deltaTime;
|
||||
pos.Y += vel.Y * deltaTime;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 注册系统
|
||||
|
||||
```csharp
|
||||
public class MyArchitecture : Architecture
|
||||
{
|
||||
protected override void OnRegisterSystem(IIocContainer container)
|
||||
{
|
||||
container.Register<MovementSystem>();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 创建实体
|
||||
|
||||
```csharp
|
||||
var world = this.GetService<World>();
|
||||
var entity = world.Create(
|
||||
new Position(0, 0),
|
||||
new Velocity(1, 1)
|
||||
);
|
||||
```
|
||||
|
||||
### 8. 更新系统
|
||||
|
||||
```csharp
|
||||
var ecsModule = this.GetService<IArchEcsModule>();
|
||||
ecsModule.Update(deltaTime);
|
||||
```
|
||||
|
||||
## 配置选项
|
||||
|
||||
### 代码配置
|
||||
|
||||
```csharp
|
||||
var architecture = new GameArchitecture(config)
|
||||
.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2000;
|
||||
options.EnableStatistics = true;
|
||||
options.Priority = 50;
|
||||
});
|
||||
```
|
||||
|
||||
### 配置说明
|
||||
|
||||
- `WorldCapacity` - World 初始容量(默认:1000)
|
||||
- `EnableStatistics` - 是否启用统计信息(默认:false)
|
||||
- `Priority` - 模块优先级(默认:50)
|
||||
|
||||
## 架构说明
|
||||
|
||||
### 显式注册模式
|
||||
|
||||
本包采用 .NET 生态标准的显式注册模式,基于架构实例:
|
||||
|
||||
**优点:**
|
||||
|
||||
- ✅ 符合 .NET 生态习惯
|
||||
- ✅ 显式、可控
|
||||
- ✅ 易于测试和调试
|
||||
- ✅ 支持配置
|
||||
- ✅ 支持链式调用
|
||||
- ✅ 避免"魔法"行为
|
||||
|
||||
**使用方式:**
|
||||
```csharp
|
||||
// 在架构初始化时添加
|
||||
var architecture = new GameArchitecture(config)
|
||||
.UseArch(); // 显式注册
|
||||
|
||||
architecture.Initialize();
|
||||
```
|
||||
|
||||
详见:[INTEGRATION_PATTERN.md](INTEGRATION_PATTERN.md)
|
||||
|
||||
### 系统适配器
|
||||
|
||||
`ArchSystemAdapter<T>` 桥接 Arch.System.ISystem<T> 到 GFramework 架构:
|
||||
|
||||
- 自动获取 World 实例
|
||||
- 集成到框架生命周期
|
||||
- 支持上下文感知(Context-Aware)
|
||||
|
||||
### 生命周期
|
||||
|
||||
1. **注册阶段** - 模块自动注册到架构
|
||||
2. **初始化阶段** - 创建 World,初始化系统
|
||||
3. **运行阶段** - 每帧调用 Update
|
||||
4. **销毁阶段** - 清理资源,销毁 World
|
||||
|
||||
## 示例
|
||||
|
||||
完整示例请参考 `GFramework.Ecs.Arch.Tests` 项目。
|
||||
|
||||
## 依赖
|
||||
|
||||
- GFramework.Core >= 1.0.0
|
||||
- Arch >= 2.1.0
|
||||
- Arch.System >= 1.1.0
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT License
|
||||
@ -1,6 +1,6 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace GFramework.Core.ecs.components;
|
||||
namespace GFramework.Ecs.Arch.components;
|
||||
|
||||
/// <summary>
|
||||
/// 位置组件,用于表示实体在二维空间中的坐标位置。
|
||||
@ -1,6 +1,6 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace GFramework.Core.ecs.components;
|
||||
namespace GFramework.Ecs.Arch.components;
|
||||
|
||||
/// <summary>
|
||||
/// 速度结构体,用于表示二维空间中实体的瞬时速度向量
|
||||
31
GFramework.Ecs.Arch/extensions/ArchExtensions.cs
Normal file
31
GFramework.Ecs.Arch/extensions/ArchExtensions.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using GFramework.Core.Abstractions.architecture;
|
||||
|
||||
namespace GFramework.Ecs.Arch.extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Arch ECS 扩展方法
|
||||
/// </summary>
|
||||
public static class ArchExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加 Arch ECS 支持到架构中
|
||||
/// </summary>
|
||||
/// <typeparam name="TArchitecture">架构类型</typeparam>
|
||||
/// <param name="architecture">架构实例</param>
|
||||
/// <param name="configure">可选的配置委托</param>
|
||||
/// <returns>架构实例,支持链式调用</returns>
|
||||
public static TArchitecture UseArch<TArchitecture>(
|
||||
this TArchitecture architecture,
|
||||
Action<ArchOptions>? configure = null)
|
||||
where TArchitecture : IArchitecture
|
||||
{
|
||||
// 配置选项
|
||||
var options = new ArchOptions();
|
||||
configure?.Invoke(options);
|
||||
|
||||
// 注册模块(传递配置选项)
|
||||
ArchitectureModuleRegistry.Register(() => new ArchEcsModule(options, enabled: true));
|
||||
|
||||
return architecture;
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
using Arch.Core;
|
||||
using GFramework.Core.ecs.components;
|
||||
using GFramework.Ecs.Arch.components;
|
||||
|
||||
namespace GFramework.Core.ecs.systems;
|
||||
namespace GFramework.Ecs.Arch.systems;
|
||||
|
||||
/// <summary>
|
||||
/// 移动系统 - 继承 ArchSystemAdapter
|
||||
@ -1,9 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TargetFrameworks>net10.0;net8.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
|
||||
@ -47,6 +47,9 @@
|
||||
<None Remove="GFramework.Godot.Abstractions\**"/>
|
||||
<None Remove="GFramework.Game.Abstractions\**"/>
|
||||
<None Remove="GFramework.Core.Tests\**"/>
|
||||
<None Remove="GFramework.Ecs.Arch.Tests\**"/>
|
||||
<None Remove="GFramework.Ecs.Arch\**"/>
|
||||
<None Remove="GFramework.Ecs.Arch.Abstractions\**"/>
|
||||
<None Remove="GFramework.Generator\**"/>
|
||||
<None Remove="GFramework.Generator.Attributes\**"/>
|
||||
<None Remove="GFramework.Godot.SourceGenerators.Attributes\**"/>
|
||||
@ -82,6 +85,9 @@
|
||||
<Compile Remove="GFramework.Godot.Abstractions\**"/>
|
||||
<Compile Remove="GFramework.Game.Abstractions\**"/>
|
||||
<Compile Remove="GFramework.Core.Tests\**"/>
|
||||
<Compile Remove="GFramework.Ecs.Arch.Tests\**"/>
|
||||
<Compile Remove="GFramework.Ecs.Arch\**"/>
|
||||
<Compile Remove="GFramework.Ecs.Arch.Abstractions\**"/>
|
||||
<Compile Remove="GFramework.Generator\**"/>
|
||||
<Compile Remove="GFramework.Generator.Attributes\**"/>
|
||||
<Compile Remove="GFramework.Godot.SourceGenerators.Attributes\**"/>
|
||||
@ -103,6 +109,9 @@
|
||||
<EmbeddedResource Remove="GFramework.Godot.Abstractions\**"/>
|
||||
<EmbeddedResource Remove="GFramework.Game.Abstractions\**"/>
|
||||
<EmbeddedResource Remove="GFramework.Core.Tests\**"/>
|
||||
<EmbeddedResource Remove="GFramework.Ecs.Arch.Tests\**"/>
|
||||
<EmbeddedResource Remove="GFramework.Ecs.Arch\**"/>
|
||||
<EmbeddedResource Remove="GFramework.Ecs.Arch.Abstractions\**"/>
|
||||
<EmbeddedResource Remove="GFramework.Generator\**"/>
|
||||
<EmbeddedResource Remove="GFramework.Generator.Attributes\**"/>
|
||||
<EmbeddedResource Remove="GFramework.Godot.SourceGenerators.Attributes\**"/>
|
||||
|
||||
155
GFramework.sln
155
GFramework.sln
@ -1,6 +1,6 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework ", "GFramework.csproj", "{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework", "GFramework.csproj", "{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.SourceGenerators", "GFramework.SourceGenerators\GFramework.SourceGenerators.csproj", "{E9D51809-0351-4B83-B85B-B5F469AAB3B8}"
|
||||
EndProject
|
||||
@ -26,63 +26,216 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Game.Abstraction
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Core.Tests", "GFramework.Core.Tests\GFramework.Core.Tests.csproj", "{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Ecs.Arch.Abstractions", "GFramework.Ecs.Arch.Abstractions\GFramework.Ecs.Arch.Abstractions.csproj", "{5E1488B2-6554-408D-83FB-EB2FFFABF545}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Ecs.Arch", "GFramework.Ecs.Arch\GFramework.Ecs.Arch.csproj", "{E9B49EE9-25BC-47C1-83CE-92F636B9D491}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GFramework.Ecs.Arch.Tests", "GFramework.Ecs.Arch.Tests\GFramework.Ecs.Arch.Tests.csproj", "{112CF413-4596-4AA3-B3FE-65532802FDD6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9BEDDD6C-DF8B-4E71-9C75-F44EC669ABBD}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E9D51809-0351-4B83-B85B-B5F469AAB3B8}.Release|x86.Build.0 = Release|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{84C5C3C9-5620-4924-BA04-92F813F2B70F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A6D5854D-79EA-487A-9ED9-396E6A1F8031}.Release|x86.Build.0 = Release|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Release|x64.Build.0 = Release|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FC56D81A-3A3B-4B49-B318-363DFA0D8206}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0B00816B-E8B2-4562-8C11-0C06CE761638}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C56FD287-CBC6-4C44-B3DF-103FA3660CA0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3A1132B7-EC3B-4BB6-A752-8ADC92BC08A0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{BB047F43-6AA0-4EA0-8AE9-E6B9784D9E8E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B6511C9A-40E1-4E51-8D1F-18EAFB3C5BFC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{31BA9F62-153A-4943-A8A0-7571FC7D5FEE}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E20DBA4C-CEB9-4184-B614-5A99A9AE4472}.Release|x86.Build.0 = Release|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Release|x64.Build.0 = Release|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{759BCD95-A9D9-4D8F-9255-A9F1B661DF74}.Release|x86.Build.0 = Release|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5E1488B2-6554-408D-83FB-EB2FFFABF545}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E9B49EE9-25BC-47C1-83CE-92F636B9D491}.Release|x86.Build.0 = Release|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{112CF413-4596-4AA3-B3FE-65532802FDD6}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@ -47,6 +47,7 @@ export default defineConfig({
|
||||
{ text: '首页', link: '/zh-CN/' },
|
||||
{ text: '入门指南', link: '/zh-CN/getting-started' },
|
||||
{ text: 'Core', link: '/zh-CN/core/' },
|
||||
{ text: 'ECS', link: '/zh-CN/ecs/' },
|
||||
{ text: 'Game', link: '/zh-CN/game/' },
|
||||
{ text: 'Godot', link: '/zh-CN/godot/' },
|
||||
{ text: '源码生成器', link: '/zh-CN/source-generators' },
|
||||
@ -91,7 +92,6 @@ export default defineConfig({
|
||||
{ text: '事件系统', link: '/zh-CN/core/events' },
|
||||
{ text: '属性系统', link: '/zh-CN/core/property' },
|
||||
{ text: 'IoC容器', link: '/zh-CN/core/ioc' },
|
||||
{ text: 'ECS 系统集成', link: '/zh-CN/core/ecs' },
|
||||
{ text: '协程系统', link: '/zh-CN/core/coroutine' },
|
||||
{ text: '状态机', link: '/zh-CN/core/state-machine' },
|
||||
{ text: '暂停系统', link: '/zh-CN/core/pause' },
|
||||
@ -110,6 +110,16 @@ export default defineConfig({
|
||||
}
|
||||
],
|
||||
|
||||
'/zh-CN/ecs/': [
|
||||
{
|
||||
text: 'ECS 系统集成',
|
||||
items: [
|
||||
{ text: 'ECS 概述', link: '/zh-CN/ecs/' },
|
||||
{ text: 'Arch ECS 集成', link: '/zh-CN/ecs/arch' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/zh-CN/game/': [
|
||||
{
|
||||
text: 'Game 游戏模块',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
751
docs/zh-CN/ecs/arch.md
Normal file
751
docs/zh-CN/ecs/arch.md
Normal file
@ -0,0 +1,751 @@
|
||||
---
|
||||
title: Arch ECS 集成
|
||||
description: GFramework 的 Arch ECS 集成包使用指南,提供高性能的实体组件系统支持。
|
||||
---
|
||||
|
||||
# Arch ECS 集成
|
||||
|
||||
## 概述
|
||||
|
||||
`GFramework.Ecs.Arch` 是 GFramework 的 Arch ECS 集成包,提供开箱即用的 ECS(Entity Component
|
||||
System)支持。基于 [Arch.Core](https://github.com/genaray/Arch) 实现,具有极致的性能和简洁的 API。
|
||||
|
||||
**主要特性**:
|
||||
|
||||
- 🎯 **显式集成** - 符合 .NET 生态习惯的显式注册方式
|
||||
- 🔌 **零依赖** - 不使用时,Core 包无 Arch 依赖
|
||||
- 🎯 **类型安全** - 完整的类型系统和编译时检查
|
||||
- ⚡ **高性能** - 基于 Arch ECS 的高性能实现
|
||||
- 🔧 **易扩展** - 简单的系统适配器模式
|
||||
- 📊 **优先级支持** - 系统按优先级顺序执行
|
||||
|
||||
**性能特点**:
|
||||
|
||||
- 10,000 个实体更新 < 100ms
|
||||
- 1,000 个实体创建 < 50ms
|
||||
- 基于 Archetype 的高效内存布局
|
||||
- 零 GC 分配的组件访问
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
dotnet add package GeWuYou.GFramework.Ecs.Arch
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 注册 ECS 模块
|
||||
|
||||
```csharp
|
||||
using GFramework.Core.architecture;
|
||||
using GFramework.Ecs.Arch.extensions;
|
||||
|
||||
public class GameArchitecture : Architecture
|
||||
{
|
||||
public GameArchitecture() : base(new ArchitectureConfiguration())
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
// 显式注册 Arch ECS 模块
|
||||
this.UseArch();
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化架构
|
||||
var architecture = new GameArchitecture();
|
||||
architecture.Initialize();
|
||||
```
|
||||
|
||||
### 2. 带配置的注册
|
||||
|
||||
```csharp
|
||||
public class GameArchitecture : Architecture
|
||||
{
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
// 带配置的注册
|
||||
this.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2000; // World 初始容量
|
||||
options.EnableStatistics = true; // 启用统计信息
|
||||
options.Priority = 50; // 模块优先级
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 定义组件
|
||||
|
||||
组件是纯数据结构,使用 `struct` 定义:
|
||||
|
||||
```csharp
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MyGame.Components;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Position(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Velocity(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Health(float current, float max)
|
||||
{
|
||||
public float Current { get; set; } = current;
|
||||
public float Max { get; set; } = max;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 创建系统
|
||||
|
||||
系统继承自 `ArchSystemAdapter<T>`:
|
||||
|
||||
```csharp
|
||||
using Arch.Core;
|
||||
using GFramework.Ecs.Arch;
|
||||
using MyGame.Components;
|
||||
|
||||
namespace MyGame.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// 移动系统 - 更新实体位置
|
||||
/// </summary>
|
||||
public sealed class MovementSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
private QueryDescription _query;
|
||||
|
||||
protected override void OnArchInitialize()
|
||||
{
|
||||
// 创建查询:查找所有同时拥有 Position 和 Velocity 组件的实体
|
||||
_query = new QueryDescription()
|
||||
.WithAll<Position, Velocity>();
|
||||
}
|
||||
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 查询并更新所有符合条件的实体
|
||||
World.Query(in _query, (ref Position pos, ref Velocity vel) =>
|
||||
{
|
||||
pos.X += vel.X * deltaTime;
|
||||
pos.Y += vel.Y * deltaTime;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 注册系统
|
||||
|
||||
```csharp
|
||||
public class GameArchitecture : Architecture
|
||||
{
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
this.UseArch();
|
||||
|
||||
// 注册 ECS 系统
|
||||
RegisterSystem<MovementSystem>();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 创建实体
|
||||
|
||||
```csharp
|
||||
using Arch.Core;
|
||||
using GFramework.Core.Abstractions.rule;
|
||||
using GFramework.SourceGenerators.Abstractions.rule;
|
||||
using MyGame.Components;
|
||||
|
||||
[ContextAware]
|
||||
public partial class GameController
|
||||
{
|
||||
public void Start()
|
||||
{
|
||||
// 获取 World
|
||||
var world = this.GetService<World>();
|
||||
|
||||
// 创建实体
|
||||
var player = world.Create(
|
||||
new Position(0, 0),
|
||||
new Velocity(0, 0),
|
||||
new Health(100, 100)
|
||||
);
|
||||
|
||||
var enemy = world.Create(
|
||||
new Position(10, 10),
|
||||
new Velocity(-1, 0),
|
||||
new Health(50, 50)
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 更新系统
|
||||
|
||||
```csharp
|
||||
using GFramework.Ecs.Arch.Abstractions;
|
||||
|
||||
public class GameLoop
|
||||
{
|
||||
private IArchEcsModule _ecsModule;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
// 获取 ECS 模块
|
||||
_ecsModule = architecture.Context.GetService<IArchEcsModule>();
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
// 更新所有 ECS 系统
|
||||
_ecsModule.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 配置选项
|
||||
|
||||
### ArchOptions
|
||||
|
||||
```csharp
|
||||
public sealed class ArchOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// World 初始容量(默认:1000)
|
||||
/// </summary>
|
||||
public int WorldCapacity { get; set; } = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用统计信息(默认:false)
|
||||
/// </summary>
|
||||
public bool EnableStatistics { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 模块优先级(默认:50)
|
||||
/// </summary>
|
||||
public int Priority { get; set; } = 50;
|
||||
}
|
||||
```
|
||||
|
||||
### 配置示例
|
||||
|
||||
```csharp
|
||||
this.UseArch(options =>
|
||||
{
|
||||
// 设置 World 初始容量
|
||||
// 根据预期实体数量设置,避免频繁扩容
|
||||
options.WorldCapacity = 2000;
|
||||
|
||||
// 启用统计信息(开发/调试时使用)
|
||||
options.EnableStatistics = true;
|
||||
|
||||
// 设置模块优先级
|
||||
// 数值越小,优先级越高
|
||||
options.Priority = 50;
|
||||
});
|
||||
```
|
||||
|
||||
## 核心概念
|
||||
|
||||
### Entity(实体)
|
||||
|
||||
实体是游戏世界中的基本对象,本质上是一个唯一标识符:
|
||||
|
||||
```csharp
|
||||
// 创建空实体
|
||||
var entity = world.Create();
|
||||
|
||||
// 创建带组件的实体
|
||||
var entity = world.Create(
|
||||
new Position(0, 0),
|
||||
new Velocity(1, 1)
|
||||
);
|
||||
|
||||
// 销毁实体
|
||||
world.Destroy(entity);
|
||||
```
|
||||
|
||||
### Component(组件)
|
||||
|
||||
组件是纯数据结构,用于存储实体的状态:
|
||||
|
||||
```csharp
|
||||
// 添加组件
|
||||
world.Add(entity, new Position(0, 0));
|
||||
|
||||
// 检查组件
|
||||
if (world.Has<Position>(entity))
|
||||
{
|
||||
// 获取组件引用(零 GC 分配)
|
||||
ref var pos = ref world.Get<Position>(entity);
|
||||
pos.X += 10;
|
||||
}
|
||||
|
||||
// 设置组件(替换现有值)
|
||||
world.Set(entity, new Position(100, 100));
|
||||
|
||||
// 移除组件
|
||||
world.Remove<Velocity>(entity);
|
||||
```
|
||||
|
||||
### System(系统)
|
||||
|
||||
系统包含游戏逻辑,处理具有特定组件组合的实体:
|
||||
|
||||
```csharp
|
||||
public sealed class DamageSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
private QueryDescription _query;
|
||||
|
||||
protected override void OnArchInitialize()
|
||||
{
|
||||
// 初始化查询
|
||||
_query = new QueryDescription()
|
||||
.WithAll<Health, Damage>();
|
||||
}
|
||||
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 处理伤害
|
||||
World.Query(in _query, (Entity entity, ref Health health, ref Damage damage) =>
|
||||
{
|
||||
health.Current -= damage.Value * deltaTime;
|
||||
|
||||
if (health.Current <= 0)
|
||||
{
|
||||
health.Current = 0;
|
||||
World.Remove<Damage>(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### World(世界)
|
||||
|
||||
World 是 ECS 的核心容器,管理所有实体和组件:
|
||||
|
||||
```csharp
|
||||
// World 由 ArchEcsModule 自动创建和注册
|
||||
var world = this.GetService<World>();
|
||||
|
||||
// 获取实体数量
|
||||
var entityCount = world.Size;
|
||||
|
||||
// 清空所有实体
|
||||
world.Clear();
|
||||
```
|
||||
|
||||
## 系统适配器
|
||||
|
||||
### ArchSystemAdapter<T>
|
||||
|
||||
`ArchSystemAdapter<T>` 桥接 Arch.System.ISystem<T> 到 GFramework 架构:
|
||||
|
||||
```csharp
|
||||
public sealed class MySystem : ArchSystemAdapter<float>
|
||||
{
|
||||
// Arch 系统初始化
|
||||
protected override void OnArchInitialize()
|
||||
{
|
||||
// 创建查询、初始化资源
|
||||
}
|
||||
|
||||
// 更新前调用
|
||||
protected override void OnBeforeUpdate(in float deltaTime)
|
||||
{
|
||||
// 预处理逻辑
|
||||
}
|
||||
|
||||
// 主更新逻辑
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 处理实体
|
||||
}
|
||||
|
||||
// 更新后调用
|
||||
protected override void OnAfterUpdate(in float deltaTime)
|
||||
{
|
||||
// 后处理逻辑
|
||||
}
|
||||
|
||||
// 资源清理
|
||||
protected override void OnArchDispose()
|
||||
{
|
||||
// 清理资源
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 访问 World
|
||||
|
||||
在系统中可以直接访问 `World` 属性:
|
||||
|
||||
```csharp
|
||||
public sealed class MySystem : ArchSystemAdapter<float>
|
||||
{
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 访问 World
|
||||
var entityCount = World.Size;
|
||||
|
||||
// 创建实体
|
||||
var entity = World.Create(new Position(0, 0));
|
||||
|
||||
// 查询实体
|
||||
var query = new QueryDescription().WithAll<Position>();
|
||||
World.Query(in query, (ref Position pos) =>
|
||||
{
|
||||
// 处理逻辑
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 访问框架服务
|
||||
|
||||
`ArchSystemAdapter<T>` 继承自 `AbstractSystem`,可以使用所有 GFramework 的扩展方法:
|
||||
|
||||
```csharp
|
||||
public sealed class ServiceAccessSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 获取 Model
|
||||
var playerModel = this.GetModel<PlayerModel>();
|
||||
|
||||
// 获取 Utility
|
||||
var timeUtility = this.GetUtility<TimeUtility>();
|
||||
|
||||
// 发送命令
|
||||
this.SendCommand(new SaveGameCommand());
|
||||
|
||||
// 发送查询
|
||||
var score = this.SendQuery(new GetScoreQuery());
|
||||
|
||||
// 发送事件
|
||||
this.SendEvent(new GameOverEvent());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 查询实体
|
||||
|
||||
### 基本查询
|
||||
|
||||
```csharp
|
||||
// 查询:必须有 Position 和 Velocity
|
||||
var query = new QueryDescription()
|
||||
.WithAll<Position, Velocity>();
|
||||
|
||||
World.Query(in query, (ref Position pos, ref Velocity vel) =>
|
||||
{
|
||||
pos.X += vel.X * deltaTime;
|
||||
pos.Y += vel.Y * deltaTime;
|
||||
});
|
||||
```
|
||||
|
||||
### 过滤查询
|
||||
|
||||
```csharp
|
||||
// 查询:必须有 Health,但不能有 Damage
|
||||
var query = new QueryDescription()
|
||||
.WithAll<Health>()
|
||||
.WithNone<Damage>();
|
||||
|
||||
World.Query(in query, (ref Health health) =>
|
||||
{
|
||||
// 只处理没有受伤的实体
|
||||
});
|
||||
```
|
||||
|
||||
### 可选组件查询
|
||||
|
||||
```csharp
|
||||
// 查询:必须有 Position,可选 Velocity
|
||||
var query = new QueryDescription()
|
||||
.WithAll<Position>()
|
||||
.WithAny<Velocity>();
|
||||
|
||||
World.Query(in query, (Entity entity, ref Position pos) =>
|
||||
{
|
||||
// 处理逻辑
|
||||
});
|
||||
```
|
||||
|
||||
### 访问实体 ID
|
||||
|
||||
```csharp
|
||||
var query = new QueryDescription().WithAll<Position>();
|
||||
|
||||
World.Query(in query, (Entity entity, ref Position pos) =>
|
||||
{
|
||||
// 可以访问实体 ID
|
||||
Console.WriteLine($"Entity {entity.Id}: ({pos.X}, {pos.Y})");
|
||||
|
||||
// 可以对实体进行操作
|
||||
if (pos.X > 100)
|
||||
{
|
||||
World.Destroy(entity);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 系统优先级
|
||||
|
||||
系统按照优先级顺序执行,数值越小优先级越高:
|
||||
|
||||
```csharp
|
||||
using GFramework.Core.Abstractions.bases;
|
||||
using GFramework.SourceGenerators.Abstractions.bases;
|
||||
|
||||
// 使用 Priority 特性设置优先级
|
||||
[Priority(10)] // 高优先级,先执行
|
||||
public sealed class InputSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
[Priority(20)] // 中优先级
|
||||
public sealed class MovementSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
[Priority(30)] // 低优先级,后执行
|
||||
public sealed class RenderSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
执行顺序:InputSystem → MovementSystem → RenderSystem
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 1. 使用 struct 组件
|
||||
|
||||
```csharp
|
||||
// ✅ 推荐:使用 struct
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Position(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
// ❌ 不推荐:使用 class
|
||||
public class Position
|
||||
{
|
||||
public float X { get; set; }
|
||||
public float Y { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 缓存查询
|
||||
|
||||
```csharp
|
||||
public class OptimizedSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
// ✅ 推荐:缓存查询
|
||||
private QueryDescription _cachedQuery;
|
||||
|
||||
protected override void OnArchInitialize()
|
||||
{
|
||||
_cachedQuery = new QueryDescription()
|
||||
.WithAll<Position, Velocity>();
|
||||
}
|
||||
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
World.Query(in _cachedQuery, (ref Position pos, ref Velocity vel) =>
|
||||
{
|
||||
pos.X += vel.X * deltaTime;
|
||||
pos.Y += vel.Y * deltaTime;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 使用 ref 访问组件
|
||||
|
||||
```csharp
|
||||
// ✅ 推荐:使用 ref 避免复制
|
||||
World.Query(in query, (ref Position pos, ref Velocity vel) =>
|
||||
{
|
||||
pos.X += vel.X; // 直接修改,零 GC
|
||||
});
|
||||
|
||||
// ❌ 不推荐:不使用 ref
|
||||
World.Query(in query, (Position pos, Velocity vel) =>
|
||||
{
|
||||
pos.X += vel.X; // 复制值,修改不会生效
|
||||
});
|
||||
```
|
||||
|
||||
### 4. 组件大小优化
|
||||
|
||||
```csharp
|
||||
// ✅ 推荐:小而专注的组件
|
||||
public struct Position(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
public struct Velocity(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
// ❌ 不推荐:大而全的组件
|
||||
public struct Transform
|
||||
{
|
||||
public float X, Y, Z;
|
||||
public float RotationX, RotationY, RotationZ;
|
||||
public float ScaleX, ScaleY, ScaleZ;
|
||||
public float VelocityX, VelocityY, VelocityZ;
|
||||
// ... 太多数据
|
||||
}
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 组件设计原则
|
||||
|
||||
- 使用 `struct` 而不是 `class`
|
||||
- 只包含数据,不包含逻辑
|
||||
- 使用 `[StructLayout(LayoutKind.Sequential)]` 优化内存布局
|
||||
- 保持组件小而专注
|
||||
|
||||
### 2. 系统设计原则
|
||||
|
||||
- 单一职责:每个系统只负责一件事
|
||||
- 缓存查询:在 `OnArchInitialize` 中创建查询
|
||||
- 使用 ref:访问组件时使用 ref 参数
|
||||
- 批量处理:一次查询处理所有实体
|
||||
|
||||
### 3. 标签组件
|
||||
|
||||
使用空结构体作为标签来分类实体:
|
||||
|
||||
```csharp
|
||||
// 定义标签组件
|
||||
public struct PlayerTag { }
|
||||
public struct EnemyTag { }
|
||||
public struct DeadTag { }
|
||||
|
||||
// 使用标签过滤实体
|
||||
var query = new QueryDescription()
|
||||
.WithAll<Position, Velocity, PlayerTag>()
|
||||
.WithNone<DeadTag>();
|
||||
```
|
||||
|
||||
### 4. 与传统架构结合
|
||||
|
||||
```csharp
|
||||
// ECS 系统可以访问 Model
|
||||
public class EnemySpawnSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
var gameState = this.GetModel<GameStateModel>();
|
||||
|
||||
// 根据关卡生成敌人
|
||||
for (int i = 0; i < gameState.Level; i++)
|
||||
{
|
||||
World.Create(
|
||||
new Position(Random.Shared.Next(0, 100), 0),
|
||||
new Velocity(0, -1),
|
||||
new Health(50, 50)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 如何在运行时动态添加/移除组件?
|
||||
|
||||
A: Arch 支持运行时修改实体的组件:
|
||||
|
||||
```csharp
|
||||
// 动态添加组件
|
||||
if (pos.X > 100 && !World.Has<FastTag>(entity))
|
||||
{
|
||||
World.Add(entity, new FastTag());
|
||||
}
|
||||
|
||||
// 动态移除组件
|
||||
if (pos.X < 0 && World.Has<FastTag>(entity))
|
||||
{
|
||||
World.Remove<FastTag>(entity);
|
||||
}
|
||||
```
|
||||
|
||||
### Q: 如何处理实体之间的交互?
|
||||
|
||||
A: 使用嵌套查询或事件:
|
||||
|
||||
```csharp
|
||||
// 方式 1:嵌套查询
|
||||
World.Query(in playerQuery, (Entity player, ref Position playerPos) =>
|
||||
{
|
||||
World.Query(in enemyQuery, (Entity enemy, ref Position enemyPos) =>
|
||||
{
|
||||
// 检测碰撞
|
||||
});
|
||||
});
|
||||
|
||||
// 方式 2:使用事件
|
||||
this.SendEvent(new CollisionEvent
|
||||
{
|
||||
Entity1 = player,
|
||||
Entity2 = enemy
|
||||
});
|
||||
```
|
||||
|
||||
### Q: 如何调试 ECS 系统?
|
||||
|
||||
A: 使用日志和统计信息:
|
||||
|
||||
```csharp
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 打印实体数量
|
||||
Console.WriteLine($"Total entities: {World.Size}");
|
||||
|
||||
// 查询特定实体
|
||||
var query = new QueryDescription().WithAll<Position>();
|
||||
var count = 0;
|
||||
World.Query(in query, (Entity entity, ref Position pos) =>
|
||||
{
|
||||
count++;
|
||||
Console.WriteLine($"Entity {entity.Id}: ({pos.X}, {pos.Y})");
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [Arch.Core 官方文档](https://github.com/genaray/Arch)
|
||||
- [ECS 概述](./index.md)
|
||||
- [ECS 最佳实践](./best-practices.md)
|
||||
- [性能优化指南](./performance.md)
|
||||
|
||||
---
|
||||
|
||||
**许可证**:MIT License
|
||||
297
docs/zh-CN/ecs/index.md
Normal file
297
docs/zh-CN/ecs/index.md
Normal file
@ -0,0 +1,297 @@
|
||||
---
|
||||
title: ECS 系统集成
|
||||
description: GFramework 的 ECS(Entity Component System)集成方案,支持多种 ECS 框架。
|
||||
---
|
||||
|
||||
# ECS 系统集成
|
||||
|
||||
## 概述
|
||||
|
||||
GFramework 提供了灵活的 ECS(Entity Component System)集成方案,允许你根据项目需求选择合适的 ECS 框架。ECS
|
||||
是一种数据驱动的架构模式,特别适合处理大量相似实体的场景。
|
||||
|
||||
## 什么是 ECS?
|
||||
|
||||
ECS(Entity Component System)是一种架构模式,将游戏对象分解为三个核心概念:
|
||||
|
||||
- **Entity(实体)**:游戏世界中的基本对象,本质上是一个唯一标识符
|
||||
- **Component(组件)**:纯数据结构,存储实体的状态
|
||||
- **System(系统)**:包含游戏逻辑,处理具有特定组件组合的实体
|
||||
|
||||
### ECS 的优势
|
||||
|
||||
- **高性能**:数据局部性好,缓存友好
|
||||
- **可扩展**:通过组合组件轻松创建新实体类型
|
||||
- **并行处理**:系统之间相互独立,易于并行化
|
||||
- **数据驱动**:逻辑与数据分离,便于序列化和网络同步
|
||||
|
||||
### 何时使用 ECS?
|
||||
|
||||
**适合使用 ECS 的场景**:
|
||||
|
||||
- 大量相似实体(敌人、子弹、粒子)
|
||||
- 需要高性能批量处理
|
||||
- 复杂的实体组合和变化
|
||||
- 需要并行处理的系统
|
||||
|
||||
**不适合使用 ECS 的场景**:
|
||||
|
||||
- 全局状态管理
|
||||
- 单例服务
|
||||
- UI 逻辑
|
||||
- 游戏流程控制
|
||||
|
||||
## 支持的 ECS 框架
|
||||
|
||||
GFramework 采用可选集成的设计,你可以根据需求选择合适的 ECS 框架:
|
||||
|
||||
### Arch ECS(推荐)
|
||||
|
||||
[Arch](https://github.com/genaray/Arch) 是一个高性能的 C# ECS 框架,具有以下特点:
|
||||
|
||||
- ✅ **极致性能**:基于 Archetype 的内存布局,零 GC 分配
|
||||
- ✅ **简单易用**:清晰的 API,易于上手
|
||||
- ✅ **功能完整**:支持查询、过滤、并行处理等高级特性
|
||||
- ✅ **活跃维护**:社区活跃,持续更新
|
||||
|
||||
**安装方式**:
|
||||
|
||||
```bash
|
||||
dotnet add package GeWuYou.GFramework.Ecs.Arch
|
||||
```
|
||||
|
||||
**文档链接**:[Arch ECS 集成指南](./arch.md)
|
||||
|
||||
### 其他 ECS 框架
|
||||
|
||||
GFramework 的设计允许集成其他 ECS 框架,未来可能支持:
|
||||
|
||||
- **DefaultEcs**:轻量级 ECS 框架
|
||||
- **Entitas**:成熟的 ECS 框架,Unity 生态常用
|
||||
- **自定义 ECS**:你可以基于 GFramework 的模块系统实现自己的 ECS 集成
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 选择 ECS 框架
|
||||
|
||||
根据项目需求选择合适的 ECS 框架。对于大多数项目,我们推荐使用 Arch ECS。
|
||||
|
||||
### 2. 安装集成包
|
||||
|
||||
```bash
|
||||
# 安装 Arch ECS 集成包
|
||||
dotnet add package GeWuYou.GFramework.Ecs.Arch
|
||||
```
|
||||
|
||||
### 3. 注册 ECS 模块
|
||||
|
||||
```csharp
|
||||
using GFramework.Core.architecture;
|
||||
using GFramework.Ecs.Arc;
|
||||
|
||||
public class GameArchitecture : Architecture
|
||||
{
|
||||
public GameArchitecture() : base(new ArchitectureConfiguration())
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
// 显式注册 Arch ECS 模块
|
||||
this.UseArch(options =>
|
||||
{
|
||||
options.WorldCapacity = 2000;
|
||||
options.EnableStatistics = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 定义组件
|
||||
|
||||
```csharp
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Position(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Velocity(float x, float y)
|
||||
{
|
||||
public float X { get; set; } = x;
|
||||
public float Y { get; set; } = y;
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 创建系统
|
||||
|
||||
```csharp
|
||||
using Arch.Core;
|
||||
using GFramework.Ecs.Arch;
|
||||
|
||||
public sealed class MovementSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
private QueryDescription _query;
|
||||
|
||||
protected override void OnArchInitialize()
|
||||
{
|
||||
_query = new QueryDescription()
|
||||
.WithAll<Position, Velocity>();
|
||||
}
|
||||
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
World.Query(in _query, (ref Position pos, ref Velocity vel) =>
|
||||
{
|
||||
pos.X += vel.X * deltaTime;
|
||||
pos.Y += vel.Y * deltaTime;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 注册系统
|
||||
|
||||
```csharp
|
||||
public class GameArchitecture : Architecture
|
||||
{
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
this.UseArch();
|
||||
|
||||
// 注册 ECS 系统
|
||||
RegisterSystem<MovementSystem>();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 设计理念
|
||||
|
||||
### 显式集成
|
||||
|
||||
GFramework 采用显式集成的设计,而不是自动注册:
|
||||
|
||||
```csharp
|
||||
// ✅ 显式注册 - 清晰、可控
|
||||
public class GameArchitecture : Architecture
|
||||
{
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
this.UseArch(); // 明确表示使用 Arch ECS
|
||||
}
|
||||
}
|
||||
|
||||
// ❌ 自动注册 - 隐式、难以控制
|
||||
// 只需引入包,自动注册(不推荐)
|
||||
```
|
||||
|
||||
**优势**:
|
||||
|
||||
- 清晰的依赖关系
|
||||
- 更好的 IDE 支持
|
||||
- 易于测试和调试
|
||||
- 符合 .NET 生态习惯
|
||||
|
||||
### 零依赖原则
|
||||
|
||||
如果你不使用 ECS,GFramework.Core 包不会引入任何 ECS 相关的依赖:
|
||||
|
||||
```xml
|
||||
<!-- GFramework.Core.csproj -->
|
||||
<ItemGroup>
|
||||
<!-- 无 Arch 依赖 -->
|
||||
</ItemGroup>
|
||||
|
||||
<!-- GFramework.Ecs.Arch.csproj -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Arch" Version="2.1.0" />
|
||||
<PackageReference Include="Arch.System" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
```
|
||||
|
||||
### 模块化设计
|
||||
|
||||
ECS 集成基于 GFramework 的模块系统:
|
||||
|
||||
```csharp
|
||||
// ECS 模块实现 IServiceModule 接口
|
||||
public sealed class ArchEcsModule : IArchEcsModule
|
||||
{
|
||||
public string ModuleName => nameof(ArchEcsModule);
|
||||
public int Priority => 50;
|
||||
public bool IsEnabled { get; }
|
||||
|
||||
public void Register(IIocContainer container) { }
|
||||
public void Initialize() { }
|
||||
public ValueTask DestroyAsync() { }
|
||||
public void Update(float deltaTime) { }
|
||||
}
|
||||
```
|
||||
|
||||
## 与传统架构结合
|
||||
|
||||
ECS 可以与 GFramework 的传统架构(Model、System、Utility)无缝结合:
|
||||
|
||||
```csharp
|
||||
// Model 存储全局状态
|
||||
public class GameStateModel : AbstractModel
|
||||
{
|
||||
public int Score { get; set; }
|
||||
public int Level { get; set; }
|
||||
}
|
||||
|
||||
// ECS System 处理实体逻辑
|
||||
public class EnemySpawnSystem : ArchSystemAdapter<float>
|
||||
{
|
||||
protected override void OnUpdate(in float deltaTime)
|
||||
{
|
||||
// 访问 Model
|
||||
var gameState = this.GetModel<GameStateModel>();
|
||||
|
||||
// 根据关卡生成敌人
|
||||
for (int i = 0; i < gameState.Level; i++)
|
||||
{
|
||||
World.Create(
|
||||
new Position(Random.Shared.Next(0, 100), 0),
|
||||
new Velocity(0, -1),
|
||||
new Health(50, 50)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 传统 System 处理游戏逻辑
|
||||
public class ScoreSystem : AbstractSystem
|
||||
{
|
||||
protected override void OnInit()
|
||||
{
|
||||
this.RegisterEvent<EnemyDestroyedEvent>(OnEnemyDestroyed);
|
||||
}
|
||||
|
||||
private void OnEnemyDestroyed(EnemyDestroyedEvent e)
|
||||
{
|
||||
var gameState = this.GetModel<GameStateModel>();
|
||||
gameState.Score += 100;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 下一步
|
||||
|
||||
- [Arch ECS 集成指南](./arch.md) - 详细的 Arch ECS 使用文档
|
||||
- [ECS 最佳实践](./best-practices.md) - ECS 设计模式和优化技巧
|
||||
- [性能优化](./performance.md) - ECS 性能优化指南
|
||||
|
||||
## 相关资源
|
||||
|
||||
- [Architecture 架构系统](../core/architecture.md)
|
||||
- [System 系统](../core/system.md)
|
||||
- [事件系统](../core/events.md)
|
||||
|
||||
---
|
||||
|
||||
**许可证**:MIT License
|
||||
Loading…
x
Reference in New Issue
Block a user