ECS 記述方法に関する備忘録

## 1. Schedule と .ScheduleParallelの違いについて

どうやら、
Schedule = ワーカースレッド上のシングルスレッド
ScheduleParallel = ワーカースレッド上のマルチスレッド
といった違いがあるようですが、具体的にコード記述していく上でどんな風に違いが出てくるのか、備忘録を残します。（随時追加予定）


#### GetSingletonEntityが利用できない

ScheduleParallelでSystemAPI.GetSingletonEntityを使おうとすると、以下のようなエラーが出ます。
（ECSのエラー長すぎ...）

InvalidOperationException: AttackEnemyJob.JobData.LocalTransformLookup is not declared [ReadOnly] in a IJobParallelFor job. The container does not support parallel writing. Please use a more suitable container type.
Unity.Jobs.LowLevel.Unsafe.JobsUtility.ScheduleParallelFor (Unity.Jobs.LowLevel.Unsafe.JobsUtility+JobScheduleParameters& parameters, System.Int32 .....


#### ReadOnlyしか使えない
例えば、
[ReadOnly] public ComponentLookup<LocalTransform> LocalTransformLookup;
のように記述する必要があります。
その際に、
using Unity.Collections;
を使うことを忘れないように。

ecbについては、
ecb = state.World.GetOrCreateSystemManaged<BeginSimulationEntityCommandBufferSystem>().CreateCommandBuffer().AsParallelWriter(),
public EntityCommandBuffer.ParallelWriter ecb
のように記述できる。

あと、
public void Execute(Entity entity, CharactorTargetEntity targetEntity, CharactorAttackProperties attackProperties, [ChunkIndexInQuery] int sortKey)
var newAttackPrefab = ecb.Instantiate(sortKey, AttackPrefab);
のように、sortkey関係の記述も忘れずに。

動作が重くなりそうなところは、積極的にParallelを使っていきましょう。


## 2. foreachとExcuteの使い分け

基本的には、Unity公式もECSではExcute利用を推奨しているので、Excuteを使いたいと思いますが、foreachでないと記述できないケースもあるので、使い分けについてメモを残します。

### foreachを使う必要がある例

#### SystemAPIを使いたい
Excute内では、JOB化して高速計算するための制約として、SystemAPI.GetComponentとかは使えません。
ただ、
```
MobaTeamLookup = SystemAPI.GetComponentLookup<MobTeam>(true),
[ReadOnly] public ComponentLookup<MobTeam> MobaTeamLookup;
```
のように記述すれば、実質利用できるので、ちょっと記述は面倒ですがExcuteを使った方がよいと思います。

#### ゲームオブジェクトを呼び出したい
例えば以下のような記述を使って、MonoBehaviorを呼び出し、ゲームオブジェクトを出現させたい場合、
Excuteは利用できないので、foreachを使う必要があります。
```
public Action<int, float3> OnDealDamage;
OnDealDamage?.Invoke(damageToCharactor.Value, transform.Position);
```
entityは制約が多いので、ゲームオブジェクトを出現させたい、というケースは結構多いのではないかと思います。
例えば私の場合は、entityがダメージを受けた時にダメージアイコン（「-10」とか）を出したいですが、entityで利用できるテキストデザインに厳しい制約があるようで、ゲームオブジェクト使いました。

### 特定EntityのCompornentを呼び出す際の記述方法

微妙な記述方法の違いが中々覚えられないので、纏めます。

#### foreachの場合

特定Entityのコンポーネントやその中身を参照
```
SystemAPI.GetComponent<コンポーネント名>(entity名)
```
コンポーネント追加
```
ecb.AddComponent(entity名, new コンポーネント名 { });
```
※foreach完了後、OnUpdate内での以下記述を忘れずに。
```
ecb.Playback(EntityManager);
ecb.Dispose();
```

#### Excuteの場合

特定Entityのコンポーネント（またはコンポーネント内の数値）
```
コンポーネント名Lookup = SystemAPI.GetComponentLookup<コンポーネント名>(),
[ReadOnly] public ComponentLookup<コンポーネント名> コンポーネント名Lookup;
コンポーネント名Lookup[entity名].コンポーネント内の数値名（Valueなど）
```

Excute内で定義したコンポーネントを使って、Excute実行中Entityのコンポーネントにアクセス
```
Execute(Entity entity, LocalTransform transform)
transform.Position
```

Excute実行中以外のEntityのコンポーネントにアクセスする場合には、コンポーネント名Lookupの利用が必須。
厄介なのは、Excute内で定義済みのコンポーネントを、CompornentLookUpで呼び出すと
InvalidOperationException: The writeable ComponentTypeHandle<Unity.Transforms.LocalTransform> ShortDistanceAttackEnemyJob.JobData.__TypeHandle.__Unity_Transforms_LocalTransform_RW_ComponentTypeHandle is the same ComponentLookup<Unity.Transforms.LocalTransform> as ShortDistanceAttackEnemyJob.JobData.LocalTransformLookup, two containers may not be the same (aliasing).
のように、大量のエラーが出現する。
併用はできないことに注意する。