@@ -1,6 +1,4 @@
using System.Collections;
using System.Collections.Generic;
using Unity.Entities;
using Unity.Entities;
using UnityEngine;
using UnityEngine.UI;

Expand All @@ -9,22 +7,24 @@ namespace Samples.FixedTimestepSystem
// NOTE: Updating a manually-created system in FixedUpdate() as demonstrated below
// is intended as a short-term workaround; the entire `SimulationSystemGroup` will
// eventually use a fixed timestep by default.
[AddComponentMenu("DOTS Samples/FixedTimestepWorkaround/Fixed Timestep Updater")]
public class FixedTimestepUpdater : MonoBehaviour
{
private FixedRateSpawnerSystem spawnerSystem;
FixedRateSpawnerSystem spawnerSystem;
public Slider fixedTimestepSlider;

private Text sliderLabelText;
private void Start()
Text sliderLabelText;

void Start()
{
sliderLabelText = fixedTimestepSlider.GetComponentInChildren<Text>();
}

private void FixedUpdate()
void FixedUpdate()
{
if (spawnerSystem == null)
{
spawnerSystem = World.Active.GetOrCreateSystem<FixedRateSpawnerSystem>();
spawnerSystem = World.DefaultGameObjectInjectionWorld.GetOrCreateSystem<FixedRateSpawnerSystem>();
}
Time.fixedDeltaTime = fixedTimestepSlider.value;
sliderLabelText.text = $"Fixed Timestep: {fixedTimestepSlider.value*1000} ms";
Expand Down
Expand Up @@ -43,7 +43,7 @@ protected override JobHandle OnUpdate(JobHandle inputDependencies)
var jobHandle = new MoveProjectileJob()
{
Commands = m_beginSimEcbSystem.CreateCommandBuffer().ToConcurrent(),
TimeSinceLoad = Time.timeSinceLevelLoad,
TimeSinceLoad = (float)Time.ElapsedTime,
ProjectileSpeed = 5.0f,
}.Schedule(this, inputDependencies);
m_beginSimEcbSystem.AddJobHandleForProducer(jobHandle);
Expand Down
@@ -1,11 +1,12 @@
using System;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;

namespace Samples.FixedTimestepSystem.Authoring
{
[RequiresEntityConversion]
[AddComponentMenu("DOTS Samples/FixedTimestepWorkaround/Projectile Spawn Time")]
[ConverterVersion("joe", 1)]
public class ProjectileSpawnTimeAuthoring : MonoBehaviour, IConvertGameObjectToEntity
{
public float SpawnTime;
Expand Down
Expand Up @@ -16,7 +16,7 @@ protected override void OnUpdate()
{
Entities.ForEach((Entity spawnerEntity, ref VariableRateSpawner spawnerData, ref Translation translation) =>
{
var spawnTime = Time.timeSinceLevelLoad;
var spawnTime = (float)Time.ElapsedTime;
var newEntity = PostUpdateCommands.Instantiate(spawnerData.Prefab);
PostUpdateCommands.AddComponent(newEntity, new Parent {Value = spawnerEntity});
PostUpdateCommands.AddComponent(newEntity, new LocalToParent());
Expand Down
Expand Up @@ -4,6 +4,8 @@

namespace Samples.FixedTimestepSystem.Authoring
{
[AddComponentMenu("DOTS Samples/FixedTimestepWorkaround/Variable Rate Spawner")]
[ConverterVersion("joe", 1)]
public class VariableRateSpawnerAuthoring : MonoBehaviour, IConvertGameObjectToEntity, IDeclareReferencedPrefabs
{
public GameObject projectilePrefab;
Expand Down
110 changes: 110 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Assets/BasicActor0.prefab
@@ -0,0 +1,110 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &5504584424357794562
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8677578845857320225}
- component: {fileID: 7241256591259727247}
- component: {fileID: 2166536328003235753}
- component: {fileID: 3139632156233265087}
- component: {fileID: 8085697106929772112}
m_Layer: 0
m_Name: BasicActor
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8677578845857320225
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5504584424357794562}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -5.672221, y: -6.2789955, z: -2.8151016}
m_LocalScale: {x: 0.75, y: 0.75, z: 0.75}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &7241256591259727247
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5504584424357794562}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ea7d7495833204790ba1d3a8755397f8, type: 3}
m_Name:
m_EditorClassIdentifier:
ConversionMode: 0
--- !u!33 &2166536328003235753
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5504584424357794562}
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &3139632156233265087
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5504584424357794562}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 23ccc3c97967842c9a200f16adfbc5ec, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
--- !u!114 &8085697106929772112
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5504584424357794562}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ede02fc5d83e4273ad9b2b008f644a5a, type: 3}
m_Name:
m_EditorClassIdentifier:
Version: 3-macton
Speed: 1.53
@@ -0,0 +1,81 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &1103163340165250616
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 5504584424357794562, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_Name
value: BasicActor1 Variant
objectReference: {fileID: 0}
- target: {fileID: 8677578845857320225, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_LocalPosition.x
value: -5.672221
objectReference: {fileID: 0}
- target: {fileID: 8677578845857320225, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_LocalPosition.y
value: -6.2789955
objectReference: {fileID: 0}
- target: {fileID: 8677578845857320225, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_LocalPosition.z
value: -2.8151016
objectReference: {fileID: 0}
- target: {fileID: 8677578845857320225, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8677578845857320225, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8677578845857320225, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8677578845857320225, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8677578845857320225, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8677578845857320225, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8677578845857320225, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8677578845857320225, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3139632156233265087, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: 4d06670ed47f24eeeba3aeb4c73e0200, type: 2}
- target: {fileID: 8085697106929772112, guid: 185fc72fe6b8347aa833fe241a0dd4de,
type: 3}
propertyPath: Speed
value: 1.93
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 185fc72fe6b8347aa833fe241a0dd4de, type: 3}
@@ -1,71 +1,74 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &6569687701493165383
--- !u!1 &6226756458611596980
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7115010737409291896}
- component: {fileID: 2488643566923045792}
- component: {fileID: 969718961144326305}
- component: {fileID: 798989487309328685}
- component: {fileID: 6226756458611596987}
- component: {fileID: 6226756458611596984}
- component: {fileID: 6226756458611596985}
- component: {fileID: 6226756458611596982}
- component: {fileID: 6226756458611596983}
m_Layer: 0
m_Name: Cube
m_Name: BasicCube
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7115010737409291896
--- !u!4 &6226756458611596987
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6569687701493165383}
m_GameObject: {fileID: 6226756458611596980}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalPosition: {x: -14.746666, y: -15.219937, z: -33.825005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &2488643566923045792
--- !u!33 &6226756458611596984
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6569687701493165383}
m_GameObject: {fileID: 6226756458611596980}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &969718961144326305
--- !u!23 &6226756458611596985
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6569687701493165383}
m_GameObject: {fileID: 6226756458611596980}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 3dfacc7ecb012ea42adb62ff8edfc9d5, type: 2}
- {fileID: 2100000, guid: bb82fc45cfd314c8cbbbb74aff1f2e17, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
Expand All @@ -78,16 +81,29 @@ MeshRenderer:
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
--- !u!65 &798989487309328685
--- !u!65 &6226756458611596982
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6569687701493165383}
m_GameObject: {fileID: 6226756458611596980}
m_Material: {fileID: 0}
m_IsTrigger: 0
m_Enabled: 1
serializedVersion: 2
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!114 &6226756458611596983
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6226756458611596980}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ea7d7495833204790ba1d3a8755397f8, type: 3}
m_Name:
m_EditorClassIdentifier:
ConversionMode: 0
76 changes: 76 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Assets/BasicCube1.prefab
@@ -0,0 +1,76 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &1816190819034052895
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 7357677057927616873, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_Name
value: BasicCube1
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616870, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_LocalPosition.x
value: -14.746666
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616870, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_LocalPosition.y
value: -15.219937
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616870, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_LocalPosition.z
value: -33.825005
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616870, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616870, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616870, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616870, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616870, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616870, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616870, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616870, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7357677057927616868, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd,
type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: 32bf30f90a6a049be8fb2aca13ddebb6, type: 2}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd, type: 3}
76 changes: 76 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Assets/BasicCube2.prefab
@@ -0,0 +1,76 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &3490951956845348829
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 6226756458611596980, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_Name
value: BasicCube1 Variant
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596987, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_LocalPosition.x
value: -14.746666
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596987, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_LocalPosition.y
value: -15.219937
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596987, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_LocalPosition.z
value: -33.825005
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596987, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596987, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596987, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596987, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596987, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596987, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596987, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596987, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6226756458611596985, guid: fa9e694a0208e45c48a1c607230cd068,
type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: 23605a7b696764d3cb15e0ab0ee1dba4, type: 2}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: fa9e694a0208e45c48a1c607230cd068, type: 3}
@@ -0,0 +1,81 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &2065233747843748173
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 9164789646436638838, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_Name
value: CornerCube Variant
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638841, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_LocalPosition.x
value: -14.746666
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638841, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_LocalPosition.y
value: -15.219937
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638841, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_LocalPosition.z
value: -33.825005
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638841, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638841, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638841, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638841, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638841, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638841, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638841, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638841, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 9164789646436638843, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: be7dd83f5567e4afea648cc7dfa2c12e, type: 2}
- target: {fileID: 9164789646436638836, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
propertyPath: m_Size.x
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: b744ba11cc6514157956bc6d96f6beaa, type: 3}
8 changes: 8 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scenes.meta
8 changes: 8 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scenes/GridCube.meta
596 changes: 596 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scenes/GridCube.unity

Large diffs are not rendered by default.

Expand Up @@ -38,30 +38,31 @@ RenderSettings:
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0.12731749, g: 0.13414757, b: 0.1210787, a: 1}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 11
m_GIWorkflowMode: 0
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 10
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
Expand All @@ -74,20 +75,28 @@ LightmapSettings:
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVRFilteringMode: 1
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ShowResolutionOverlay: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_UseShadowmask: 1
--- !u!196 &4
Expand All @@ -112,59 +121,53 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &1841332243
--- !u!1 &235473809
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1841332245}
- component: {fileID: 1841332244}
- component: {fileID: 235473811}
- component: {fileID: 235473810}
m_Layer: 0
m_Name: SceneSwitcher
m_Name: Grid
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1841332244
--- !u!114 &235473810
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1841332243}
m_GameObject: {fileID: 235473809}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5db787c63c8124a7291c505ceeb02ceb, type: 3}
m_Script: {fileID: 11500000, guid: 7238b95470734819b4a9ba11900739a2, type: 3}
m_Name:
m_EditorClassIdentifier:
SceneSwitchInterval: 20
TimeUntilNextSwitch: 5
CurrentSceneIndex: 0
EntitiesDestroyed: 0
SceneConfigs:
- SceneName: BoidExample
CustomDuration: 10
- SceneName: HelloCubeRotationSpeed
CustomDuration: 5
- SceneName: Hello2Cubes
CustomDuration: 5
- SceneName: HelloSpawnACube
CustomDuration: 5
- SceneName: HelloSpawnMoreStuff
CustomDuration: 5
--- !u!4 &1841332245
Version: 4-macton-2
RowCount: 32
FloorPrefab:
- {fileID: 6226756458611596980, guid: fa9e694a0208e45c48a1c607230cd068, type: 3}
- {fileID: 7357677057927616873, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd, type: 3}
WallPrefab: {fileID: 9164789646436638838, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
WallSProbability: 0.33
WallWProbability: 0.33
--- !u!4 &235473811
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1841332243}
m_GameObject: {fileID: 235473809}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 48.69622, y: 34.48973, z: 85.32182}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
Expand Down
8 changes: 8 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scenes/GridPlane.meta
472 changes: 472 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scenes/GridPlane.unity

Large diffs are not rendered by default.

176 changes: 176 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scenes/GridPlane/Grid.unity
@@ -0,0 +1,176 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 11
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_UseShadowmask: 1
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &1138643408
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1138643410}
- component: {fileID: 1138643409}
m_Layer: 0
m_Name: Grid
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1138643409
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1138643408}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d3b7dec172b34d219fd0799d314645e5, type: 3}
m_Name:
m_EditorClassIdentifier:
Version: 4-macton-9
ColumnCount: 128
RowCount: 32
FloorPrefab:
- {fileID: 6226756458611596980, guid: fa9e694a0208e45c48a1c607230cd068, type: 3}
- {fileID: 7357677057927616873, guid: ce1bdd9c4ca1c4a1a9da4ac00b6db6cd, type: 3}
WallPrefab: {fileID: 9164789646436638838, guid: b744ba11cc6514157956bc6d96f6beaa,
type: 3}
WallSProbability: 0.25
WallWProbability: 0.25
--- !u!4 &1138643410
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1138643408}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -1.4750153, y: 1.7389027, z: 3.6991482}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
8 changes: 8 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scripts.meta
284 changes: 284 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scripts/GridAuthoringUtility.cs
@@ -0,0 +1,284 @@
using System.Collections.Generic;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Rendering;
using Unity.Transforms;
using UnityEngine;
using Hash128 = UnityEngine.Hash128;

public static class GridAuthoringUtility
{
public enum WallFlags : byte
{
SouthWall = 1,
WestWall = 2,
}

public static void CreateGridPath(int rowCount, int columnCount, NativeArray<GridWalls> gridWalls, float wallSProbability, float wallWProbability, bool outerWalls)
{
var buildGridPathJob = new BuildGridPath
{
GridWalls = gridWalls,
RowCount = rowCount,
ColumnCount = columnCount,
WallSProbability = wallSProbability,
WallWProbability = wallWProbability,
OuterWalls = outerWalls
};
buildGridPathJob.Run();
}

public static void AddTrailingOffsets(EntityManager dstManager, Entity entity, int rowCount, int columnCount)
{
var cx = (columnCount * 0.5f);
var cz = (rowCount * 0.5f);

// Trailing offset so something is not considered "in" a grid section until it is
// *completely* in that grid section. So no check needs to be done to see if it is at
// the center of the grid for correct turning timing. As soon as it's in the grid, it must
// be in the right place to decide on new direction.
var trailingOffsets = new NativeArray<GridTrailingOffset>(4, Allocator.Temp);
trailingOffsets[0] = new GridTrailingOffset { Value = new float2( cx + 0.0f, cz + -0.5f ) }; // North
trailingOffsets[1] = new GridTrailingOffset { Value = new float2( cx + 0.0f, cz + 0.5f ) }; // South
trailingOffsets[2] = new GridTrailingOffset { Value = new float2( cx + 0.5f, cz + 0.0f ) }; // West
trailingOffsets[3] = new GridTrailingOffset { Value = new float2( cx + -0.5f, cz + 0.0f ) }; // East

var gridTrailingOffsetBuffer = dstManager.AddBuffer<GridTrailingOffset>(entity);
gridTrailingOffsetBuffer.AddRange(trailingOffsets);
trailingOffsets.Dispose();
}

[BurstCompile]
struct BuildGridPath : IJob
{
public NativeArray<GridWalls> GridWalls;
public int RowCount;
public int ColumnCount;
public float WallSProbability;
public float WallWProbability;
public bool OuterWalls;

public void Execute()
{
var cx = (ColumnCount * 0.5f);
var cz = (RowCount * 0.5f);

// Add additional row/col to create SE walls along outer edge
var GridWallsRowCount = RowCount + 1;
var GridWallsColumnCount = ColumnCount + 1;

// 2 bit (0=None, 1=South Wall, 2=West Wall)
var GridWallsSW = new NativeArray<byte>(GridWallsRowCount * GridWallsColumnCount, Allocator.Temp);

// Populate the grid
for (int y = 0; y < GridWallsRowCount; y++)
for (int x = 0; x < GridWallsColumnCount; x++)
{
// By default place outer walls along the edge of the grid.
if ((y == 0) && (x < (GridWallsColumnCount - 1)))
GridWallsSW[(y * GridWallsColumnCount) + x] |= (byte)WallFlags.SouthWall;
if ((x == 0) && (y < (GridWallsRowCount - 1)))
GridWallsSW[(y * GridWallsColumnCount) + x] |= (byte)WallFlags.WestWall;
if ((y == (GridWallsRowCount - 1)) && (x < (GridWallsColumnCount - 1)))
GridWallsSW[(y * GridWallsColumnCount) + x] |= (byte)WallFlags.SouthWall;
if ((x == (GridWallsColumnCount - 1)) && (y < (GridWallsRowCount - 1)))
GridWallsSW[(y * GridWallsColumnCount) + x] |= (byte)WallFlags.WestWall;

if ((x < (GridWallsColumnCount - 1)) && (y < (GridWallsRowCount - 1)))
{
var tx = ((float)x) - cx;
var tz = ((float)y) - cz;

var n0 = noise.snoise(new float2(tx * 1.2345f, tz * 1.2345f));
var n1 = noise.snoise(new float2(tz * 1.6789f, tx * 1.6789f));

if (((n0 * 0.5f) + 0.5f) < WallSProbability)
GridWallsSW[(y * GridWallsColumnCount) + x] |= (byte)WallFlags.SouthWall;
if (((n1 * 0.5f) + 0.5f) < WallWProbability)
GridWallsSW[(y * GridWallsColumnCount) + x] |= (byte)WallFlags.WestWall;
}

// Make sure there are no outer walls along the edge of the grid
if (!OuterWalls)
{
if (x == 0)
GridWallsSW[(y * GridWallsColumnCount) + x] &= (byte)~WallFlags.WestWall;
if (x == (GridWallsColumnCount - 1))
GridWallsSW[(y * GridWallsColumnCount) + x] &= (byte)~WallFlags.WestWall;
if (y == (GridWallsRowCount - 1))
GridWallsSW[(y * GridWallsColumnCount) + x] &= (byte)~WallFlags.SouthWall;
if (y == 0)
GridWallsSW[(y * GridWallsColumnCount) + x] &= (byte)~WallFlags.SouthWall;
}
}

for (int y = 0; y < RowCount; y++)
for (int x = 0; x < ColumnCount; x++)
{
var wallN = ((GridWallsSW[((y + 1) * GridWallsColumnCount) + x] & (byte)WallFlags.SouthWall) != 0);
var wallS = ((GridWallsSW[(y * GridWallsColumnCount) + x] & (byte)WallFlags.SouthWall) != 0);
var wallW = ((GridWallsSW[(y * GridWallsColumnCount) + x] & (byte)WallFlags.WestWall) != 0);
var wallE = ((GridWallsSW[(y * GridWallsColumnCount) + (x + 1)] & (byte)WallFlags.WestWall) != 0);
var walls = ((wallN) ? 0x01 : 0x00)
| ((wallS) ? 0x02 : 0x00)
| ((wallW) ? 0x04 : 0x00)
| ((wallE) ? 0x08 : 0x00);

var gridWallIndex = (y * ((ColumnCount+1)/2)) + (x / 2);
walls <<= (x & 1) * 4; // odd columns packed into upper 4 bits
walls |= GridWalls[gridWallIndex].Value;
GridWalls[gridWallIndex] = new GridWalls { Value = (byte)walls };
}
}
}

public static void CreateFloorPanel(EntityManager dstManager, GameObjectConversionSystem conversionSystem, GameObject gameObject, GameObject prefab, float4x4 parentLocalToWorld, float tx, float tz)
{
var pos = new float3(tx + 0.5f, 0.0f, tz + 0.5f);
var childLocalToParent = math.mul(float4x4.Translate(pos), float4x4.Scale(0.98f));
var localToWorld = new LocalToWorld
{
Value = math.mul(parentLocalToWorld,childLocalToParent)
};

CreatePanel(dstManager, conversionSystem, gameObject, prefab, localToWorld);
}

public static void CreateWallS(EntityManager dstManager, GameObjectConversionSystem conversionSystem, GameObject gameObject, GameObject prefab, float4x4 parentLocalToWorld, float tx, float tz)
{
var pos = new float3(tx + 0.5f, 1.0f, tz);
var childLocalToParent = math.mul(float4x4.Translate(pos), float4x4.Scale(1.1f, 1.1f, 0.1f));
var localToWorld = new LocalToWorld
{
Value = math.mul(parentLocalToWorld,childLocalToParent)
};

CreatePanel(dstManager, conversionSystem, gameObject, prefab, localToWorld);
}

public static void CreateWallW(EntityManager dstManager, GameObjectConversionSystem conversionSystem, GameObject gameObject, GameObject prefab, float4x4 parentLocalToWorld, float tx, float tz)
{
var pos = new float3(tx, 1.0f, tz + 0.5f);
var childLocalToParent = math.mul(float4x4.Translate(pos), float4x4.Scale(0.1f, 1.1f, 1.1f));
var localToWorld = new LocalToWorld
{
Value = math.mul(parentLocalToWorld,childLocalToParent)
};

CreatePanel(dstManager, conversionSystem, gameObject, prefab, localToWorld);
}

public static void CreatePanel(EntityManager dstManager, GameObjectConversionSystem conversionSystem, GameObject gameObject, GameObject prefab, LocalToWorld localToWorld)
{
var meshRenderer = prefab.GetComponent<MeshRenderer>();
var meshFilter = prefab.GetComponent<MeshFilter>();
var materials = new List<Material>(10);
var mesh = meshFilter.sharedMesh;
meshRenderer.GetSharedMaterials(materials);

var segmentEntity = conversionSystem.CreateAdditionalEntity(gameObject);
var pos = localToWorld.Position;

var renderBounds = new RenderBounds
{
Value = new AABB
{
Center = new float3(0.0f, 0.0f, 0.0f),
Extents = new float3(0.5f, 0.5f, 0.5f)
}
};
var worldRenderBounds = new WorldRenderBounds
{
Value = new AABB
{
Center = pos,
Extents = new float3(0.5f, 0.5f, 0.5f)
}
};
var frozenRenderSceneTag = new FrozenRenderSceneTag
{
HasStreamedLOD = 0,
SceneGUID = Hash128.Compute("Grid Panel"),
SectionIndex = 0
};

#if UNITY_EDITOR
dstManager.SetName(segmentEntity, "Grid Panel");
#endif
dstManager.AddComponentData(segmentEntity, localToWorld);
dstManager.AddComponentData(segmentEntity, renderBounds);

dstManager.AddComponentData(segmentEntity, worldRenderBounds);
dstManager.AddSharedComponentData(segmentEntity, frozenRenderSceneTag);
dstManager.AddComponent(segmentEntity, typeof(Static));

CreateRenderMesh(segmentEntity, dstManager, conversionSystem, meshRenderer, mesh, materials);
}

static void CreateRenderMesh( Entity entity, EntityManager dstEntityManager, GameObjectConversionSystem conversionSystem, Renderer meshRenderer, Mesh mesh, List<Material> materials)
{
var materialCount = materials.Count;

// Don't add RenderMesh (and other required components) unless both mesh and material assigned.
if ((mesh != null) && (materialCount > 0))
{
var renderMesh = new RenderMesh
{
mesh = mesh,
castShadows = meshRenderer.shadowCastingMode,
receiveShadows = meshRenderer.receiveShadows,
layer = meshRenderer.gameObject.layer
};

//@TODO: Transform system should handle RenderMeshFlippedWindingTag automatically. This should not be the responsibility of the conversion system.
float4x4 localToWorld = meshRenderer.transform.localToWorldMatrix;
var flipWinding = math.determinant(localToWorld) < 0.0;

if (materialCount == 1)
{
renderMesh.material = materials[0];
renderMesh.subMesh = 0;

dstEntityManager.AddSharedComponentData(entity, renderMesh);

dstEntityManager.AddComponentData(entity, new PerInstanceCullingTag());
dstEntityManager.AddComponentData(entity, new RenderBounds { Value = mesh.bounds.ToAABB() });

if (flipWinding)
dstEntityManager.AddComponent(entity, ComponentType.ReadWrite<RenderMeshFlippedWindingTag>());

conversionSystem.ConfigureEditorRenderData(entity, meshRenderer.gameObject, true);
}
else
{
for (var m = 0; m != materialCount; m++)
{
var meshEntity = conversionSystem.CreateAdditionalEntity(meshRenderer);

renderMesh.material = materials[m];
renderMesh.subMesh = m;

dstEntityManager.AddSharedComponentData(meshEntity, renderMesh);

dstEntityManager.AddComponentData(meshEntity, new PerInstanceCullingTag());
dstEntityManager.AddComponentData(meshEntity, new RenderBounds { Value = mesh.bounds.ToAABB() });
dstEntityManager.AddComponentData(meshEntity, new LocalToWorld { Value = localToWorld });

if (!dstEntityManager.HasComponent<Static>(meshEntity))
{
dstEntityManager.AddComponentData(meshEntity, new Parent { Value = entity });
dstEntityManager.AddComponentData(meshEntity, new LocalToParent { Value = float4x4.identity });
}

if (flipWinding)
dstEntityManager.AddComponent(meshEntity, ComponentType.ReadWrite<RenderMeshFlippedWindingTag>());

conversionSystem.ConfigureEditorRenderData(meshEntity, meshRenderer.gameObject, true);
}
}
}
}
}
162 changes: 162 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scripts/GridCubeAuthoring.cs
@@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;

// ReSharper disable once InconsistentNaming
[RequiresEntityConversion]
[AddComponentMenu("DOTS Samples/GridPath/Grid Cube")]
[ConverterVersion("joe", 1)]
public class GridCubeAuthoring : MonoBehaviour, IConvertGameObjectToEntity, IDeclareReferencedPrefabs
{
[Range(2, 512)]
public int RowCount;
public GameObject[] FloorPrefab;
public GameObject WallPrefab;

// Specific wall probability, given PotentialWallProbability
public float WallSProbability = 0.5f;
public float WallWProbability = 0.5f;


static readonly float4x4[] m_FaceLocalToWorldRotation =
{
new float4x4(
new float4(0.00f, -1.00f, 0.00f, 0.00f),
new float4(1.00f, 0.00f, 0.00f, 0.00f),
new float4(0.00f, 0.00f, 1.00f, 0.00f),
new float4(0.00f, 0.00f, 0.00f, 1.00f)),
new float4x4(
new float4(0.00f, 1.00f, 0.00f, 0.00f),
new float4(-1.00f, 0.00f, 0.00f, 0.00f),
new float4(0.00f, 0.00f, 1.00f, 0.00f),
new float4(0.00f, 0.00f, 0.00f, 1.00f)),
new float4x4(
new float4(1.00f, 0.00f, 0.00f, 0.00f),
new float4(0.00f, 1.00f, 0.00f, 0.00f),
new float4(0.00f, 0.00f, 1.00f, 0.00f),
new float4(0.00f, 0.00f, 0.00f, 1.00f)),
new float4x4(
new float4(-1.00f, 0.00f, 0.00f, 0.00f),
new float4(0.00f, -1.00f, 0.00f, 0.00f),
new float4(0.00f, 0.00f, 1.00f, 0.00f),
new float4(0.00f, 0.00f, 0.00f, 1.00f)),
new float4x4(
new float4(1.00f, 0.00f, 0.00f, 0.00f),
new float4(0.00f, 0.00f, 1.00f, 0.00f),
new float4(0.00f, -1.00f, 0.00f, 0.00f),
new float4(0.00f, 0.00f, 0.00f, 1.00f)),
new float4x4(
new float4(1.00f, 0.00f, 0.00f, 0.00f),
new float4(0.00f, 0.00f, -1.00f, 0.00f),
new float4(0.00f, 1.00f, 0.00f, 0.00f),
new float4(0.00f, 0.00f, 0.00f, 1.00f)),
};

// Referenced prefabs have to be declared so that the conversion system knows about them ahead of time
public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
{
referencedPrefabs.Add(WallPrefab);
referencedPrefabs.AddRange(FloorPrefab);
}

public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
var floorPrefabCount = FloorPrefab.Length;
if (floorPrefabCount == 0)
return;

#if UNITY_EDITOR
dstManager.SetName(entity, "Grid");
#endif

var cx = (RowCount * 0.5f);
var cz = (RowCount * 0.5f);

var gridWallsBuffer = dstManager.AddBuffer<GridWalls>(entity);

var faceLocalToWorld = new NativeArray<FaceLocalToWorld>(6, Allocator.Temp);
var faceWorldToLocal = new NativeArray<FaceLocalToWorld>(6, Allocator.Temp);
var faceLocalToLocal = new NativeArray<FaceLocalToWorld>(6 * 6, Allocator.Temp);

for (int faceIndex = 0; faceIndex < 6; faceIndex++)
{
var localToWorld = m_FaceLocalToWorldRotation[faceIndex];

// Translate along normal of face by width
localToWorld.c3.xyz = localToWorld.c1.xyz * RowCount * 0.5f;

faceLocalToWorld[faceIndex] = new FaceLocalToWorld
{
Value = localToWorld
};
faceWorldToLocal[faceIndex] = new FaceLocalToWorld
{
Value = math.fastinverse(faceLocalToWorld[faceIndex].Value)
};
}

// Diagonal is identity and unused, but makes lookup simpler.
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 6; j++)
{
faceLocalToLocal[(i * 6) + j] = new FaceLocalToWorld
{
Value = math.mul(faceWorldToLocal[j].Value, faceLocalToWorld[i].Value)
};
}
}

for (int i = 0; i < 6; i++)
{
// 4 bits per grid section (bit:0=N,1=S,2=W,3=E)
var gridWalls = new NativeArray<GridWalls>(RowCount * ((RowCount + 1) / 2), Allocator.Persistent);

GridAuthoringUtility.CreateGridPath(RowCount, RowCount, gridWalls, WallSProbability, WallWProbability, false);

// Create visible geometry
for (int y = 0; y < RowCount; y++)
for (int x = 0; x < RowCount; x++)
{
var prefabIndex = (x + y) % floorPrefabCount;
var tx = ((float)x) - cx;
var tz = ((float)y) - cz;

GridAuthoringUtility.CreateFloorPanel(dstManager, conversionSystem, gameObject, FloorPrefab[prefabIndex], faceLocalToWorld[i].Value, tx, tz);

var gridWallsIndex = (y * ((RowCount + 1) / 2)) + (x / 2);
var walls = (gridWalls[gridWallsIndex].Value >> ((x & 1) * 4)) & 0x0f;

if ((walls & 0x02) != 0) // South wall
GridAuthoringUtility.CreateWallS(dstManager, conversionSystem, gameObject, WallPrefab, faceLocalToWorld[i].Value, tx, tz);
if ((walls & 0x04) != 0) // West wall
GridAuthoringUtility.CreateWallW(dstManager, conversionSystem, gameObject, WallPrefab, faceLocalToWorld[i].Value, tx, tz);
}

gridWallsBuffer = dstManager.GetBuffer<GridWalls>(entity);
gridWallsBuffer.AddRange(gridWalls);

gridWalls.Dispose();
}

dstManager.AddComponent<GridCube>(entity);
dstManager.AddComponentData(entity, new GridConfig
{
RowCount = (ushort)RowCount,
ColCount = (ushort)RowCount
});

var faceLocalToWorldBuffer = dstManager.AddBuffer<FaceLocalToWorld>(entity);
faceLocalToWorldBuffer.AddRange(faceLocalToWorld);
faceLocalToWorldBuffer.AddRange(faceLocalToLocal);

GridAuthoringUtility.AddTrailingOffsets(dstManager, entity, RowCount, RowCount);

faceLocalToWorld.Dispose();
faceWorldToLocal.Dispose();
faceLocalToLocal.Dispose();
}
}
93 changes: 93 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scripts/GridPath.cs
@@ -0,0 +1,93 @@
using System;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;

public struct GridCube : IComponentData
{
}

public struct GridPlane : IComponentData
{
}

public struct GridConfig : IComponentData
{
public ushort RowCount;
public ushort ColCount;
}

// Direction along grid axis
// 0 = N
// 1 = S
// 2 = W
// 3 = E
public struct GridDirection : IComponentData
{
public byte Value; // 2 bits current direction
}

// Speed of movement in grid-space
// - 6:10 fixed point instead of 32bit float (for size)
public struct GridSpeed : IComponentData
{
public ushort Value;
}

// NativeArray<4bit x rowCount x colCount> of walls.
// 0x01 = North
// 0x02 = South
// 0x04 = West
// 0x08 = East
public struct GridWalls : IBufferElementData
{
public byte Value;
}

// Which face of the GridCube
// 0 = X+
// 1 = X-
// 2 = Y+
// 3 = Y-
// 4 = Z+
// 5 = Z-
[WriteGroup((typeof(LocalToWorld)))]
public struct GridFace : IComponentData
{
public byte Value;
}

// Coordinates quantized to the grid
public struct GridPosition : IComponentData, IEquatable<GridPosition>
{
public short x;
public short y;

public GridPosition(float2 pos, int rowCount, int colCount)
{
// Grid indices of Trailing edge
// - Always positive when on the grid.
// - However, in the case of a cube, the translation may go off the grid when travelling around the corner.
// In this case, stretch the one-off grid element to encompass the whole area off the grid.
// e.g. if it's off to the left, grid x value is always -1.
x = (short)math.clamp(((int)(pos.x + 1.0f)) - 1, -1, colCount);
y = (short)math.clamp(((int)(pos.y + 1.0f)) - 1, -1, rowCount);
}

public bool Equals(GridPosition other)
{
return ((other.x == x) && (other.y == y));
}
}

public struct FaceLocalToWorld : IBufferElementData
{
public float4x4 Value;
}

public struct GridTrailingOffset : IBufferElementData
{
public float2 Value;
}


3 changes: 3 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scripts/GridPath.cs.meta
@@ -0,0 +1,28 @@
using Unity.Entities;
using UnityEngine;

[RequiresEntityConversion]
[AddComponentMenu("DOTS Samples/GridPath/GridPathMovement")]
[ConverterVersion("joe", 1)]
public class GridPathMovementAuthoring : MonoBehaviour, IConvertGameObjectToEntity
{
[Range(0.0f, 2.0f)]
public float Speed;

public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
dstManager.AddComponentData(entity, new GridDirection
{
Value = 0, // default N
});
dstManager.AddComponentData(entity, new GridSpeed
{
Value = (ushort)(Speed * 1024.0f)
});
dstManager.AddComponentData(entity, new GridPosition
{
x = -1,
y = -1
});
}
}
331 changes: 331 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scripts/GridPathMovementSystem.cs
@@ -0,0 +1,331 @@
using System;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;

// Update movement on GridPlane and GridCube
// - Simple move around walls
public class GridPathMovementSystem : JobComponentSystem
{
EntityQuery m_GridQuery;

// Convenience vectors for turning direction.
static readonly float[] m_UnitMovement =
{
0.0f, 1.0f, // North
0.0f, -1.0f, // South
-1.0f, 0.0f, // West
1.0f, 0.0f, // East
};

// Next Direction lookup by grid element walls
// - Calculate gridX, gridY based on current actual position (Translation)
// - Get 4 path options = [(gridY * rowCount)+gridX]
// - Select path option based on current direction (Each of 4 direction 2bits of result)
static readonly byte[] m_NextDirection =
{
// Standard paths. Bounce off walls.
// Two paths because two directions can be equally likely.

// PathSet[0]
0xe4, 0xe7, 0xec, 0xef, 0xc4, 0xd7, 0xcc, 0xff,
0x24, 0x66, 0x28, 0xaa, 0x04, 0x55, 0x00, 0xe4,

// PathSet[1]
0xe4, 0xe6, 0xe8, 0xea, 0xd4, 0xd7, 0xcc, 0xff,
0x64, 0x66, 0x28, 0xaa, 0x54, 0x55, 0x00, 0xe4,

// Path (rare) variations below
// Very occasionally, move without bouncing off wall.

// Assume north wall
0xe6, 0xe6, 0xea, 0xea, 0xd7, 0xd7, 0xff, 0xff,
0x66, 0x66, 0xaa, 0xaa, 0x55, 0x55, 0x00, 0xe4,

// Assume south wall
0xe8, 0xea, 0xe8, 0xea, 0xcc, 0xff, 0xcc, 0xff,
0x28, 0xaa, 0x28, 0xaa, 0x00, 0x55, 0x00, 0xe4,

// Assume west wall
0xd4, 0xd7, 0xcc, 0xff, 0xd4, 0xd7, 0xcc, 0xff,
0x54, 0x55, 0x00, 0xaa, 0x54, 0x55, 0x00, 0xe4,

// Assume east wall
0x64, 0x66, 0x28, 0xaa, 0x54, 0x55, 0x00, 0xff,
0x64, 0x66, 0x28, 0xaa, 0x54, 0x55, 0x00, 0xe4,
};

// Next face to move to when moving off edge of a face
static readonly byte[] m_NextFaceIndex =
{
// X+ X- Y+ Y- Z+ Z- <- From which face
4, 4, 4, 4, 3, 2, // Off north edge
5, 5, 5, 5, 2, 3, // Off south edge
2, 3, 1, 0, 1, 1, // Off west edge
3, 2, 0, 1, 0, 0, // Off east edge
};

static readonly byte[] m_NextFaceDirection =
{
// X+ X- Y+ Y- Z+ Z- <- From which face
2, 3, 0, 1, 1, 0, // Off north edge
2, 3, 1, 0, 1, 0, // Off south edge
2, 2, 2, 2, 1, 0, // Off west edge
3, 3, 3, 3, 1, 0, // Off east edge
};

// Arbitrarily select direction when two directions are equally valid
int m_NextDirectionBufferSelect = 0;
int m_NextDirectionVariationSelect = 0;

protected override void OnCreate()
{
m_GridQuery = GetEntityQuery(
ComponentType.ReadOnly<GridConfig>(),
ComponentType.ReadOnly<GridWalls>());
}

protected override JobHandle OnUpdate(JobHandle lastJobHandle)
{
// There's only one grid. Make sure it exists before start moving.
if (m_GridQuery.CalculateEntityCount() != 1)
return lastJobHandle;

// Flip which arbitrary direction would be selected.
int directionBufferIndex = 0;

// Once every 16 frames, select an arbitrary variation (if happen to be crossing threshold)
// Both crossing a threshold and hitting a variation at the same time is a very rare event.
// The purpose of these variations is to occasionally kick things out that are caught in a
// movement loop.
if (m_NextDirectionBufferSelect == 15)
{
directionBufferIndex = 2 + m_NextDirectionVariationSelect;
m_NextDirectionVariationSelect = (m_NextDirectionVariationSelect + 1) & 0x03;
}

// Otherwise select one of two main paths
else
{
directionBufferIndex = m_NextDirectionBufferSelect & 1;
}

// Update selection frame counter
m_NextDirectionBufferSelect = (m_NextDirectionBufferSelect + 1) & 15;

// Get component data from the Grid (GridPlane or GridCube)
var gridConfigFromEntity = GetComponentDataFromEntity<GridConfig>(true);
var gridWallsFromEntity = GetBufferFromEntity<GridWalls>(true);
var trailingOffsetsFromEntity = GetBufferFromEntity<GridTrailingOffset>(true);
var faceLocalToWorldFromEntity = GetBufferFromEntity<FaceLocalToWorld>(true);
var gridEntity = m_GridQuery.GetSingletonEntity();
var onGridCube = EntityManager.HasComponent<GridCube>(gridEntity);
var onGridPlane = EntityManager.HasComponent<GridPlane>(gridEntity);
var gridConfig = gridConfigFromEntity[gridEntity];
var gridWalls = gridWallsFromEntity[gridEntity].Reinterpret<byte>().AsNativeArray();

// Trailing edge of movement (relative to center)
// - Trailing edge is used to determine grid section to make sure the object is *completely* in the
// grid section before being considered in the grid section.
var trailingOffsets = trailingOffsetsFromEntity[gridEntity].Reinterpret<float2>().AsNativeArray();

if (!(onGridCube || onGridPlane))
return lastJobHandle;

var faceLocalToWorld = new NativeArray<float4x4>();
if (faceLocalToWorldFromEntity.Exists(gridEntity))
{
// FaceLocalToWorld is provides:
// LocalToWorld float4x4 per face (6)
// - In order of X+, X-, Y+, Y-, Z+, Z-
// - Which is the same order as referenced by GridDirection
// LocalToLocal float4x4 per pair of faces (36)
// - For each source face, in order of X+, X-, Y+, Y-, Z+, Z-
// - For each destination face of X+, X-, Y+, Y-, Z+, Z-
// - The diagonal along this 6x6 matrix of float4x4 is unused, but simplifies lookup.
faceLocalToWorld = faceLocalToWorldFromEntity[gridEntity].Reinterpret<float4x4>().AsNativeArray();
}

// Starting index into the LocalToLocal matrices described above
int faceLocalToLocalOffset = 6;

// Board size (rowCount == colCount when GridCube)
var rowCount = gridConfig.RowCount;
var colCount = gridConfig.ColCount;
var rowStride = ((colCount + 1) / 2);

// Two global variations of paths divided by 0.5 probability.
var pathOffset = 16 * directionBufferIndex;

// Offset center to grid cell
var cellCenterOffset = new float2(((float)colCount * 0.5f) - 0.5f, ((float)rowCount * 0.5f) - 0.5f);

// Clamp delta time so you can't overshoot.
var deltaTime = math.min(Time.DeltaTime, 0.05f);

// Change direction for GridCube, including traveling around corners and changing active face.
if (onGridCube)
lastJobHandle = Entities
.WithName("GridCubeChangeDirection")
.WithAll<GridCube>()
.WithReadOnly(gridWalls)
.WithReadOnly(faceLocalToWorld)
.WithReadOnly(trailingOffsets)
.ForEach((ref GridDirection gridDirection,
ref Translation translation,
ref GridPosition gridPosition,
ref GridFace gridFace) =>
{
var prevDir = gridDirection.Value;
var nextGridPosition = new GridPosition(translation.Value.xz + trailingOffsets[prevDir], rowCount, rowCount);
if (gridPosition.Equals(nextGridPosition))
return; // Still in the same grid cell. No need to change direction.
// Which edge of GridCube face is being exited (if any)
var edge = -1;
// Edge is in order specified in m_NextFaceIndex and m_NextFaceDirection
// - Matches GridDirection values.
edge = math.select(edge, 0, nextGridPosition.y >= rowCount);
edge = math.select(edge, 1, nextGridPosition.y < 0);
edge = math.select(edge, 2, nextGridPosition.x < 0);
edge = math.select(edge, 3, nextGridPosition.x >= rowCount);
// Change direction based on wall layout (within current face.)
if (edge == -1)
{
gridPosition = nextGridPosition;
gridDirection.Value = LookupGridDirectionFromWalls( ref gridPosition, prevDir, rowStride, ref gridWalls, pathOffset);
}
// Exiting face of GridCube, change face and direction relative to new face.
else
{
int prevFaceIndex = gridFace.Value;
// Look up next direction given previous face and exit edge.
var nextDir = m_NextFaceDirection[(edge * 6) + prevFaceIndex];
gridDirection.Value = nextDir;
// Lookup next face index given previous face and exit edge.
var nextFaceIndex = m_NextFaceIndex[(edge * 6) + prevFaceIndex];
gridFace.Value = nextFaceIndex;
// Transform translation relative to next face's grid-space
// - This transform is only done to "smooth" the transition around the edges.
// - Alternatively, you could "snap" to the same relative position in the next face by rotating the translation components.
// - Note that Y position won't be at target value from one edge to another, so that is interpolated in movement update,
// purely for "smoothing" purposes.
var localToLocal = faceLocalToWorld[faceLocalToLocalOffset + ((prevFaceIndex * 6) + nextFaceIndex)];
translation.Value.xyz = math.mul(localToLocal, new float4(translation.Value, 1.0f)).xyz;
// Update gridPosition relative to new face.
gridPosition = new GridPosition(translation.Value.xz + trailingOffsets[nextDir], rowCount, rowCount);
}
}).Schedule(lastJobHandle);

// Change direction for gridPlane
if (onGridPlane)
lastJobHandle = Entities
.WithName("GridPlaneChangeDirection")
.WithAll<GridPlane>()
.WithReadOnly(gridWalls)
.WithReadOnly(trailingOffsets)
.ForEach((ref GridDirection gridDirection,
ref GridPosition gridPosition,
in Translation translation) =>
{
var dir = gridDirection.Value;
var nextGridPosition = new GridPosition(translation.Value.xz + trailingOffsets[dir], rowCount, colCount);
if (gridPosition.Equals(nextGridPosition))
return; // Still in the same grid cell. No need to change direction.
gridPosition = nextGridPosition;
gridDirection.Value = LookupGridDirectionFromWalls(ref gridPosition, dir, rowStride, ref gridWalls, pathOffset);
}).Schedule(lastJobHandle);

// Move forward along direction in grid-space given speed.
// - This is the same for Plane or Cube and is the core of the movement code. Simply "move forward" along direction.
lastJobHandle = Entities
.WithName("GridMoveForward")
.ForEach((ref Translation translation,
in GridDirection gridDirection,
in GridSpeed gridSpeed,
in GridPosition gridPosition) =>
{
var dir = gridDirection.Value;
// Don't allow translation to drift
var pos = ClampToGrid(translation.Value, dir, gridPosition, cellCenterOffset);
// Speed adjusted to float m/s from fixed point 6:10 m/s
var speed = deltaTime * ((float)gridSpeed.Value) * (1.0f / 1024.0f);
// Write: add unit vector offset scaled by speed and deltaTime to current position
var dx = m_UnitMovement[(dir * 2) + 0] * speed;
var dz = m_UnitMovement[(dir * 2) + 1] * speed;
// Smooth y changes when transforming between cube faces.
var dy = math.min(speed, 1.0f - pos.y);
translation.Value = new float3(pos.x + dx, pos.y + dy, pos.z + dz);
}).Schedule(lastJobHandle);

// Transform from grid-space Translation and gridFace to LocalToWorld for GridCube
// - This is an example of overriding the transform system's default behavior.
// - GridFace is in the LocalToWorld WriteGroup, so when it this component is present, it is required to be
// part of the query in order to write to LocalToWorld. Since the transform system doesn't know anything
// about GridFace, it will never be present in those default transformations. So it can be handled custom
// here.
if (onGridCube)
lastJobHandle = Entities.WithAll<GridCube>()
.WithName("GridCubeLocalToWorld")
.ForEach((ref LocalToWorld localToWorld,
in Translation translation,
in GridFace gridFace) =>
{
var resultLocalToWorld = faceLocalToWorld[gridFace.Value];
resultLocalToWorld.c3 = math.mul(resultLocalToWorld, new float4(translation.Value, 1.0f));
localToWorld = new LocalToWorld
{
Value = resultLocalToWorld
};
}).Schedule(lastJobHandle);

return lastJobHandle;
}

static float3 ClampToGrid(float3 v, byte dir, GridPosition gridPosition, float2 cellCenterOffset)
{
// When (dir == N,S) clamp to grid cell center x
// When (dir == W,E) clamp to grid cell center y
var mx = (dir >> 1) * 1.0f;
var my = ((dir >> 1) ^ 1) * 1.0f;

return new float3
{
x = (mx * v.x) + (my * (gridPosition.x - cellCenterOffset.x)),
z = (my * v.z) + (mx * (gridPosition.y - cellCenterOffset.y)),
y = v.y
};
}

static byte LookupGridDirectionFromWalls(ref GridPosition gridPosition, byte dir, int rowStride, ref NativeArray<byte> gridWalls, int pathOffset)
{
// gridPosition needs to be on-grid (positive and < [colCount, rowCount]) when looking up next direction.

// Index into grid array
var gridWallsIndex = (gridPosition.y * rowStride) + (gridPosition.x / 2);

// Walls in current grid element (odd columns in upper 4 bits of byte)
var walls = (gridWalls[gridWallsIndex] >> ((gridPosition.x & 1) * 4)) & 0x0f;

// New direction = f( grid index, movement direction )
return (byte)((m_NextDirection[pathOffset + walls] >> (dir * 2)) & 0x03);
}
}
83 changes: 83 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scripts/GridPlaneAuthoring.cs
@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;

// ReSharper disable once InconsistentNaming
[RequiresEntityConversion]
[AddComponentMenu("DOTS Samples/GridPath/Grid Plane")]
[ConverterVersion("joe", 1)]
public class GridPlaneAuthoring : MonoBehaviour, IConvertGameObjectToEntity, IDeclareReferencedPrefabs
{
[Range(2,512)] public int ColumnCount;
[Range(2,512)] public int RowCount;
public GameObject[] FloorPrefab;
public GameObject WallPrefab;

// Specific wall probability, given PotentialWallProbability
public float WallSProbability = 0.5f;
public float WallWProbability = 0.5f;

// Referenced prefabs have to be declared so that the conversion system knows about them ahead of time
public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
{
referencedPrefabs.Add(WallPrefab);
referencedPrefabs.AddRange(FloorPrefab);
}

public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
var prefabCount = FloorPrefab.Length;

#if UNITY_EDITOR
dstManager.SetName(entity, "Grid");
#endif

var cx = (ColumnCount * 0.5f);
var cz = (RowCount * 0.5f);

// 4 bits per grid section (bit:0=N,1=S,2=W,3=E)
var gridWalls = new NativeArray<GridWalls>(RowCount * (ColumnCount+1)/2, Allocator.Persistent);

GridAuthoringUtility.CreateGridPath(RowCount, ColumnCount, gridWalls, WallSProbability, WallWProbability, true);

// Create visible geometry
for (int y = 0; y < RowCount; y++)
for (int x = 0; x < ColumnCount; x++)
{
var prefabIndex = (x+y) % prefabCount;
var tx = ((float)x) - cx;
var tz = ((float)y) - cz;

GridAuthoringUtility.CreateFloorPanel(dstManager, conversionSystem, gameObject, FloorPrefab[prefabIndex], float4x4.identity, tx, tz);

var gridWallsIndex = (y * ((ColumnCount + 1) / 2)) + (x / 2);
var walls = (gridWalls[gridWallsIndex].Value >> ((x & 1) * 4)) & 0x0f;

if ((walls & 0x02) != 0) // South wall
GridAuthoringUtility.CreateWallS(dstManager, conversionSystem, gameObject, WallPrefab, float4x4.identity, tx, tz);
if ((walls & 0x04) != 0) // West wall
GridAuthoringUtility.CreateWallW(dstManager, conversionSystem, gameObject, WallPrefab, float4x4.identity, tx, tz);
if (y == (RowCount - 1)) // North wall
GridAuthoringUtility.CreateWallS(dstManager, conversionSystem, gameObject, WallPrefab, float4x4.identity, tx, tz + 1.0f);
if (x == (ColumnCount - 1)) // East wall
GridAuthoringUtility.CreateWallW(dstManager, conversionSystem, gameObject, WallPrefab, float4x4.identity, tx + 1.0f, tz);
}

var gridWallsBuffer = dstManager.AddBuffer<GridWalls>(entity);
gridWallsBuffer.AddRange(gridWalls);

dstManager.AddComponent<GridPlane>(entity);
dstManager.AddComponentData(entity, new GridConfig
{
RowCount = (ushort)RowCount,
ColCount = (ushort)ColumnCount
});

GridAuthoringUtility.AddTrailingOffsets(dstManager, entity, RowCount, ColumnCount);

gridWalls.Dispose();
}
}
13 changes: 13 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scripts/OnGridGenerator.cs
@@ -0,0 +1,13 @@
using Unity.Entities;
using Unity.Mathematics;

public struct OnGridGenerator : IComponentData
{
public Entity Prefab;
public float CoolDownSeconds;
public float SecondsUntilGenerate;
public int GenerateMaxCount;

public int GeneratedCount;
public Random Random;
}
@@ -0,0 +1,33 @@
using System.Collections.Generic;
using Unity.Entities;
using UnityEngine;
using Random = Unity.Mathematics.Random;

[RequiresEntityConversion]
[AddComponentMenu("DOTS Samples/GridPath/OnGridGenerator")]
[ConverterVersion("joe", 1)]
public class OnGridGeneratorAuthoring : MonoBehaviour, IConvertGameObjectToEntity, IDeclareReferencedPrefabs
{
public GameObject Prefab;
public float CoolDownSeconds;
[Range(0,64*1024)]
public int GenerateMaxCount;

public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
dstManager.AddComponentData(entity, new OnGridGenerator
{
Prefab = conversionSystem.GetPrimaryEntity(Prefab),
CoolDownSeconds = CoolDownSeconds,
SecondsUntilGenerate = 0.0f,
GenerateMaxCount = GenerateMaxCount,
GeneratedCount = 0,
Random = new Random(0xDBC19 * (uint)entity.Index )
});
}

public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
{
referencedPrefabs.Add(Prefab);
}
}
@@ -0,0 +1,71 @@
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;

public class OnGridGeneratorSystem : JobComponentSystem
{
BeginInitializationEntityCommandBufferSystem m_EntityCommandBufferSystem;

protected override void OnCreate()
{
RequireSingletonForUpdate<GridConfig>();

// Cache the BeginInitializationEntityCommandBufferSystem in a field, so we don't have to create it every frame
m_EntityCommandBufferSystem = World.GetOrCreateSystem<BeginInitializationEntityCommandBufferSystem>();
}

protected override JobHandle OnUpdate(JobHandle inputDeps)
{
var deltaTime = Time.DeltaTime;
var commandBuffer = m_EntityCommandBufferSystem.CreateCommandBuffer();
var gridEntity = GetSingletonEntity<GridConfig>();
var gridConfig = EntityManager.GetComponentData<GridConfig>(gridEntity);
var onGridCube = EntityManager.HasComponent<GridCube>(gridEntity);
var onGridPlane = EntityManager.HasComponent<GridPlane>(gridEntity);

// Board size
var rowCount = gridConfig.RowCount;
var colCount = gridConfig.ColCount;

// Offset to center of board
var cx = (float)colCount * 0.5f;
var cy = (float)rowCount * 0.5f;

Entities.ForEach((ref OnGridGenerator onGridGenerator) =>
{
var secondsUntilGenerate = onGridGenerator.SecondsUntilGenerate;
secondsUntilGenerate -= deltaTime;
if (secondsUntilGenerate <= 0.0f)
{
if (onGridGenerator.GeneratedCount < onGridGenerator.GenerateMaxCount)
{
var entity = commandBuffer.Instantiate(onGridGenerator.Prefab);
var u = onGridGenerator.Random.NextInt(0, colCount-1);
var v = onGridGenerator.Random.NextInt(0, rowCount-1);
var x = u - cx + 0.5f;
var z = v - cy + 0.5f;
var y = 1.0f;
if (onGridCube)
{
var faceIndex = onGridGenerator.Random.NextInt(0, 6);
commandBuffer.AddComponent(entity, new GridCube());
commandBuffer.AddComponent(entity, new GridFace { Value = (byte)faceIndex });
}
if (onGridPlane)
commandBuffer.AddComponent(entity, new GridPlane());
commandBuffer.SetComponent(entity, new Translation { Value = new float3(x, y, z) });
onGridGenerator.GeneratedCount++;
}
secondsUntilGenerate = onGridGenerator.CoolDownSeconds;
}
onGridGenerator.SecondsUntilGenerate = secondsUntilGenerate;
}).Run();

return inputDeps;
}
}
17 changes: 17 additions & 0 deletions ECSSamples/Assets/Advanced/GridPath/Scripts/README.md
@@ -0,0 +1,17 @@
# GridPath

Move straight until you hit a wall. Then change direction,

1. There are only four walls (NSWE). Describe permutations of each wall with 4bits.
- This is what GridAuthoring creates and is stored in GridWalls.
- 4bits per grid cell (so two cells in the same row are packed into a byte)
2. Given grid x,y look up walls in that grid section.
3. For any given permutation of walls, the exit (next) direction is known.
- This is stored Paths in GridPathMovementSystem.
- It may be possible there are two equally good exit directions.
- So two path options are stored in Paths and are arbitrarily selected between.
4. It's possible to move around in a loop because of wall layout.
- While that's fine, just as a bonus we want to break the pattern a little.
- Under rare conditions, provide alternate exit direction from any grid section.
- Which may be a grid you'd normally move straight through.
- This is stored as four extra path options in Paths in GridPathMovementSystem.
@@ -0,0 +1,24 @@
{
"name": "Samples.GridPath",
"references": [
"Unity.Entities",
"Unity.Entities.Hybrid",
"Unity.Collections",
"Unity.Transforms",
"Unity.Transforms.Hybrid",
"Unity.Rendering.Hybrid",
"Unity.Burst",
"Unity.Jobs",
"Unity.Mathematics",
"Unity.Mathematics.Extensions",
"Unity.Mathematics.Extensions.Hybrid"
],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}
8 changes: 8 additions & 0 deletions ECSSamples/Assets/Advanced/SubsceneWithBuildSettings.meta
@@ -0,0 +1,7 @@
{
"Dependencies": [],
"Components": [{
"$type": "RotationSpeedSetting, SubsceneWithBuildSettings",
"RotationSpeed": 160
}]
}
@@ -0,0 +1,26 @@
using System;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;

#if UNITY_EDITOR
[RequiresEntityConversion]
[ConverterVersion("joe", 1)]
public class RotationSpeedFromBuildSettings_IJobChunk : MonoBehaviour, IConvertGameObjectToEntity
{
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
var rotationSpeedSetting = conversionSystem.GetBuildSettingsComponent<RotationSpeedSetting>();

// Change rotation speed
var data = new RotationSpeed_IJobChunk { RadiansPerSecond = math.radians(rotationSpeedSetting.RotationSpeed) };
dstManager.AddComponentData(entity, data);

// Offset the translation of the generated object
var translation = dstManager.GetComponentData<Translation>(entity);
translation.Value.y += rotationSpeedSetting.Offset;
dstManager.SetComponentData(entity, translation);
}
}
#endif
@@ -0,0 +1,19 @@
using UnityEditor;

#if UNITY_EDITOR
public class RotationSpeedSetting : Unity.Build.IBuildSettingsComponent
{
public float RotationSpeed;
public float Offset;

public string Name => "RotationSpeedSetting";

public bool OnGUI()
{
EditorGUI.BeginChangeCheck();
RotationSpeed = EditorGUILayout.FloatField("RotationSpeed", RotationSpeed);
Offset = EditorGUILayout.FloatField("Offset", Offset);
return EditorGUI.EndChangeCheck();
}
}
#endif
@@ -0,0 +1,79 @@
using System;
using System.Linq;
using Unity.Entities;
using Unity.Scenes;
using UnityEditor;
using UnityEngine;
using UnityEngine.LowLevel;
using Hash128 = Unity.Entities.Hash128;
#if UNITY_EDITOR
using Unity.Build;
#endif
#pragma warning disable 649

[ExecuteAlways]
public class SetBuildSettingsComponent : MonoBehaviour
{
#if UNITY_EDITOR
[SerializeField]
public BuildSettings _BuildSettingsA;
[SerializeField]
public BuildSettings _BuildSettingsB;
#endif

[SerializeField]
[HideInInspector]
Hash128 _BuildSettingsGUIDA;

[SerializeField]
[HideInInspector]
Hash128 _BuildSettingsGUIDB;


private World worldA;
private World worldB;

static void SetBuildSettingOnWorld(Hash128 buildSettingsGUID, World world)
{
if (world == null)
return;
world.GetExistingSystem<SceneSystem>().BuildSettingsGUID = buildSettingsGUID;
}

private void OnValidate()
{
#if UNITY_EDITOR
_BuildSettingsGUIDA = new GUID(AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(_BuildSettingsA)));
_BuildSettingsGUIDB = new GUID(AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(_BuildSettingsB)));
#endif

SetBuildSettingOnWorld(_BuildSettingsGUIDA, worldA);
SetBuildSettingOnWorld(_BuildSettingsGUIDB, worldB);
}

private void OnEnable()
{
var worldNameA = "BuildSettings Test World A";
var worldNameB = "BuildSettings Test World B";

World.DisposeAllWorlds();
DefaultWorldInitialization.Initialize(worldNameA, !Application.isPlaying);
DefaultWorldInitialization.Initialize(worldNameB, !Application.isPlaying);

worldA = World.AllWorlds.First(w => w.Name == worldNameA);
worldB = World.AllWorlds.First(w => w.Name == worldNameB);

OnValidate();

//@TODO: This API is confusing. Should be way more explicit.
// Current API makes it very easy to have the same system injected multiple times
ScriptBehaviourUpdateOrder.UpdatePlayerLoop(worldA, null);
ScriptBehaviourUpdateOrder.UpdatePlayerLoop(worldB, PlayerLoop.GetCurrentPlayerLoop());
}

private void OnDisable()
{
World.DisposeAllWorlds();
DefaultWorldInitialization.Initialize("Default World", !Application.isPlaying);
}
}
@@ -0,0 +1,8 @@
{
"Dependencies": [],
"Components": [{
"$type": "RotationSpeedSetting, SubsceneWithBuildSettings",
"RotationSpeed": 50,
"Offset": 2
}]
}
@@ -0,0 +1,24 @@
{
"name": "SubsceneWithBuildSettings",
"references": [
"Unity.Burst",
"Unity.Collections",
"Unity.Entities",
"Unity.Entities.Hybrid",
"Unity.Mathematics",
"Unity.Rendering.Hybrid",
"Unity.Transforms",
"Unity.Build",
"Unity.Scenes.Hybrid",
"HelloCube"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}