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 LocalTransformLookup;
のように記述する必要があります。
その際に、
using Unity.Collections;
を使うことを忘れないように。
ecbについては、
ecb = state.World.GetOrCreateSystemManaged().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 ShortDistanceAttackEnemyJob.JobData.__TypeHandle.__Unity_Transforms_LocalTransform_RW_ComponentTypeHandle is the same ComponentLookup as ShortDistanceAttackEnemyJob.JobData.LocalTransformLookup, two containers may not be the same (aliasing).
のように、大量のエラーが出現する。
併用はできないことに注意する。