本題の前に
ただの大学生がUnity DOTSを実際に触ってみる。2日目です。いつものように嘘が混じってるかもしれません。ごめんなさい。
昨日の記事は こちら
環境
Unity 2022.2.1f1
Entities 1.0.0-pre.15
Burst 1.7.4
今日の内容
生成したEntityを消したい。今日はその一心で頑張ってました。そして、ISystemとSystemBaseの差に気がつかされました。
昨日は内容が本当に内容だったので、今日は適当に書いたコードも載せます。
Entityを消す。
どうやら、2通り消し方があるっぽい。
1個目がEntityManager.DestroyEntity()
を使う方法。
2個目がEntityCommandBuffer.DestroyEntity()
を使う方法です。
何が違うのか
正直、良くわからんというのが本音。バッファーッテナンヤ
今わかってるふんわりとしたものを書きます。
EntityManager
1個目の方は上手く使うのは難しそうだったってこと。foreach
で条件に合ったEntity全部消し飛ばすコードを書いたら、EntityManagerを過労死させるんじゃねぇって言われました。(意訳)
まぁ詳細に言えば非同期処理に対応していなくて連続して使用するとパンクしてしまうようです。
EntityCommandBuffer
2個目のほうは使うまでが遠い。あとISystem
では使えないっぽいですね。(最適化できないっぽい?)なぜかというと、ISystem
はstruct
でしか使えず、それではCommandBuffer
の取得の最初の段階である、BeginSimulationEntityCommandBufferSystem
の取得が上手くいかなかったです。ただ、CommandBuffer
の取得方法は色々あるみたいなのでもう少し検証が必要かもしれません。
結局
EntityManager
は取得が簡単で、ISystem
でもSystemBase
でも使えるようです。なので簡単な処理はEntityManager。複雑な処理はCommandBuffer
を引っ張り出してくる手法が良さそうです。
適当に書いたコード
昨日紹介した、Unity公式ドキュメント中に落ちているサンプルコードで色々遊んでいました。しばらくしたら、Cube消したいなーというコードです。
using Unity.Burst;
using Unity.Entities;
using UnityEngine;
[BurstCompile]
public partial class CubeSystem : SystemBase
{
private BeginSimulationEntityCommandBufferSystem _entityCommandBufferSystem;
protected override void OnCreate()
{
// EntityCommandBufferの取得
_entityCommandBufferSystem = World.GetOrCreateSystemManaged<BeginSimulationEntityCommandBufferSystem>();
}
protected override void OnDestroy()
{
}
[BurstCompile]
protected override void OnUpdate()
{
int i = 0;
var _ecb = _entityCommandBufferSystem.CreateCommandBuffer();
foreach (var (_componentData, _entity) in SystemAPI.Query<RefRW<CubeData>>().WithEntityAccess())
{
_componentData.ValueRW._liveTime += 0.1f;
if(_componentData.ValueRW._liveTime >= 1000f)
{
//CommandBufferでデストロイ!
_ecb.DestroyEntity(_entity);
}
i++;
}
Debug.Log($"キューブの数は、{i}個です。");
}
}
で、色々苦戦したことを上に書いたのですが、それ以上に知っておいて得だなと思ったコードがあるので、少し紹介します。
多くの人が知ってるかもしれないんですけど…
コード解説(そんな大そうなものではない)
ECSのforeach
Entity.ForEach
という構文がどうにも好きになれない私は純粋なforeachで書いてみました。しかし、Componentは取得できてもEntityが取得できない!!!という現象に陥りました。結果以下のコードで良かった。
foreach (var (_componentData, _entity) in SystemAPI.Query<RefRW</*Componentの条件*/>>().WithEntityAccess())
{
//処理
}
WithEntityAccess()
が肝でした。そうすると、Entityも一緒に降ってくるようになって幸せになりました。
え?Entity.ForEachを使えば楽だって?それは分かってる。
情報更新
ネットのどこを漁ってもBeginSimulationEntityCommandBufferSystem
の取得をするときはWorld.GetOrCreateSystem<BeginSimulationEntityCommandBufferSystem>()
を使え!って書いてありました。
しかし、バージョンの更新の影響なのかそれではエラーになってました。なので、World
のコードを漁るとそれっぽいメソッドを発見。
World.GetOrCreateSystemManaged<BeginSimulationEntityCommandBufferSystem>()
でした。Managedね。よくわからんけどこれで動いたからよし!(後々理解したいの意)
おわり
昨日よりは内容あったんじゃないっすか?明日は、当たり判定とかInput Systemとの連携とかそこら辺をやりたい所存。
雑記にお付き合いいただきありがとうございました。また明日。