Skip to content

Instantly share code, notes, and snippets.

@tsubaki
Last active October 22, 2019 17:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tsubaki/22453785321ec8b0732f13fc6b719434 to your computer and use it in GitHub Desktop.
Save tsubaki/22453785321ec8b0732f13fc6b719434 to your computer and use it in GitHub Desktop.
ISystemStateComponentData及びISystemStateBufferElementDataの使用例
using Unity.Collections;
using Unity.Entities;
using Unity.Transforms;
using static Unity.Entities.ComponentType;
public struct LookAtInitialized : ISystemStateComponentData
{
public Entity Value;
}
public struct ReferenceFromLookatBuffer : ISystemStateBufferElementData
{
public Entity Value;
}
public struct ReferenceFromLookatInitialized : IComponentData { }
[UpdateInGroup(typeof(InitializationSystemGroup))]
public sealed class LookAtCleanupSystem : ComponentSystem
{
EntityQuery initializeQuery, cleanupQuery, cleanupTargetQuery;
protected override void OnCreate()
{
initializeQuery = GetEntityQuery(ReadOnly<LookAt>(), Exclude<LookAtInitialized>());
cleanupQuery = GetEntityQuery(ReadOnly<LookAtInitialized>(), Exclude<LookAt>());
cleanupTargetQuery = GetEntityQuery(ReadOnly<ReferenceFromLookatBuffer>(), Exclude<ReferenceFromLookatInitialized>(), Exclude<LocalToWorld>());
}
protected override void OnUpdate()
{
if (initializeQuery.CalculateChunkCount() > 0)
{
InitializeLookAt();
}
if (cleanupQuery.CalculateChunkCount() > 0)
{
CleanupLookAt();
}
if (cleanupTargetQuery.CalculateChunkCount() > 0)
{
CleanupReferenceFromLookat();
}
}
void InitializeLookAt()
{
// LookAtが参照するEntityにReferenceFromLookatBufferを追加、LookAtを持つEntityを参照させる。
Entities.With(initializeQuery).ForEach((Entity entity, ref LookAt lookat) =>
{
var buffer = EntityManager.AddBuffer<ReferenceFromLookatBuffer>(lookat.Target);
buffer.Add(new ReferenceFromLookatBuffer { Value = entity });
});
// 初期化完了フラグを設定。
// LookAtInitializedはEntityが破棄されても参照先の情報を把握できるようにバックアップする。
using (var lookats = initializeQuery.ToComponentDataArray<LookAt>(Allocator.TempJob))
{
EntityManager.AddComponentData(initializeQuery, lookats.Reinterpret<LookAt, LookAtInitialized>()); // LookAtがLookAtInitializedと同じデータ構造なので、そのままコピー。
EntityManager.AddComponent<ReferenceFromLookatInitialized>(lookats.Reinterpret<LookAt, Entity>()); // LookAtの中身がEntityだけなので、変換して参照先として使用
}
}
void CleanupLookAt()
{
// ReferenceFromLookatBufferの一覧から、破棄されたEntityを削除。
Entities.With(cleanupQuery).ForEach((Entity entity, ref LookAtInitialized lookat) =>
{
var buffer = EntityManager.GetBuffer<ReferenceFromLookatBuffer>(lookat.Value);
var bufferIndex = buffer.Find(new ReferenceFromLookatBuffer { Value = entity });
if (bufferIndex != -1) { buffer.RemoveAt(bufferIndex); }
});
EntityManager.RemoveComponent<LookAtInitialized>(cleanupQuery);
}
void CleanupReferenceFromLookat()
{
var lookatEntityList = new NativeList<Entity>(Allocator.Temp);
// ReferenceFromLookatBufferが参照しているEntityを全てlistに格納。
// 格納完了後、ReferenceFromLookatBufferは破棄する。
using (var referencedEntities = cleanupTargetQuery.ToEntityArray(Allocator.TempJob))
{
foreach (var entity in referencedEntities)
{
var buffer = EntityManager.GetBuffer<ReferenceFromLookatBuffer>(entity);
lookatEntityList.AddRange(buffer.Reinterpret<Entity>().AsNativeArray()); // ReferenceFromLookatBufferがEntityしか格納してないので使える力業
EntityManager.RemoveComponent<ReferenceFromLookatBuffer>(entity); // 代わりに使用:EntityManager.RemoveComponent<ReferenceFromLookatBuffer>(referencedEntities);
}
}
// ReferenceFromLookatBufferが参照していたEntityのLookAtとLookAtInitializedコンポーネントを全て破棄。
EntityManager.RemoveComponent<LookAt>(lookatEntityList);
EntityManager.RemoveComponent<LookAtInitialized>(lookatEntityList);
lookatEntityList.Dispose();
}
}
public static class DynamicBufferEx
{
public static int Find<T>(this ref DynamicBuffer<T> buffer, T input) where T : struct
{
for (var bufferIndex = 0; bufferIndex < buffer.Length; bufferIndex++)
{
if (buffer[bufferIndex].Equals(input)) { return bufferIndex; }
}
return -1;
}
}
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
[DisallowMultipleComponent]
[RequiresEntityConversion]
public class LookAtComponent : MonoBehaviour, IConvertGameObjectToEntity
{
[SerializeField]
GameObject target;
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
dstManager.AddComponentData(entity, new LookAt { Target = conversionSystem.GetPrimaryEntity(target) });
}
}
public struct LookAt : IComponentData
{
public Entity Target;
}
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
public sealed class LookAtSystem : JobComponentSystem
{
struct LookatJob : IJobForEach<LocalToWorld, Rotation, LookAt>
{
[ReadOnly] public ComponentDataFromEntity<LocalToWorld> worldPositions;
public void Execute([ReadOnly] ref LocalToWorld worldPosition, ref Rotation rotation, [ReadOnly] ref LookAt lookat)
{
var diffPos = math.normalizesafe(worldPositions[lookat.Target].Position - worldPosition.Position);
rotation.Value = quaternion.LookRotation(diffPos, math.up());
}
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
inputDeps = new LookatJob
{
worldPositions = GetComponentDataFromEntity<LocalToWorld>(true)
}.Schedule(this, inputDeps);
return inputDeps;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment