普通方式
@H_502_0@1. 先创建OPPMoveScript.cs来实现Cube的随机旋转和移动:
1 using UnityEngine; 2 3 public class OPPMoveScript : MonoBehavIoUr 4 { 5 private Vector3 _rotateSpeed; 6 private Vector3 _moveSpeed; 7 private float _movedistance; 8 9 private Vector3 _origin; 10 private float _distanceSqr; 11 12 void Start() 13 { 14 _rotateSpeed.x = Random.value * 360; 15 _rotateSpeed.y = Random.value * 360; 16 _rotateSpeed.z = Random.value * 360; 17 18 _moveSpeed.x = Random.Range(0.5f, 1f); 19 _moveSpeed.z = Random.Range(0.5f, 1f); 20 _moveSpeed.y = Random.Range(0.5f, 1f); 21 22 _movedistance = Random.Range(0.5f, 1f) * 5; 23 24 _origin = transform.position; 25 _distanceSqr = _movedistance * _movedistance; 26 } 27 28 void Update() 29 { 30 transform.Rotate(_rotateSpeed * Time.deltaTime); 31 transform.Translate(_moveSpeed * Time.deltaTime); 32 33 if (Vector3.SqrMagnitude(transform.position - _origin) > _distanceSqr) 34 { 35 _moveSpeed = -_moveSpeed; 36 } 37 } 38 }View Code @H_502_0@2. 再创建OPPCreateScript.cs来生成10000个Cube:
1 using UnityEngine; 2 3 public class OPPCreateScript : MonoBehavIoUr 4 { 5 public int MaxCount = 10000; 6 7 public float RandomNum = 10f; 8 9 void Start() 10 { 11 GameObject go = Resources.Load<GameObject>("OPP/Prefabs/OPPCube"); 12 13 for (int i = 0; i < MaxCount; i++) 14 { 15 Vector3 pos = new Vector3(); 16 pos.x = Random.value * RandomNum * 2 - RandomNum; 17 pos.y = Random.value * RandomNum * 2 - RandomNum; 18 pos.z = Random.value * RandomNum * 2 - RandomNum; 19 GameObject.Instantiate(go, pos, Quaternion.LookRotation(Vector3.forward)); 20 } 21 } 22 }View Code @H_502_0@最终效果如下: @H_502_0@
DOTS方式
@H_502_0@在开始实现效果之前,我们需要先知道该如何使用DOTS在场景中创建一个Cube。 @H_502_0@尽管在ECS中,提供了ConvertToEntity的脚本,只要简单的挂到普通的GameObject之上,就可以将其转换为对应的Entity对象,但是由于其内部使用了大量的反射导致存在性能问题所以在实际项目中基本上不会采用该方式来开发。 @H_502_0@所以下面我们会使用ECS的方式来创建该Cube。创建一个Cube
@H_502_0@ECS中,Component是存放数据的地方,所以我们需要将Cube的信息添加到Component里,而Sy@R_502_6063@是处理所有数据的地方。由于我们只是要显示一个Cube,Unity已经提供了我们所需要的Component和Sy@R_502_6063@,所以我们只要创建一个Entity并且设置好对应的数据即可。 @H_502_0@注:DOTS中显示一个3D对象至少需要LocalToWorld、RenderMesh和RenderBounds这3个Component。 @H_502_0@LocalToWorld存放的是旋转和位置数据,RenderMesh存放渲染所需的mesh和material等数据,RenderBounds则存放AABB盒的信息。 @H_502_0@其中mesh和material需要从资源中获取,所以我们提前编写一个类AssetHolder,并且创建对应的Prefab将mesh和material设置好。
1 using UnityEngine; 2 3 public class AssetHolder : MonoBehavIoUr 4 { 5 public Mesh mesh; 6 7 public Material material; 8 }View Code @H_502_0@接下来我们创建一个脚本用来添加Cube:
1 using Unity.Entities; 2 using Unity.Mathematics; 3 using Unity.Rendering; 4 using Unity.Transforms; 5 using UnityEngine; 6 7 public class SimpleECSCreateScript : MonoBehavIoUr 8 { 9 void Start() 10 { 11 AssetHolder assetHolder = Resources.Load<GameObject>("AssetHolder").GetComponent<AssetHolder>(); 12 Mesh mesh = assetHolder.mesh; 13 Material material = assetHolder.material; 14 15 //获取默认的World和EntityManager 16 World world = World.DefaultGameObjectInjectionWorld; 17 EntityManager entityManager = world.EntityManager; 18 //创建Cube需要的所有Component对应的类型集合 19 EntityArchetype archetype = entityManager.CreateArchetype( 20 ComponentType.ReadOnly<LocalToWorld>(), 21 ComponentType.ReadOnly<RenderMesh>(), 22 ComponentType.ReadWrite<RenderBounds>() 23 ); 24 //创建Entity 25 Entity entity = entityManager.CreateEntity(archetype); 26 //为Entity设置数据 27 entityManager.SetComponentData(entity, new LocalToWorld() 28 { 29 Value = new float4x4(rotation: quaternion.identity, translation: new float3(0, 0, 0)) 30 }); 31 entityManager.SetSharedComponentData(entity, new RenderMesh() 32 { 33 mesh = mesh, 34 material = material 35 }); 36 entityManager.SetComponentData(entity, new RenderBounds() 37 { 38 Value = new AABB() 39 { 40 Center = new float3(0, 0, 0), 41 Extents = new float3(0.5f, 0.5f, 0.5f) 42 } 43 }); 44 } 45 }View Code @H_502_0@运行起来后,可以在Game和Scene中看到一个红色的Cube,但是在Hierarchy中是看不到的,因为Entity不是GameObject。 @H_502_0@
实现10000个Cube同屏运动
@H_502_0@知道怎么创建一个Cube并显示后,就可以实现10000个Cube同屏运动的效果了,在此之前,有几个需要注意的地方先说一下:- 由于是我们自己的效果,就得编写自己的Component和Sy@R_502_6063@来实现逻辑;
- Sy@R_502_6063@类只要存在,就默认会自己创建并添加到World中执行,也就是说我们只需要创建Sy@R_502_6063@类并编写好代码即可,游戏一运行该Sy@R_502_6063@类就会自己创建并执行;但是一般来说,我们还是希望自己控制Sy@R_502_6063@的生命周期,所以我们一般会添加不自动创建的标签[disableAutoCreation]来取消其自动创建的特性;
- World中会存在默认的几个Sy@R_502_6063@,我们自己实现的Sy@R_502_6063@如果要执行OnUpdate方法,就必须添加到这几个默认的Sy@R_502_6063@中的某一个里,这里我们会添加到SimulationSy@R_502_6063@Group中;
1 using Unity.Entities; 2 using Unity.Mathematics; 3 4 public struct ECSMoveData : IComponentData 5 { 6 public float3 rotateSpeed; 7 public float3 moveSpeed; 8 public float movedistance; 9 10 public float3 origin; 11 public float distanceSqr; 12 }View Code @H_502_0@2. ECSMoveSy@R_502[email protected],这里包含了所有Entity的创建和运动的逻辑:
1 using Unity.Entities; 2 using Unity.Mathematics; 3 using Unity.Rendering; 4 using Unity.Transforms; 5 using UnityEngine; 6 using Random = UnityEngine.Random; 7 8 [disableAutoCreation] 9 public class ECSMoveSy@R_502_6063@ : Sy@R_502_6063@Base 10 { 11 private Mesh _mesh; 12 private Material _material; 13 14 private EntityManager _entityManager; 15 private EntityArchetype _archetype; 16 17 private Entity[] _entities; 18 19 protected override void OnCreate() 20 { 21 base.OnCreate(); 22 23 AssetHolder assetHolder = Resources.Load<GameObject>("AssetHolder").GetComponent<AssetHolder>(); 24 _mesh = assetHolder.mesh; 25 _material = assetHolder.material; 26 27 World world = World.DefaultGameObjectInjectionWorld; 28 _entityManager = world.EntityManager; 29 30 _archetype = _entityManager.CreateArchetype( 31 ComponentType.ReadOnly<LocalToWorld>(), 32 ComponentType.ReadOnly<RenderMesh>(), 33 ComponentType.ReadWrite<RenderBounds>(), 34 ComponentType.ReadOnly<Translation>(), 35 ComponentType.ReadOnly<Rotation>(), 36 ComponentType.ReadOnly<ECSMoveData>() 37 ); 38 } 39 40 public void CreateallEntity(int maxCount, float randomNum) 41 { 42 _entities = new Entity[maxCount]; 43 for (int i = 0; i < maxCount; i++) 44 { 45 float x = Random.value * randomNum * 2 - randomNum; 46 float y = Random.value * randomNum * 2 - randomNum; 47 float z = Random.value * randomNum * 2 - randomNum; 48 _entities[i] = CreateEntity(x, y, z); 49 } 50 } 51 52 private Entity CreateEntity(float x, float y, float z) 53 { 54 Entity entity = _entityManager.CreateEntity(_archetype); 55 _entityManager.SetComponentData(entity, new LocalToWorld() 56 { 57 Value = new float4x4(rotation: quaternion.identity, translation: new float3(0, 0, 0)) 58 }); 59 _entityManager.SetSharedComponentData(entity, new RenderMesh() 60 { 61 mesh = _mesh, 62 material = _material 63 }); 64 _entityManager.SetComponentData(entity, new RenderBounds() 65 { 66 Value = new AABB() 67 { 68 Center = new float3(0, 0, 0), 69 Extents = new float3(0.5f, 0.5f, 0.5f) 70 } 71 }); 72 _entityManager.SetComponentData(entity, new Translation() 73 { 74 Value = new float3(x, y, z) 75 }); 76 _entityManager.SetComponentData(entity, new Rotation() 77 { 78 Value = quaternion.identity 79 }); 80 float movedistance = Random.Range(0.5f, 1f) * 5; 81 _entityManager.SetComponentData(entity, new ECSMoveData() 82 { 83 rotateSpeed = new float3(Random.value * math.PI * 2, Random.value * math.PI * 2, Random.value * math.PI * 2), 84 moveSpeed = new float3(Random.Range(0.5f, 1f), Random.Range(0.5f, 1f), Random.Range(0.5f, 1f)), 85 movedistance = movedistance, 86 origin = new float3(x, y, z), 87 distanceSqr = movedistance * movedistance 88 }); 89 return entity; 90 } 91 92 protected override void OnUpdate() 93 { 94 float deltaTime = Time.DeltaTime; 95 Entities.ForEach((ref ECSMoveData moveData, ref Translation translation, ref Rotation rotation) => 96 { 97 rotation.Value = math.mul(math.normalize(rotation.Value), 98 quaternion.AxisAngle(moveData.rotateSpeed, deltaTime)); 99 100 translation.Value += new float3(moveData.moveSpeed.x * deltaTime, moveData.moveSpeed.y * deltaTime, 101 moveData.moveSpeed.z * deltaTime); 102 103 if (math.distancesq(translation.Value, moveData.origin) > moveData.distanceSqr) 104 { 105 moveData.moveSpeed = -moveData.moveSpeed; 106 } 107 }).Schedule(); 108 } 109 110 protected override void OnDestroy() 111 { 112 base.OnDestroy(); 113 114 for (int i = 0; i < _entities.Length; i++) 115 { 116 _entityManager.DestroyEntity(_entities[i]); 117 } 118 } 119 }View Code @H_502_0@3. ECSCreateScript.cs,这里创建Sy@R_502_6063@并添加到World中执行:
1 using Unity.Entities; 2 using UnityEngine; 3 4 public class ECSCreateScript : MonoBehavIoUr 5 { 6 public int MaxCount = 10000; 7 8 public float RandomNum = 10f; 9 10 void Start() 11 { 12 World world = World.DefaultGameObjectInjectionWorld; 13 ECSMoveSy@R_502_6063@ moveSy@R_502_6063@ = world.GetorCreateSy@R_502_6063@<ECSMoveSy@R_502_6063@>(); 14 moveSy@R_502[email protected]teallEntity(MaxCount, RandomNum); 15 SimulationSy@R_502_6063@Group sy@R_502_6063@Group = world.GetorCreateSy@R_502_6063@<SimulationSy@R_502_6063@Group>(); 16 sy@R_502[email protected]@R_502_6063@ToUpdateList(moveSy@R_502_6063@); 17 } 18 }View Code @H_502_0@最终效果如下: @H_502_0@
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。