Merge branch 'main' into dev

This commit is contained in:
Mikhail 2024-08-07 12:14:17 +08:00
commit b893291090
3 changed files with 56 additions and 57 deletions

View File

@ -308,7 +308,7 @@ EcsPipeline pipeline = EcsPipeline.New()
Для добавления нового процесса создайте интерфейс наследованный от `IEcsProcess` и создайте раннер для него. Раннер это класс реализующий интерфейс запускаемого процесса и наследуемый от `EcsRunner<TInterface>`. Пример:
``` c#
// Интерфейс.
// Интерфейс процесса.
interface IDoSomethingProcess : IEcsProcess
{
void Do();
@ -448,7 +448,6 @@ class Aspect : EcsAspect
public OtherAspect2 otherAspect2;
public EcsPool<Pose> poses;
// Функция Init аналогична конструктору Aspect(Builder b).
protected override void Init(Builder b)
{
// Комбинирует с SomeAspect1.

View File

@ -65,7 +65,7 @@ DragonECS 是一个[实体组件系统](https://www.imooc.com/article/331544)框
- [方面](#方面)
- [查询](#查询)
- [集合](#集合)
- [根本](#根本)
- [ECS入口](#ECS入口)
- [Debug](#debug)
- [元属性](#元属性)
- [EcsDebug](#ecsdebug)
@ -308,12 +308,12 @@ EcsPipeline pipeline = EcsPipeline.New()
Для добавления нового процесса создайте интерфейс наследованный от `IEcsProcess` и создайте раннер для него. Раннер это класс реализующий интерфейс запускаемого процесса и наследуемый от `EcsRunner<TInterface>`. Пример:
``` c#
//Интерфейс.
// 流程接口。
interface IDoSomethingProcess : IEcsProcess
{
void Do();
}
//Реализация раннера. Пример реализации можно так же посмотреть в встроенных процессах
// 启动器实现. 也可以在内置的流程中参考实现示例。
sealed class DoSomethingProcessRunner : EcsRunner<IDoSomethingProcess>, IDoSomethingProcess
{
public void Do()
@ -323,25 +323,25 @@ sealed class DoSomethingProcessRunner : EcsRunner<IDoSomethingProcess>, IDoSomet
}
//...
//Добавление раннера при создании пайплайна.
// 添加启动器到管线
_pipeline = EcsPipeline.New()
//...
.AddRunner<DoSomethingProcessRunner>()
//...
.BuildAndInit();
//Запуск раннера если раннер был добавлен.
// 如果启动器已经添加,运行它。
_pipeline.GetRunner<IDoSomethingProcess>.Do()
//Или если раннер не был добавлен(Вызов GetRunnerInstance так же добавит раннер в пайплайн).
// 如果启动器尚未添加,使用 GetRunnerInstance 将其添加并运行
_pipeline.GetRunnerInstance<DoSomethingProcessRunner>.Do()
```
> Раннеры имеют ряд требований к реализации:
> * Наследоваться от `EcsRunner<T>` можно только напрямую;
> * Раннер может содержать только один интерфейс(за исключением `IEcsProcess`);
> * Наследуемый класс `EcsRunner<T>,` должен так же реализовать интерфейс `T`;
> 启动器的实现有一些要求:
> * 必须直接继承自 `EcsRunner<T>`
> * 启动器只能包含一个接口(除了 `IEcsProcess` 接口);
> * 继承的 `EcsRunner<T>,` 类必须实现接口 `T`
> Не рекомендуется в цикле вызывать `GetRunner`, иначе кешируйте полученный раннер.
不建议在循环中频繁调用 `GetRunner` 方法,建议缓存获取的启动器实例。
</details>
## 世界
@ -438,7 +438,7 @@ class Aspect : EcsAspect
<details>
<summary>结合方面</summary>
В аспекты можно добавлять другие аспекты, тем самым комбинируя их. Ограничения так же будут скомбинированы.
可以把一个方面加入另一个方面,从而组合它们。限制也会被组合
``` c#
using DCFApixels.DragonECS;
...
@ -448,25 +448,24 @@ class Aspect : EcsAspect
public OtherAspect2 otherAspect2;
public EcsPool<Pose> poses;
// функция Init аналогична конструктору Aspect(Builder b)
protected override void Init(Builder b)
{
// комбинирует с SomeAspect1.
// 与 SomeAspect1 进行组合。
otherAspect1 = b.Combine<OtherAspect1>(1);
// хотя для OtherAspect1 метод Combine был вызван раньше, сначала будет скомбинирован с OtherAspect2, так как по умолчанию order = 0.
// 即使对 OtherAspect1 调用 Combine 方法更早Aspect 会首先与 OtherAspect2 进行组合,因为默认情况下 order = 0。
otherAspect2 = b.Combine<OtherAspect2>();
// если в OtherAspect1 или в OtherAspect2 было ограничение b.Exclude<Pose>() тут оно будет заменено на b.Include<Pose>().
// 如果 OtherAspect1 或 OtherAspect2 中有 b.Exclude<Pose>() 的限制条件,这里将被替换为 b.Include<Pose>()。
poses = b.Include<Pose>();
}
}
```
Если будут конфликтующие ограничения у комбинируемых аспектов, то новые ограничения будут заменять добавленные ранее. Ограничения корневого аспекта всегда заменяют ограничения из добавленных аспектов. Визуальный пример комбинации ограничений:
如果组合的方面存在冲突的限制条件,则新的限制条件将替换先前添加的限制条件。根方面的限制条件始终会替换添加的方面中的限制条件。限制条件组合的视觉示例:
| | cmp1 | cmp2 | cmp3 | cmp4 | cmp5 | разрешение конфликтных ограничений|
| :--- | :--- | :--- | :--- | :--- | :--- |:--- |
| OtherAspect2 | :heavy_check_mark: | :x: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_check_mark: | |
| OtherAspect1 | :heavy_minus_sign: | :heavy_check_mark: | :heavy_minus_sign: | :x: | :heavy_minus_sign: | Для `cmp2` будет выбрано :heavy_check_mark: |
| Aspect | :x: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_check_mark: | Для `cmp1` будет выбрано :x: |
| Итоговые ограничения | :x: | :heavy_check_mark: | :heavy_minus_sign: | :x: | :heavy_check_mark: | |
| OtherAspect1 | :heavy_minus_sign: | :heavy_check_mark: | :heavy_minus_sign: | :x: | :heavy_minus_sign: | 对于 `cmp2` 将选择 :heavy_check_mark: |
| Aspect | :x: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_check_mark: | 对于 `cmp1` 将选择 :x: |
| 最终的限制 | :x: | :heavy_check_mark: | :heavy_minus_sign: | :x: | :heavy_check_mark: | |
</details>
@ -571,9 +570,9 @@ groupA.Inverse();
EcsGroup newGroup = EcsGroup.Inverse(groupA);
```
## 根本
## ECS入口
这是一个用户定义的类,作为 ECS 的入口点。其主要目的是初始化和启动每个 Update 引擎上的系统,并在使用结束后释放资源。
### Пример для Unity
### Unity示例
``` c#
using DCFApixels.DragonECS;
using UnityEngine;
@ -619,7 +618,7 @@ public class EcsRoot : MonoBehaviour
}
}
```
### Общий пример
### 公用示例
``` c#
using DCFApixels.DragonECS;
public class EcsRoot

View File

@ -311,14 +311,14 @@ Processes are queues of systems that implement a common interface, such as `IEcs
<details>
<summary>Custom Processes</summary>
Для добавления нового процесса создайте интерфейс наследованный от `IEcsProcess` и создайте раннер для него. Раннер это класс реализующий интерфейс запускаемого процесса и наследуемый от `EcsRunner<TInterface>`. Пример:
To add a new process, create an interface inherited from `IEcsProcess` and create a runner for it. A runner is a class that implements the interface of the process to be run and inherits from `EcsRunner<TInterface>`. Example:
``` c#
// Интерфейс.
// Process interface.
interface IDoSomethingProcess : IEcsProcess
{
void Do();
}
// Реализация раннера. Пример реализации можно так же посмотреть в встроенных процессах
// Implementation of a runner. An example of implementation can also be seen in built-in processes.
sealed class DoSomethingProcessRunner : EcsRunner<IDoSomethingProcess>, IDoSomethingProcess
{
public void Do()
@ -328,25 +328,25 @@ sealed class DoSomethingProcessRunner : EcsRunner<IDoSomethingProcess>, IDoSomet
}
// ...
// Добавление раннера при создании пайплайна.
// Adding the runner when creating the pipeline
_pipeline = EcsPipeline.New()
//...
.AddRunner<DoSomethingProcessRunner>()
//...
.BuildAndInit();
// Запуск раннера если раннер был добавлен.
// Running the runner if it was added
_pipeline.GetRunner<IDoSomethingProcess>.Do()
// or если раннер не был добавлен(Вызов GetRunnerInstance так же добавит раннер в пайплайн).
// or if the runner was not added (calling GetRunnerInstance will also add the runner to the pipeline).
_pipeline.GetRunnerInstance<DoSomethingProcessRunner>.Do()
```
> Раннеры имеют ряд требований к реализации:
> * Наследоваться от `EcsRunner<T>` можно только напрямую;
> * Раннер может содержать только один интерфейс(за исключением `IEcsProcess`);
> * Наследуемый класс `EcsRunner<T>,` должен так же реализовать интерфейс `T`;
> Runners have several implementation requirements:
> * Inheritance from `EcsRunner<T>` must be direct.
> * Runner can only contain one interface (except `IEcsProcess`);
> * The inheriting class of `EcsRunner<T>,` must also implement the `T` interface;
> Не рекомендуется в цикле вызывать `GetRunner`, иначе кешируйте полученный раннер.
> It's not recommended to call `GetRunner` in a loop; instead, cache the retrieved runner instance.
</details>
## World
@ -401,7 +401,7 @@ poses.Del(entityID);
> It is possible to implement a user pool. This feature will be described shortly.
## Аспект
## Aspect
These are custom classes inherited from `EcsAspect` and used to interact with entities. Aspects are both a pool cache and a component mask for filtering entities. You can think of aspects as a description of what entities the system is working with.
Simplified syntax:
@ -443,7 +443,7 @@ class Aspect : EcsAspect
<details>
<summary>Combining aspects</summary>
В аспекты можно добавлять другие аспекты, тем самым комбинируя их. Ограничения так же будут скомбинированы.
Aspects can have additional aspects added to them, thus combining them. The constraints will also be combined accordingly.
``` c#
using DCFApixels.DragonECS;
// ...
@ -453,25 +453,24 @@ class Aspect : EcsAspect
public OtherAspect2 otherAspect2;
public EcsPool<Pose> poses;
// Функция Init аналогична конструктору Aspect(Builder b).
protected override void Init(Builder b)
{
// Комбинирует с SomeAspect1.
// Combines with SomeAspect1.
otherAspect1 = b.Combine<OtherAspect1>(1);
// Хотя для OtherAspect1 метод Combine был вызван раньше, сначала будет скомбинирован с OtherAspect2, так как по умолчанию order = 0.
// Although Combine was called earlier for OtherAspect1, it will first combine with OtherAspect2 because the default order is 0.
otherAspect2 = b.Combine<OtherAspect2>();
// Если в OtherAspect1 или в OtherAspect2 было ограничение b.Exclude<Pose>() тут оно будет заменено на b.Include<Pose>().
// If b.Exclude<Pose>() was specified in OtherAspect1 or OtherAspect2, it will be replaced with b.Include<Pose>() here.
poses = b.Include<Pose>();
}
}
```
Если будут конфликтующие ограничения у комбинируемых аспектов, то новые ограничения будут заменять добавленные ранее. Ограничения корневого аспекта всегда заменяют ограничения из добавленных аспектов. Визуальный пример комбинации ограничений:
If there are conflicting constraints between the combined aspects, the new constraints will replace those added earlier. Constraints from the root aspect always replace constraints from added aspects. Here's a visual example of constraint combination:
| | cmp1 | cmp2 | cmp3 | cmp4 | cmp5 | разрешение конфликтных ограничений|
| :--- | :--- | :--- | :--- | :--- | :--- |:--- |
| OtherAspect2 | :heavy_check_mark: | :x: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_check_mark: | |
| OtherAspect1 | :heavy_minus_sign: | :heavy_check_mark: | :heavy_minus_sign: | :x: | :heavy_minus_sign: | Для `cmp2` будет выбрано :heavy_check_mark: |
| Aspect | :x: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_check_mark: | Для `cmp1` будет выбрано :x: |
| Итоговые ограничения | :x: | :heavy_check_mark: | :heavy_minus_sign: | :x: | :heavy_check_mark: | |
| OtherAspect1 | :heavy_minus_sign: | :heavy_check_mark: | :heavy_minus_sign: | :x: | :heavy_minus_sign: | For `cmp2` will be chosen. :heavy_check_mark: |
| Aspect | :x: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_check_mark: | For `cmp1` will be chosen. :x: |
| Final Constraints | :x: | :heavy_check_mark: | :heavy_minus_sign: | :x: | :heavy_check_mark: | |
</details>
@ -793,40 +792,42 @@ var _someDataB = _pipeline.Configs.Get<SomeDataB>();
```
## World Components
С помощью компонентов можно прикреплять дополнительные данные к мирам. В качестве компонентов используются `struct` типы. Доступ к компонентам через `Get` оптимизирован, скорость почти такая же как доступ к полям класса.
Components can be used to attach additional data to worlds. World components are `struct` types. Access to components via `Get` is optimized, the speed is almost the same as access to class fields.
Get component:
``` c#
// Получить компонент.
ref WorldComponent component = ref _world.Get<WorldComponent>();
```
Реализация компонента:
Component Implementation:
``` c#
public struct WorldComponent
{
// Данные.
// Data.
}
```
Или:
Or:
``` c#
public struct WorldComponent : IEcsWorldComponent<WorldComponent>
{
// Данные.
// Data.
void IEcsWorldComponent<WorldComponent>.Init(ref WorldComponent component, EcsWorld world)
{
// Действия при инициализации компонента. Вызывается до первого возвращения из EcsWorld.Get .
// Actions during component initialization. Called before the first return from EcsWorld.Get().
}
void IEcsWorldComponent<WorldComponent>.OnDestroy(ref WorldComponent component, EcsWorld world)
{
// Действия когда вызывается EcsWorld.Destroy.
// Вызов OnDestroy, обязует пользователя вручную обнулять компонент, если это необходимо.
// Actions when EcsWorld.Destroy is called.
// Calling OnDestroy, obliges the user to manually reset the component if necessary.
component = default;
}
}
```
<details>
<summary>Пример использования</summary>
<summary>Example of use</summary>
События интерфейса IEcsWorldComponent<T>, могут быть использованы для автоматической инициализации полей компонента, и освобождения ресурсов.
IEcsWorldComponent<T> interface events, can be used to automatically initialize component fields, and release resources.
``` c#
public struct WorldComponent : IEcsWorldComponent<WorldComponent>
{