Skip to content

Commit 569f569

Browse files
committed
Update: README
1 parent 01a4004 commit 569f569

6 files changed

Lines changed: 583 additions & 1 deletion

File tree

README.md

Lines changed: 292 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,293 @@
11
# Arch.Unity
2-
Arch ECS integration for Unity.
2+
3+
[日本語版READMEはこちら](README_JA.md)
4+
5+
Arch.Unity is a library that provides functionality to integrate [Arch](https://github.com/genaray/Arch), an ECS framework for C#, with Unity.
6+
7+
## Why not Unity ECS?
8+
9+
Unity provides an extremely fast ECS framework integrated into the Unity Editor through the Entities package. Additionally, there are packages available for physics and rendering functionalities that are compatible with Entities.
10+
11+
However, Entities is somewhat feature-heavy as an ECS framework, and adopting it requires significant restructuring of the project. Furthermore, at the current stage, Unity ECS lacks support for many packages, necessitating a "Hybrid ECS" approach where GameObjects are still used alongside Entities in many cases. To be frank, for small to medium-sized projects where optimization is not a top priority (especially 2D projects where Unity ECS functionalities are lacking), there is little advantage in adopting Unity ECS.
12+
13+
Nevertheless, there are benefits to adopting ECS itself. Unity's Update function is generally slower than regular method calls, leading many developers to create their own "UpdateManager" for optimization. Additionally, the decrease in readability due to mixing data and processing within a single Component is also a concern. These issues can be resolved by placing data on Entities and separating methods into Systems.
14+
15+
Arch is an ECS framework for C# that offers sufficient speed and allows the use of reference types as Components (with some performance overhead). Furthermore, the core of Arch is minimal and refined, making it easy to integrate with Unity. Arch.Unity adds several features and layers to facilitate smooth integration between Arch ECS and Unity.
16+
17+
## Setup
18+
19+
### Requirements
20+
21+
* Unity 2022.2 or later
22+
* Burst 1.6.0 or later
23+
* Collections 2.0.0 or later
24+
* Arch 1.0.0 or later
25+
* Arch.System 1.0.0 or later
26+
27+
### Installation
28+
29+
1. Use [Nuget For Unity](https://github.com/GlitchEnzo/NuGetForUnity) to install Arch and Arch.System.
30+
31+
![img](docs/images/img-nuget-for-unity.png)
32+
33+
2. Open the Package Manager from Window > Package Manager.
34+
3. Click the "+" button > Add package from git URL.
35+
4. Enter the following URL:
36+
37+
```
38+
https://github.com/AnnulusGames/Arch.Unitygit?path=src/Arch.Unity/Assets/Arch.Unity
39+
```
40+
41+
## Package Structure
42+
43+
| Namespace | Description |
44+
| - | - |
45+
| Arch.Unity.Conversion | Provides functionality to convert GameObjects to Entities. |
46+
| Arch.Unity.Editor | Editor extensions such as displaying Entities in the Hierarchy and Inspector. |
47+
| Arch.Unity.Jobs | Integration between Arch queries and Unity's C# Job System. |
48+
| Arch.Unity.Toolkit | Provides custom functionalities to integrate Arch.System with Unity. |
49+
50+
## Conversion Workflow
51+
52+
To create Entities from GameObjects, the `EntityConverter` component is provided. This allows for interoperation between GameObjects and Entities, including converting GameObjects to Entities, adding Components from GameObjects to Entities, and more.
53+
54+
![img](docs/images/img-entity-converter-inspector.png)
55+
56+
### Conversion Mode
57+
58+
There are two modes of conversion:
59+
60+
| Conversion Mode | Description |
61+
| - | - |
62+
| Convert And Destroy | GameObjects are destroyed upon conversion. This is used when using `IComponentConverter` (explained below). |
63+
| Sync With Entity | Generates a single Entity per GameObject and associates it with the GameObject. The Entity is automatically destroyed when the GameObject is destroyed. Checking Convert Hybrid Components allows adding Components directly from the GameObject to the Entity. |
64+
65+
### EntityConversion.DefaultWorld
66+
67+
Entities created by `EntityConverter` are added to the `EntityConversion.DefaultWorld` World. `EntityConversion.DefaultWorld` is automatically created at startup and is automatically disposed of in sync with the application.
68+
69+
### Component Converter
70+
71+
MonoBehaviours that implement `IComponentConverter` are considered converters and perform custom processing during conversion. (If `IComponentConverter` is not implemented, it is treated as a Hybrid Component.)
72+
73+
Here's a sample implementation of `IComponentConverter`:
74+
75+
```cs
76+
using UnityEngine;
77+
using Arch.Unity.Conversion;
78+
79+
public class ExampleConverter : MonoBehaviour, IComponentConverter
80+
{
81+
[SerializeField] float value;
82+
83+
public void Convert(IEntityConverter converter)
84+
{
85+
converter.AddComponent(new ExampleComponent()
86+
{
87+
Value = value
88+
});
89+
}
90+
}
91+
92+
public struct ExampleComponent
93+
{
94+
public float Value;
95+
}
96+
```
97+
98+
### GameObjectReference
99+
100+
In Sync With Entity conversion mode, the generated Entity will have a `GameObjectReference` component added. This component allows retrieving the synchronized GameObject.
101+
102+
### Performance Considerations
103+
104+
Unlike Unity's Subscene, `EntityConverter` performs conversion to Entities at runtime. Therefore, it is recommended to avoid using it as much as possible in performance-critical scenarios or when synchronization with GameObjects is not necessary.
105+
106+
## Integration with C# Job System
107+
108+
Arch uses its own JobScheduler for parallel processing, but Unity offers a safer and faster C# Job System. By implementing a custom Job interface in Arch.Unity, Arch queries can be safely processed in parallel with the Job System.
109+
110+
These Jobs are also compatible with Burst Compiler. Applying Burst allows for extremely fast enumeration.
111+
112+
### IJobArchChunk
113+
114+
`IJobArchChunk` is an interface for creating Jobs that process chunks. To create a Job, first define a struct that implements this interface.
115+
116+
```cs
117+
using Unity.Burst;
118+
using Arch.Unity.Jobs;
119+
120+
[BurstCompile]
121+
public struct ExampleJob : IJobArchChunk
122+
{
123+
public int ComponentId;
124+
125+
public void Execute(NativeChunk chunk)
126+
{
127+
var array = chunk.GetNativeArray<ExampleComponent>(ComponentId);
128+
for (int i = 0; i < array.Length; i++)
129+
{
130+
var test = array[i];
131+
test.Value++;
132+
array[i] = test;
133+
}
134+
}
135+
}
136+
137+
public struct ExampleComponent
138+
{
139+
public float Value;
140+
}
141+
```
142+
143+
You can obtain a NativeArray pointing to the Component's data by calling `GetNativeArray<T>(int id)` on `NativeChunk`. However, you need to pass the Component's specific Id to the Job beforehand. This can be obtained from `Arch.Core.Utils.Component<T>.ComponentType.Id`, for example.
144+
145+
```cs
146+
var world = World.Create();
147+
var query = new QueryDescription().WithAll<ExampleComponent>();
148+
149+
var job = new ExampleJob()
150+
{
151+
ComponentId = Component<ExampleComponent>.ComponentType.Id
152+
};
153+
job.ScheduleParallel(world, query).Complete();
154+
```
155+
156+
### Limitations
157+
158+
Due to the constraints of HPC#, reference types cannot be used. Additionally, operations involving structural changes, such as adding/removing Entities or Components, are not allowed. (Arch's CommandBuffer is not compatible with HPC#, and Arch.Unity does not currently provide a dedicated CommandBuffer for use with Jobs.)
159+
160+
## Editor Extensions
161+
162+
### Arch Hierarchy
163+
164+
Arch.Unity provides an EditorWindow to display Entities for each World. You can open it from `Window > Arch > Arch Hierarchy`.
165+
166+
![img](docs/images/img-arch-hierarchy.png)
167+
168+
The numbers in the Entity names represent `(Index:Version)`.
169+
170+
### Inspector
171+
172+
When you select an Entity in Arch Hierarchy, the Inspector displays a list of Components attached to that Entity. These are read-only but useful for debugging as changes to values are reflected in real-time.
173+
174+
If the Entity has a `GameObjectReference` component, the synchronized GameObject is also displayed.
175+
176+
![img](docs/images/img
177+
178+
-inspector.png)
179+
180+
## Toolkit
181+
182+
Arch itself does not provide Systems. [Arch.Extended](https://github.com/genaray/Arch.Extended) provides APIs for Systems and a Source Generator. While these are very useful, they are not very user-friendly for use in Unity. Arch.Unity provides its own features to make working with Arch.System easier in Unity.
183+
184+
### UnitySystemBase
185+
186+
Instead of inheriting from `BaseSystem<W, T>`, implement Systems by inheriting from `UnityBaseSystem`. `UnityBaseSystem` inherits from `BaseSystem<World, SystemState>`, allowing access to information such as `Time` and `DeltaTime` from `SystemState`.
187+
188+
```cs
189+
public class FooSystem : UnitySystemBase
190+
{
191+
public FooSystem(World world) : base(world) { }
192+
193+
public override void Update(in SystemState state)
194+
{
195+
196+
}
197+
}
198+
```
199+
200+
### ArchApp
201+
202+
`ArchApp` is a class provided by Arch.Unity that offers functionality to handle World and Systems on Unity's PlayerLoop. (The design of ArchApp is inspired by Bevy Engine's App.)
203+
204+
Create an ArchApp using `ArchApp.Create()`. You can optionally pass in an external World, or it will automatically create a new one.
205+
206+
```cs
207+
var app = ArchApp.Create();
208+
```
209+
210+
Systems can be added to the created App. Systems added this way are automatically scheduled on the PlayerLoop. (You can also specify a `SystemRunner` to control when they run.)
211+
212+
```cs
213+
app.AddSystems(systems =>
214+
{
215+
systems.Add<FooSystem>();
216+
});
217+
218+
app.AddSystems(SystemRunner.FixedUpdate, systems =>
219+
{
220+
systems.Add<BarSystem>();
221+
});
222+
```
223+
224+
Start the ArchApp by calling `Run()`. Call `Stop()` to stop it.
225+
226+
```cs
227+
app.Run();
228+
```
229+
230+
These can also be chained using method chaining.
231+
232+
```cs
233+
ArchApp.Create()
234+
.AddSystems(systems =>
235+
{
236+
systems.Add<FooSystem>();
237+
})
238+
.AddSystems(SystemRunner.FixedUpdate, systems =>
239+
{
240+
systems.Add<BarSystem>();
241+
})
242+
.Run();
243+
```
244+
245+
Dispose of the App when finished using `Dispose()`. This will also dispose of the internal World.
246+
247+
```cs
248+
app.Dispose();
249+
```
250+
251+
### SystemRunner
252+
253+
SystemRunner abstracts the driving of Systems. Arch.Unity provides several SystemRunners that operate on the PlayerLoop and a `FakeSystemRunner` for unit testing.
254+
255+
You can also implement a custom SystemRunner by implementing `ISystemRunner`.
256+
257+
```cs
258+
public interface ISystemRunner
259+
{
260+
void Run();
261+
void Add(ISystem<SystemState> system);
262+
void Remove(ISystem<SystemState> system);
263+
}
264+
```
265+
266+
## VContainer Integration
267+
268+
Arch.Unity provides extensions to handle `ArchApp` with [VContainer](https://github.com/hadashiA/VContainer).
269+
270+
```cs
271+
using Arch.Unity;
272+
using Arch.Unity.Conversion;
273+
using VContainer;
274+
using VContainer.Unity;
275+
276+
public class ExampleLifetimeScope : LifetimeScope
277+
{
278+
protected override void Configure(IContainerBuilder builder)
279+
{
280+
// Create a new ArchApp when building the container
281+
// The created ArchApp, World, and added Systems are automatically registered with the DI container
282+
builder.UseNewArchApp(Lifetime.Scoped, EntityConversion.DefaultWorld, systems =>
283+
{
284+
systems.Add<FooSystem>();
285+
systems.Add<BarSystem>();
286+
});
287+
}
288+
}
289+
```
290+
291+
## License
292+
293+
[MIT License](LICENSE)

0 commit comments

Comments
 (0)