動作確認環境
Unity 2020.02
Entities 0.17.0
前提
さわる対象のEntityはPhysics Shape相当(Colliderでもさわれる)がないとだめです。
#Physics Bodyは不要の簡易版
ソースコード
2パターン。(挙動的には同一のもの)
・Monobehavior経由
・ECS、Job、Burstで実行(無駄に長い)
カメラ情報を取得するためにMonobehaviorを使います。
MouseTouchEntityFromMonobehavior.cs
[SerializeField] Camera xCamera = default;
const float RAYCAST_DISTANCE = 1000;
PhysicsWorld physicsWorld => World.DefaultGameObjectInjectionWorld.GetExistingSystem<BuildPhysicsWorld>().PhysicsWorld;
EntityManager entityManager => World.DefaultGameObjectInjectionWorld.EntityManager;
void LateUpdate()
{
var screenPointToRay = xCamera.ScreenPointToRay(position);
var rayInput = new RaycastInput
{
Start = screenPointToRay.origin,
End = screenPointToRay.GetPoint(RAYCAST_DISTANCE),
Filter = CollisionFilter.Default
};
if (!physicsWorld.CastRay(rayInput, out RaycastHit hit)) return;
var selectedEntity = physicsWorld.Bodies[hit.RigidBodyIndex].Entity;
// ↑ マウスがあたったエンティティ(単体)
// CastRayの2個目の引数でNativeList<RaycastHit>を入れてあげれば
// Start-End間のEntitiesを取れる。(検証してないけど)
// あたったコンポーネントにアクセッス!
var renderMesh = entityManager.GetSharedComponentData<RenderMesh>(selectedEntity);
}
MouseTouchEntityFromJob.cs
public class MouseTouchEntityFromJob : MonoBehaviour, IConvertGameObjectToEntity
{
[SerializeField] Camera xCamera = default;
MouseTouchEntityFromJobSystem system => World.DefaultGameObjectInjectionWorld.GetExistingSystem<MouseTouchEntityFromJobSystem>();
void IConvertGameObjectToEntity.Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
dstManager.AddComponentData(entity, new MouseTouch() {});
}
void Start()
{
system.xCamera = xCamera;
}
}
public struct MouseTouch : IComponentData {}
public struct HitTargetData
{
public Entity Entity;
public int Hit;
}
public class MouseTouchEntityFromJobSystem : SystemBase
{
public Camera xCamera = default;
const float RAYCAST_DISTANCE = 1000;
public NativeArray<HitTargetData> MouseHitData;
BuildPhysicsWorld m_BuildPhysicsWorldSystem;
EndFramePhysicsSystem endFramePhysicsSystem;
EntityQuery m_MouseGroup;
public MousePickSystem()
{
// 気持ち悪かったらOnStartRunning()内でもいい好きにして!
MouseHitData = new NativeArray<HitTargetData>(1, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
MouseHitData[0] = new HitTargetData();
}
protected override void OnStartRunning()
{
// OnCreate()でもいい。好きにして!
m_BuildPhysicsWorldSystem = World.GetOrCreateSystem<BuildPhysicsWorld>();
endFramePhysicsSystem = World.GetOrCreateSystem<EndFramePhysicsSystem>();
m_MouseGroup = GetEntityQuery(new EntityQueryDesc { All = new ComponentType[] { typeof(MouseTouch) } });
}
protected override void OnUpdate()
{
var handle = JobHandle.CombineDependencies(Dependency, endFramePhysicsSystem.GetOutputDependency());
if (Input.GetMouseButton(0))
{
MouseTouchExecute(ref handle);
PaintJobHandle = handle;
handle.Complete();
}
Dependency.Complete();
if(MouseHitData[0].Hit == 1)
{
// あたったコンポーネントにアクセッス!
var renderMesh = EntityManager.GetSharedComponentData<RenderMesh>(MouseHitData[0].Entity);
}
}
protected override void OnDestroy()
{
if (MouseHitData.IsCreated) MouseHitData.Dispose();
}
void MouseTouchExecute(ref JobHandle handle)
{
var screenPointToRay = xCamera.ScreenPointToRay(Input.mousePosition);
handle = new Touch
{
physicsWorld = m_BuildPhysicsWorldSystem.PhysicsWorld,
SpringData = MouseHitData,
RayInput = new RaycastInput
{
Start = screenPointToRay.origin,
End = screenPointToRay.GetPoint(RAYCAST_DISTANCE),
Filter = CollisionFilter.Default
},
}.Schedule(handle);
}
[BurstCompile]
struct Touch : IJob
{
[ReadOnly] public PhysicsWorld physicsWorld;
public NativeArray<HitTargetData> SpringData;
public RaycastInput RayInput;
public void Execute()
{
if (physicsWorld.CastRay(RayInput, out Unity.Physics.RaycastHit rayInput))
{
RigidBody hitBody = physicsWorld.Bodies[rayInput.RigidBodyIndex];
SpringData[0] = new HitTargetData
{
Entity = hitBody.Entity,
Hit = 1,
};
}
else
{
SpringData[0] = new HitTargetData
{
Hit = 0,
};
}
}
}
}
参考資料
・https://github.com/reeseschultz/ReeseUnityDemos
・https://github.com/Unity-Technologies/EntityComponentSystemSamples