ãUnityãGameObjectãECSã使ããã Hybrid ECSã«ã¤ãã¦
ãECSã¯ç¾ç¶æ£ç´ãªæãç©éãå¿ è¦ãªé¨åãECSã§è©¦ãã¦å¤§ã¾ããªé¨åã¯æ¢åã®MonoBehaviourãUnityEngineç³»ã®ã³ã³ãã¼ãã³ãã使ãã®ããã¿ã¼ãªåçã§ããä»åã¯ECSã¨GameObjectãé£æºãããææ³ã«ã¤ãã¦ãç´¹ä»ãã¾ãã
æ¤è¨¼ãã¼ã¸ã§ã³ï¼Unity 2019.3ãEntities 0.3.0 preview 4
- Hybrid ECS
- GameObjectã¨Entityã®åæ
- åæã®ãµã³ãã«ã³ã¼ã
- GameObjectãããã¯Entityã®ç ´æ£ã«ã¤ãã¦
- ã¯ã©ã¹ã管çãããManagedããªComponentData
- ISharedComponentDataã¨ã®éã
- ãã¾ã
- é¢é£
Hybrid ECS
ãConvertToEntity
ã¯GameObjectãEntityã¸å¤æãã¦ãããã³ã³ãã¼ãã³ãã§ãããConvertAndInjectGameObject
ã使ç¨ããã¨å¤æå¾ã«GameObjectãåé¤ãã代ããã«ãGameObjectãComponentãEntityã¸ç»é²ãã¦ããã¾ããããã§EntityããGameObjectãComponentã¸åç
§ãå¯è½ã«ãªãã2ã¤ã»ããã§éç¨å¯è½ã«ãªãã¾ãã
ããã®æãæ ¼ç´ããããã¼ã¿ã¯Structã§ã¯ãªãClassã§ãããå é¨ã§ã®æ±ãã¯ã ãã¶éãã¾ãããã®è¾ºãã¯å¾è¿°ã®MnaagedComponentData辺ãã§ã
GameObjectã¨Entityã®åæ
ãHybrid ECSã®æçãªä½¿ãæ¹ã®ä¸ã¤ã¯GameObjectã¨ã®åæã§ããECSå´ã§è¤éãªè¨ç®ãè¡ããã¼ã¿ãåæãè¨ç®çµæãMonoBehaviourã§ä½¿ç¨ãã¾ãã
ããªãGameObjectã¨Entityã®åæã¯ä¸æ¹éè¡ãæã¾ããã§ããã¤ã¾ãEntityã®åº§æ¨ãGameObjectã«åæããããGameObjectã®åº§æ¨ãEntityã«åæããã®ãã¨ãã話ã§ããåè ã®å ´åã¯å¿ ç¶çã«ECSã®Systemã«ãã管çãå¾è ã®å ´åã¯MonoBehaviourã®ç®¡çã«ãªãã¾ãã
ãæ
å ±ãåæããã¿ã¤ãã³ã°ã¯PlayerLoopãã«ã¹ã¿ã ãã¦ããªããã°ãInitializationSystemGroup
ãMonoBehaviourã®Update
ãSimulationSystemGroup
ãPresentationSystemGroup
ãMonoBehaviourã®LateUpdate
ã®ã©ããã®ã¿ã¤ãã³ã°ã«è¨å®ãã¾ããå人çãªãªã¹ã¹ã¡ã¯ SimulationSystemGroupã§ã¸ã§ããçºè¡ãã¦æ¬¡ã®InitializationSystemGroupã§åæã§ããæ
å ±ã¯å¸¸ã«1ãã¬ã¼ã é
ããäºã«ãªãã¾ããããããããã®ã¨å²ãåã£ã¦ä½¿ãã°ã¯ã»ããªã使ããããã§ãã
åæã®ãµã³ãã«ã³ã¼ã
ãä¾ãã°ä¸ã®ãããªã·ã¹ãã ãèãã¾ããPlayerTag
ãæã¤ãã£ã©ã¯ã¿ã¼ã¨ã®è·é¢ã確èªãã¦DistanceFromPlayer
ã«æ ¼ç´ããã¨ãã£ããã®ã§ãã
/// <summary> PlayerTagãæã¤Entityã¨ã®è·é¢ </summary> public struct DistanceFromPlayer : IComponentData{ public float Value;} /// <summary> PlayerTagã¨DistanceFromPlayerã®è·é¢ãValueã«æ ¼ç´ããã·ã¹ãã </summary> public class DistanceCheckSystem : JobComponentSystem { // ä¸ç¥ protected override JobHandle OnUpdate(JobHandle inputDeps) { var playerPos = playerQuery.GetSingleton<LocalToWorld>().Position; // è·é¢ãæ ¼ç´ return Entities .ForEach((ref DistanceFromPlayer distance, in LocalToWorld pos) => { distance.Value = math.distance(pos.Position, playerPos); } ).Schedule(inputDeps); } }
ããã®ã¾ã¾ã ã¨ECSã§ã¯ä½¿ãã¦ãMonoBehaviourã§ã¯é¢åãããã®ã§ãè¨ç®çµæãMonoBehaviourã«åæãã¾ããããã§ä»ã®MonoBehaviourããè¦ã㨠distanceFromPlayerAuthoring.Distance
ã§ãã¬ã¤ã¤ã¼ã¨ã®è·é¢ãåå¾åºæ¥ãããã«ãªãã¾ãã
ãããGameObjectâEntityã«ãããå ´åã¯ãauthoring.Distance = distance.Value;
ãéã«ãã¾ãã
[DisallowMultipleComponent] [RequiresEntityConversion] public class DistanceFromPlayerAuthoring : MonoBehaviour, IConvertGameObjectToEntity { /// <summary> ãã¬ã¤ã¤ã¼ã¨ã®è·é¢ </summary> public float Distance { get; set; } // ä¸ç¥ } // DistanceFromPlayerãDistanceFromPlayerAuthoringã«åæ ããã·ã¹ãã [UpdateInGroup(typeof(InitializationSystemGroup))] public class SetDistanceDataToAnimator : ComponentSystem { protected override void OnUpdate() { // DistanceFromPlayer ã®å¤ãDistanceFromPlayerAuthoring ã¸åæ Entities. ForEach((DistanceFromPlayerAuthoring authoring, ref DistanceFromPlayer distance) => { authoring.Distance = distance.Value; }); } }
ãããã§ä»ã®MonoBehaviourããã¯ä¸ã®ãããªã³ã¼ãã§Playerã¨ã®è·é¢ãåå¾åºæ¥ãããã«ãªãã¾ãããæ¬å½ã¯EntityManagerã§åå¥ã«åã£ã¦ãè¯ãã®ã§ãããã·ã¼ã±ã³ã·ã£ã«ã«åæ ãããã»ããæçµçã«å®ãã®ã§ã
void Update()
{
Debug.Log(fromPlayer.Distance);
}
å ¨æ
MonoBehaviourとComponentDataの同期 · GitHub
GameObjectãããã¯Entityã®ç ´æ£ã«ã¤ãã¦
ãGameObjectã¨Entityãåæããæ¹æ³ã¯ConvertToEntityã使ç¨ãããã¨ã§ããããã®ã³ã³ãã¼ãã³ãã¯å®ã¯Entityã®ç ´æ£ã«ãããã¦GameObjectãç ´æ£ãã¦ãããªãããããã¯GameObjectã®ç ´æ£ã«åããã¦Entityãç ´æ£ãã¦ãããªãã§ãã
ããã®ãããåç´ã«ãã¬ã¤ã¤ã¼ãUIã«ä½¿ç¨ããå ´åãã·ã¼ã³ã®åãã¼ãã§ãã¬ã¤ã¤ã¼ã®æ°ãå¢ããããã¹ã³ã¢ã表示ããUIã2ã¤ãã£ããã¨ãã£ãæåããããã¾ããã¤ã¾ãEntityããªã¼ã¯ãã¾ããã¾ãEntityãJobSystemããç ´æ£ãã¦ãGameObjectãç ´æ£ãããªãã®ã§ã対象ã«ããæåãå¤ããã¨ããé常ã«é¢åãããããªãã¯ãå¿ è¦ã«ãªãã¾ãã
ããããåé¿ããã«ã¯GameObjectã®ç ´æ£ãæ¤ç¥ãã¦èªåã§Entityãç ´æ£ãããã¾ãã¯ãã®éã¨ãã£ãã³ã¼ããå¿ è¦ã«ãªãã¾ããããã¯ä¸ã®ã³ã³ãã¼ãã³ãã使ç¨ãããã¨ã§å®ç¾åºæ¥ã¾ããã³ã¼ãã¯é·ãã®ã§ãªã³ã¯ã®ã¿ã
GameObjectを破棄するとEntityも破棄される。もしくはその逆 · GitHub
ããã£ã¦ãããã¨ã¯ISystemStateComponentDataã§Entityã®ç ´æ£ãæ¤åºãã¦ç´ä»ãã¦ããGameObjectãç ´æ£ããããã¯Authoringã®OnDestroyã«åå¿ãã¦Entityãç ´æ£â¦ã¨ãã¦ããã ãã§ãã
ãManagedComponentDataãç¡ãã£ãæã¯Dictionaryã¨InstanceIDã§ç´ä»ãã¦ãã¾ãããã0.2.0ã§ä¸è¦ã«ãªãã¾ããã
ã¯ã©ã¹ã管çãããManagedããªComponentData
ãHybrid ECSã¯ããã¼ã¸ããªã¡ã¢ãªãæã¤ãã¼ã¿ãEntityã«æ ¼ç´ãããã¨ã§æãç«ã¡ã¾ãããã®å®è£ ã¯ä»ã¾ã§ã¯MonoBehaviourå°ç¨ã§ããããEntities 0.2.0ããclassã®IComponentDataã使ç¨å¯è½ã«ãªãã¾ããã Classã®ComponentDataã¯æ®éã«åç §åãªã®ã§ãå é¨ã§å¤é¨åç §ãããè²ã ã¨è¡ããã¨ãåºæ¥ã¾ãã
ãå½ç¶MonoBehaviourã使ç¨ããå ´åã¨åãå¶ç´ãJobSystemã§ã¯ä½¿ããªãããBurstã使ããªãããã·ã¼ã±ã³ã·ã£ã«ãªã¡ã¢ãªã¢ã¯ã»ã¹ãåºæ¥ãªããã®å¶ç´ã¯ããã¾ãããéãå°ãªããã°å¤§ããåé¡ã§ã¯ãªãã§ããããããã§ã·ã¹ãã ã«è²ã ã¨ã¹ãã¼ããæ ¼ç´ããªãã¦ãè¯ããªãã¾ããã
// æååãComponentã«æ ¼ç´ [GenerateAuthoringComponent] public class MessageData : IComponentData{ public string Value; } public class ShowMessage : JobComponentSystem { protected override JobHandle OnUpdate(JobHandle inputDeps) { // å®è¡ã«ã¯WithoutBurstã¨Runã§è¡ãå¿ è¦ããã Entities .WithoutBurst() .ForEach((MessageData data) =>{ UnityEngine.Debug.Log(data.Value); }).Run(); return inputDeps; } }
ããªãHybrid ECSã§Entityã«ç»é²ããMonoBehaviourãUnityEngineãã¼ã¹ã®ã³ã³ãã¼ãã³ããããã¦classã®IComponentDataã¯Chunkã«æ ¼ç´ããããç¬èªã®ãããã¡ã«æ ¼ç´ããEntityçµç±ã§åç §ããã¾ããHybrid ECSã使ç¨ããå ´åã§ãstructã®IComponentDataã®ã¢ã¯ã»ã¹ã¯ãªãã¢ãªã¢ã¯ã»ã¹ãç´æããã¦ããã®ã§ãé度ã¯ä½ä¸ãã¾ããã
ISharedComponentDataã¨ã®éã
ãManagedãªãã¼ã¿ãä¿æåºæ¥ãã¨ããç¹ã§ã¯ãä¼¼ããããªæ©è½ã«ISharedComponentDataã¨ãããã®ãããã¾ããããã¯ä»å¾ã¯ãããå¦çãããã¨ãã«ä½¿ç¨ããã¨ãã棲ã¿åãã«ãªãããããªãããã¨æãã¾ãã
ãSharedComponentDataã¯ä¿æãããã¼ã¿ã®ç¨®é¡ã§ãã£ã³ã¯ãåå²ãã¾ããããã¯è¨ãæããã°åãSharedComponentDataãæã£ã¦ããEntityãé£ç¶ãã¦é ç½®ãããã¨ãããã¨ã§ãé£ç¶ãã¦åãå¦çãå®ç¾ããï¼ãããå¦çï¼ã«å¹ççã§ããã·ã¹ãã å´ããããã¨é£ç¶ãã¦åããã¼ã¿ãããäºãä¿è¨¼ãããã®ã§ãBurstã«ããæé©åãè¡ãããããªãã¾ãã
ãå®éãAIãç¶æ
ç°å¸¸çãæåãå¤ããééãåºãåä½ã«ã¤ãã¦ã¯ComponentDataã®ä¸èº«ãè¦ã¦ifã§åå²ãããããã¿ã°ComponentData
ã追å ãããSharedComponentData
ã®å¤ã®å¤æ´ã«ãã£ã¦åä½ãåãæ¿ããã»ããçã«ããªã£ã¦ããã¨ãã話ãããã¾ãã
ããã ãChunkãåå²ãããã¨ãããã¨ã¯ãSharedComponentDataã®å¤ãå¤ãã度ã«ãã¼ã¿ã¯ã½ã¼ãã®ããã«ä»ã®Chunkã¸ã³ãã¼ãããã¨ããäºã§ãããã¾ãããã®ã³ãã¼ã¯ãããªãã«å¹ççã§ã¯ããã¾ãããå®å ¨ã«ç¡è¦åºæ¥ãã»ã©ã«å®ãã¯ãªãã®ã§ãæ´æ°é »åº¦ãé«ãå ´åã¯é¿ããæ¹ãè¯ãã§ãï¼æ¯ãã¬ã¼ã å¤ãããããªå ´åï¼ ãã¾ã座æ¨ã®ããã«ã¦ãã¼ã¯ãªå¤ã大éã«æã¤ã®ãé¿ããã¹ãã§ããChunkãã¹ã«ã¹ã«ã«ãªãã¾ãã
ããã®ç¹Managed Component Dataã¯ãã£ã³ã¯ç§»åç¡ãã«ComponentDataã®å¤ãå¤æ´åºæ¥ãã¦ãã¼ã¯ãªå¤ãæã£ã¦ãã¦ãChunkã¯ã¹ã«ã¹ã«ã«ã¯ãªãã¾ããããã ããã¼ã¿ãã½ã¼ããã¦ãããªãã®ã§ãComponentDataã®ä¸èº«ã«å¿ãã¦å¦çãåãæ¿ããã¨ãã£ãå ´åã§ã¯å¹çã¯å£ãã¾ãã*1
ãã¾ã
ãManagedComponentDataãåºæ¥ãã®ã§ãScriptableObjectãEntityã«æ ¼ç´ããã¨ããåæãåºæ¥ãããã«ãªã£ãã¿ããã§ãããã£ã¦è¯ãã®ãã¯ã¾ãå¥ã¨ãã¦ãããã§ã·ã¹ãã ã«æ
å ±ã渡ãçºã«åè¦å
«è¦ããªãã¦ãè¯ããªãæ°ãããªãããªãã§ãããã¨ã·ã¹ãã ã®å¤ãæ´æ°ããã®ã楽ã§ãã
ããã LiveLinkã¨ç¸æ§ãæªãããªã®ã§ãç¾å®çã«ã¯ClassãªComponentDataã«ç´æ¥ãã¼ã¿ã使ç¨ããã®ãç¾å®çããããã¾ããã
/// <summary> /// ScriptableObject (IComponentDataãç¶æ¿ï¼ /// </summary> public class MyData : ScriptableObject, IComponentData { public string Value; } /// <summary> /// Authoringã§ScriptableObjectãç»é² /// </summary> public class MessageData : MonoBehaviour, IConvertGameObjectToEntity { public MyData data; public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { dstManager.AddComponentData(entity, data); } } public class LogTest : JobComponentSystem { EntityQuery query; MyData data; protected override void OnCreate() { query = GetEntityQuery(typeof(MyData)); } protected override void OnStartRunning() { Entities .WithoutBurst() .ForEach((MyData d) => data = d) .Run(); } protected override JobHandle OnUpdate(JobHandle inputDeps) { // ã·ã¹ãã ãScriptableObjectã®å¤ãåç § Debug.Log(data.Value); return inputDeps; } }
é¢é£
*1:ã¾ãã¡ã¤ã³ã¹ã¬ããã§ã®ã¢ã¯ã»ã¹éå®ã§å¹çãã¯ã½ããªãã®ã§ãã
ãUnityãJobSystemãåä½ãã¦ããã¹ã¬ããã®çªå·ãåå¾ãã
è¤æ°ã®ã¸ã§ãã§å¦çãè¡ãæãå ¨ã¦ã®ã¸ã§ããåããããã¡ã«æ ¼ç´ãããã¨ããã¨å½ç¶ç«¶åãèµ·ããã¾ããã³ã¬ãåé¿ããããã«æä»å¦çãè¡ã訳ã§ããããããè¡ããè¨ç®çµæãæ ¼ç´ããæ¹æ³ãèãã¦ã¿ã¾ãã
ã¸ã§ãæ¯ã«è¨ç®çµæãæ ¼ç´ãã対象ãåãæ¿ãã
ç¹ã«ä½ãèããã«å ¨ã¦ã®ã¸ã§ãããç¹å®ã®è¦ç´ ã«æ¸ãè¾¼ãå ´åãåæã«æ¸ãè¾¼ãã ããè¨ç®ã®åæã¨ãªãç¶æ ãå¤ãã£ãããã¦åé¡ã«ãªãã¾ãããã®æåã¯JobSystemã§ã¯å®è¡æã«ã¨ã©ã¼ã«ãªãã¾ãã
ãã®åé¡ã¯ ç°ãªãã¹ã¬ããããåãè¦ç´ ã«æ¸ãè¾¼ãäºã§èµ·ããã®ã§ãã¹ã¬ããæ¯ã«èªã¿æ¸ãããè¦ç´ ã決ãã¦ãå¦çãè¡ãæ¹æ³ãèãã¦ã¿ã¾ãã
å©ç¨ããAPI
ã¾ãéè¦ãªã®ã [NativeSetThreadIndex] int threadIndex;
ãã¸ã§ãã«å®ç¾©ãããã¨ã§ãããã®è¨è¿°ã§ã¸ã§ããåä½ãã¦ããã¹ã¬ããã®çªå·ãåå¾ã§ãã¾ãã注æã¨ãã¦ï¼ï½ï¼ã¨ãã£ãWorkerThreadãåä½ãã¦ããçªå·ã§ã¯ãªãã0ï½128ã¨ãã£ãã¹ã¬ããã®å
ã®ãã¬ããå
¥ãã¾ãã
ãã®threadIndex
ãå
ã«æ
å ±ãæ ¼ç´ããããåå¾ããããã¾ãã
ãã®æãã¸ã§ããèªã¿æ¸ãããNativeArrayã«ã¯NativeDisableContainerSafetyRestriction
ãè¨å®ãã¾ããã³ã¬ãè¨å®ããªããã°ãã¸ã§ãã·ã¹ãã ã¯è¤æ°ã®ã¹ã¬ããããä¸ã¤ã®è¦ç´ ãæä½ããå¯è½æ§ãããã¨ãã¦ã¨ã©ã¼ãåºãã¦ãã¾ãã¾ããä»åã¯ããã¯èµ·ãããªãäºå®ãªã®ã§ä¸è¨ã®è¨å®ã使ç¨ã§ãã¾ãã
ã¸ã§ãã®å®è£ ã¯ãããªæãã§ããå ¨ã¦ã®ã¸ã§ããåã ã®æ å½ããè¦ç´ ã«ï¼ï¼ãã¦ããã ãã§ãã
[BurstCompile] struct CountJob : IJobParallelFor { [NativeSetThreadIndex] int threadIndex; [NativeDisableContainerSafetyRestriction] public NativeArray<int> array; public void Execute(int index) { var count = array[threadIndex]; count = count + 1; array[threadIndex] = count; } }
ãã¨ã¯ã¸ã§ãã使ç¨ããå´ã§ããæ®éã«NativeArrayãçæããã®ã§ãããè¦ç´ æ°ã¯JobsUtility.MaxJobThreadCount
ã使ç¨ãã¾ããthreadIndex
ãè¿ãæ°ã0~128ãªã®ã§ããã®è¦ç´ ã®ã©ãã§ãæ ¼ç´åºæ¥ãããã«ããå¿
è¦ãããçºããã®åéã®è¦ç´ ãçæãã¦ãã¾ãã
void Update() { handle.Complete(); var array = new NativeArray<int>(JobsUtility.MaxJobThreadCount, Allocator.TempJob); handle = new CountJob { array = array }.Schedule(24576, 8); array.Dispose(handle); JobHandle.ScheduleBatchedJobs(); }
ãªãæçµçãªéè¨ã¯JobsUtility.MaxJobThreadCount
ã®æ°ã®è¦ç´ ãéè¨ããæãã«ãªãã¾ããããã¯ã¤ã±ã¦ãªãæ°ããã¾ãããæ°åã®è¦ç´ ãã¸ã§ãã®æ°ã ãåå²è¨ç®ããæçµçãªéè¨ã¯128ã®è¦ç´ ãèããã°è¯ãï¼ãããBurstã«ããæé©åãå¹ããããæ§é ï¼ãªã®ã§ãã¾ãæªãã¯ãªãããªã¨è¨ãèªèã§ããã¯ã¼ã«ã¼ã¹ã¬ããã®çªå·ãåå¾ã§ããã°ããã¡ãã£ã¨ç´å¾è¡ãæãã§ã¯ããã¾ããã
ã³ã¼ã
using UnityEngine; using Unity.Jobs; using Unity.Jobs.LowLevel.Unsafe; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Burst; public class PositionUpdateSystem : MonoBehaviour { JobHandle handle; void OnDestroy() { handle.Complete(); } void Update() { handle.Complete(); var array = new NativeArray<int>(JobsUtility.MaxJobThreadCount, Allocator.TempJob); var counter = new NativeArray<int>(1, Allocator.TempJob); handle = new CountJob { array = array }.Schedule(24576, 8); handle = new GatherJob { array = array, counter = counter }.Schedule(handle); handle = new LogJob { counter = counter }.Schedule(handle); array.Dispose(handle); counter.Dispose(handle); JobHandle.ScheduleBatchedJobs(); } [BurstCompile] struct CountJob : IJobParallelFor { [NativeSetThreadIndex] int threadIndex; [NativeDisableContainerSafetyRestriction] public NativeArray<int> array; public void Execute(int index) { var count = array[threadIndex]; count = count + 1; array[threadIndex] = count; } } [BurstCompile] struct GatherJob : IJob { [ReadOnly] public NativeArray<int> array; [WriteOnly] public NativeArray<int> counter; public void Execute() { var count = 0; for (int index = 0; index < array.Length; index++) { count = count + array[index]; } counter[0] = count; } } struct LogJob : IJob { [ReadOnly] public NativeArray<int> counter; public void Execute() { Debug.Log(counter[0]); } } }
ææ³
NativeQueueã®NativeArrayå¤æããNativeListã®ä¸¦åæ¸è¾¼ã使ããã°æ¥½ãªãã§ãã⦠UnsafeList
åãåã«ã¯æå¾
ãã¦ãããï¼æªæ¤è¨¼
ãUnityãJobSystemã使ãã¯ã¼ã«ã¼ã¹ã¬ããã®æ°ãå¶éãã
ãã¶ãUnity 2019.3
ãããã¯ã¼ã«ã¼ã¹ã¬ããã®æ°ãå¶éåºæ¥ãããã«ãªã£ãã£ã½ãã§ãã
ã¯ã¼ã«ã¼ã¹ã¬ããã®æ°ãå¶éãã
Unityã®JobSystemã¯åºæ¬çã«ã使ç¨ã§ããå
¨ã¦ã®ã¹ã¬ããã使ç¨ããã¾ããããã¯ä¾ãã°ã²ã¼ã æ©ãã³ã¢ãï¼ï½ï¼åå°æãã¦ãã¾ã£ã¦ãããããããã¯ä½ããã®ã·ã¹ãã ãã¹ã¬ãããä¸ã¤å°æãã¦ãã¾ãå ´åã§ãåæ§ã§ãã
ãããªãã¨ä½¿ç¨ä¸ã«ã®ã¹ã¬ããã«ã¸ã§ããä¾é ¼ããå½¢ã«ãªãã®ã§ãã³ã³ããã¹ãã¹ã¤ãããçºçããå¹çãä½ä¸ãã¾ãã
ã¸ã§ãã®åä½æ°ãå¶éããå ´åJobsUtility.JobWorkerCount
ã使ç¨ãã¾ããããã§ã¸ã§ããçºçããæ°ãå¶éåºæ¥ã¾ããä¾ãã°ä¸ã®ããã«è¨è¿°ããã°ãã¸ã§ããå²ãæ¯ãæ°ã¯å¶éããã¾ãã
using Unity.Jobs.LowLevel.Unsafe; ï¼ä¸ç¥ï¼ void Awake() { JobsUtility.JobWorkerCount = 2; }
å®éã®åä½ã¯ä¸ã®ãããªæãã§ããå·¦ãé常ã®ã¸ã§ãã§ãå³ãWorkerã®æ°ãå¶éããå ´åã§ããã¸ã§ããå¦çãã¦ããã¯ã¼ã«ã¼ã¹ã¬ããã®æ°ãæ¸ã£ã¦ããäºã確èªåºæ¥ã¾ãã
ã¯ã¼ã«ã¼ã¹ã¬ããã®æ°
ã¯ã¼ã«ã¼ã¹ã¬ããã®æ°ã§ããããã¼ãã³ã¼ãã£ã³ã°ã§è¨è¿°ããã«ã¯ã²ã¼ã ã®ç°å¢ã¯è¤éã«éãã¾ããä¾ãã°ã¢ãã¤ã«ã®ã³ã¢æ°ã¯æ¢ã«ï¼ã ããAMDã®CPUã¯32åï¼64ã¹ã¬ããï¼ã§ããã³ã¢æ°ã¯ç¾ç¶ãããä¸æããããé ç®ãªã®ã§ããã®ã¾ã¾ä½¿ãã®ã¯è¾ããã§ãã
ã¨ããããèªåçã«ã¯ JobsUtility.JobWorkerMaximumCount
ãã-1ï½-2辺ãããã®ãè¯ãããã«è¦ãã¾ãããå®éã«ã©ã®ç¨åº¦æ¸ããã®ãã¯ä»ã®ã¹ã¬ãããã©ã®ç¨åº¦ä½¿ç¨ãã¦ããã®ãã«ä¾åãããã§ãã
ãUnityãä½ãã¬ã¼ã ã¬ã¼ãã§ããããããªå ¥åãåãåããã
InputManagerã§ã¯å
¥åæ
å ±ã¯ãã¬ã¼ã ã¬ã¼ãã«å¼·ãä¾åãã¦ããããã®ä¸éã§åå¾ããæ
å ±ã®å¤§æµã¯ç ´æ£ããã¦ãã¾ããã
InputSystemã§ã¯ä¸éã®æ
å ±ããããã¡ã¨ãã¦ç¢ºä¿ã»ä½¿ç¨ã§ããããã«ãªã£ãã®ã§ãããã使ç¨ãã¦ãã¬ã¼ã ãä½ãã¦ããã¬ã¤ãªç·ãå¼ããæ¹æ³ãèãã¦ã¿ã¾ãã
ãªãåä½ã¯OSã®åä½ã«å¼·ãä¾åãã¾ãã
åä½ç°å¢ï¼Unity 2018.3 b12
ã Input System 1.0 preview
å®éã®åä½
ã¾ãæ®éã«ä½ãã¬ã¼ã ã¬ã¼ãç°å¢ä¸ã§InputManagerã使ç¨ãã¦ãã¦ã¹ã®ä½ç½®ã追跡ãã¦ç·ãå¼ããããªã³ã¼ããå®è£
ããå ´åãä¸ã®ãããªå½¢ã«ãªãã¾ãã
åä½ã§ã¯ããã¦ã¹ã¯æ»ããã«åãæãå½¢ã§åãã¦ãã¾ãããç·ã¯é常ã«è§å¼µã£ãå½¢ã§æç»ããã¦ãã¾ããããã¯ãã¦ã¹ã®åº§æ¨ãåå¾ããééãåºãããã«èµ·ããã¾ãã
InputSystemã使ç¨ããå ´åã¯ã³ãã©ããã¡ãããã¬ã¼ã ã¬ã¼ããè½ã¨ãã¦ãã¾ããå ¥åæ å ±ã¯ãã¬ã¤ã«è£å®ããã¦ãããã¡ããã¨æ²ç·ãæãã¦ããäºã確èªåºæ¥ã¾ããï¼ãã¬ã¼ã ã«è¤æ°åã®å ¥åãåãåããã¨ããèªèãä¸çªèªèããããæ¦å¿µã§ãã
ã³ã¼ãå ¨æ
InputManagerã®å ´å
ã¾ãæåã«ãInputManagerã使ç¨ããã³ã¼ãã§ããæ®éã«ä½ç½®æ å ±ãåå¾ããæç»ãä¾é ¼ããã³ã³ãã¼ãã³ãã«æ å ±ã渡ãã¾ããç´°ããã³ã¼ãã¯ä¸ã®å ¨æãè¦ã¦ãã ããã
// GetInput3.cs void Update() { var pos = Input.mousePosition; line.AddPosition(pos); // 座æ¨ãæ³¨å ¥ }
InputSystemã§ãã¦ã¹ã®ä½ç½®ãåå¾ãã
InputSystemã§mousePositionãåå¾ããã³ã¼ãã§ããããã¯ã¾ã InputManagerã¨åããããªåãããã¾ãã
void Update() { var pos = Mouse.current.position.ReadValue(); // ãã¦ã¹ã®ä½ç½®ãåå¾ line.AddPosition(pos); }
InputSystemã§ãããã¡ã使ç¨ãã¦åå¾ãã
ãããã¡ã使ç¨ãã¦åå¾ãã¾ããããã§ã¯ InputStateHistory
ã使ç¨ãã¾ãã
ãã®ã¢ããã¼ãã§ã¯ä¸éãããã¡ãè£å®ãã¦ããã®ã§ãæ»ãããªç·ãå¼ãã¾ãã
ãªããããã¡ã¯newããå°ç¹ã§ç¢ºä¿ãããã®ã§ãèªåã§éæ¾ãè¡ããªãã¨ã¡ã¢ãªãªã¼ã¯ãèµ·ããã¾ãã
InputStateHistory history; void Awake() { history = new InputStateHistory<Vector2>(Mouse.current.position); //ãã¦ã¹ã®ä½ç½®ã観測 } void OnDestroy() { history.Dispose(); // ç¡å¹ãããã¯ç ´æ£ã®ã¿ã¤ãã³ã°ã§å¿ ãéæ¾ } void OnEnable() => history.StartRecording(); // ãããã¡ãã¬ã³ã¼ãéå§ void OnDisable() => history.StopRecording(); // ãããã¡ãã¬ã³ã¼ãçµäº void Update() { foreach( var record in history) { var pos = record.ReadValue<Vector2>(); line.AddPosition(pos); } history.Clear(); // ä»åã®åã®ãããã¡ã¯éæ¾ }
InputActionã使ç¨ããï¼ãã¼ãªã³ã°ï¼
InputActionã®ãã¼ãªã³ã°ã使ç¨ãã¦ã¿ã¾ããã¤ã¾ã InputActionTrace
ã使ç¨ãã¾ãã
äºåæºåã¨ãã¦InputActionã«Position
ããã®Controlã«ã¯MousePositionãå
¥ãã¾ããããã¯Touchãå§ãã¨ããä»ã®Controlã§ãè¯ãã§ãã
ãããPlayerInputã«è¨å®ãã»ããã¢ãããã¦ããããGetComponent<PlayerInput>().currentActionMap["Position"];
ã§InputActionãåå¾ã»ä½¿ç¨ãã¾ãã
private InputAction inputAction; private InputActionTrace trace; void Awake() { inputAction = GetComponent<PlayerInput>().currentActionMap["Position"]; trace = new InputActionTrace(); } void OnDestroy() { trace.Dispose(); } void OnEnable() => trace.SubscribeTo(inputAction); // 観測éå§ void OnDisable() => trace.UnsubscribeFrom(inputAction); // 観測çµäº void Update() { foreach (var record in trace) // 観測å 容ããä¸ã¤ãã¤åãåºãã¦å¦ç { var v = record.ReadValue<Vector2>(); line.AddPosition(v); } trace.Clear(); }
ã¤ãã³ãé§å
ä¸ã®ã¤ãã³ãé§åããå ´åã§ããUpdateãæ¸ããªãã¦ãè¯ãã¨ããåé¢ãï¼ãã¬ã¼ã ã«åãå¦çãè¤æ°åå¼ã°ããæã®å¯¾çãå°ãé¢åã¨ããã°é¢åããããã¾ããã
private DrawLine line; private InputAction inputAction; void Awake() { inputAction = GetComponent<PlayerInput>().currentActionMap["Position"]; } void OnEnable() => inputAction.performed += Input_performed; void OnDisable() => inputAction.performed -= Input_performed; void Input_performed(InputAction.CallbackContext c) { var v = c.ReadValue<Vector2>(); line.AddPosition(v); }
ãã¼ãªã³ã°ã®é »åº¦
å
¥åã¤ãã³ãããã¼ãªã³ã°ããã¿ã¤ãã®ããã¤ã¹ã®å ´åããã¼ãªã³ã°ã®é »åº¦ãInputSystem.pollingFrequency
ã§è¨å®ã§ãã¾ããåæå¤ã¯60Hzï¼1ç§éã«60åãã§ãã¯ï¼ã§ããããä¸ãããä¸ããããããã¨ã§å
¥åã¤ãã³ãã®ãµã³ããªã³ã°ç²¾åº¦ãä¸ãããåºæ¥ã¾ãã
ãã ä¸ããããã¨ï¼1000ã¨ãï¼ã¨ãã£ã¿ã¼ãã¨è½ã¡ãäºããã£ãã®ã§æ³¨æãå¿ è¦ããããã¾ãããã¾ãå¹¾ã¤ãã®ããã¤ã¹ã¯ãã¼ãªã³ã°ããå½¢ã§ã¯ãªãOSããã®å ¥åãåãåãã¿ã¤ããªã®ã§ããã®APIã¯åä½ãã¾ããã