Step 8 - 세이프 존(Safe zone)
싱글턴 구성, 실시간 변환.
- "Scripts/Components" 폴더에 "Shooting.cs"이라는 이름의 새 C# 스크립트 파일을 만들고 다음 내용을 저장합니다:
-
using Unity.Entities; // 이 태그 컴퍼넌트는 "사용 가능한 컴퍼넌트"이기도 합니다. // 이러한 컴퍼넌트들은 엔티티에 존재하는 동안 온/오프 될 수 있습니다. // 이렇게 하는 것이 컴퍼넌트를 추가하거나 제거하는 것보다 훨씬 효율적입니다. struct Shooting : IComponentData, IEnableableComponent { }
- "Scripts/Authoring" 폴더에 있는 "TurretAuthoring.cs" 파일의 내용을 다음과 같이 수정합니다:
-
using Unity.Entities; class TurretAuthoring : UnityEngine.MonoBehaviour { public UnityEngine.GameObject CannonBallPrefab; public UnityEngine.Transform CannonBallSpawn; } class TurretBaker : Baker<TurretAuthoring> { public override void Bake(TurretAuthoring authoring) { AddComponent(new Turret { CannonBallPrefab = GetEntity(authoring.CannonBallPrefab), CannonBallSpawn = GetEntity(authoring.CannonBallSpawn) }); + // 활성화된 컴퍼넌트들은 항상 초기에 활성화됩니다. + AddComponent<Shooting>(); } }
- "Scripts/Systems" 폴더에 "SafeZoneSystem.cs"이라는 이름의 새 C# 스크립트 파일을 만들고 다음 내용을 저장합니다.
-
using Unity.Burst; using Unity.Collections; using Unity.Entities; using Unity.Mathematics; using Unity.Transforms; // Turret type을 처리없이 사용해야 합니다(Execute 메서드에 포함되지 않음). [WithAll(typeof(Turret))] [BurstCompile] partial struct SafeZoneJob : IJobEntity { // 이 작업을 병렬로 실행할 경우, 서로 다른 스레드에서 동일한 엔티티에 액세스하면 문제가 발생하여 // 세이프티 시스템에서 TurretActiveFromEntity와의 잠재적인 경합 상태에 대해 항의합니다. // 그러나 이 작업의 코드는 현재 처리 중인 엔티티만 TurretActiveFromEntity에서 조회되도록 작성되어 // 이 프로세스를 안전하게 만듭니다. // 그래서 우리는 병렬 세이프티 체크를 비활성화할 수 있습니다. [NativeDisableParallelForRestriction] public ComponentLookup<Shooting> TurretActiveFromEntity; public float SquaredRadius; void Execute(Entity entity, TransformAspect transform) { // 슈팅 태그 컴퍼넌트는 탱크가 지정된 범위를 벗어나는 경우에만 활성화됩니다. TurretActiveFromEntity.SetComponentEnabled(entity, math.lengthsq(transform.Position) > SquaredRadius); } } [BurstCompile] partial struct SafeZoneSystem : ISystem { // ComponentLookup 랜덤 접근자는 즉석에서 생성해서는 안 됩니다. // EntityQuery처럼, 한 번 만들고 필드에 저장해야 합니다. ComponentLookup<Shooting> m_TurretActiveFromEntity; [BurstCompile] public void OnCreate(ref SystemState state) { state.RequireForUpdate<Config>(); m_TurretActiveFromEntity = state.GetComponentLookup<Shooting>(); } [BurstCompile] public void OnDestroy(ref SystemState state) { } [BurstCompile] public void OnUpdate(ref SystemState state) { float radius = SystemAPI.GetSingleton<Config>().SafeZoneRadius; const float debugRenderStepInDegrees = 20; // Debug rendering (the white circle). for (float angle = 0; angle < 360; angle += debugRenderStepInDegrees) { var a = float3.zero; var b = float3.zero; math.sincos(math.radians(angle), out a.x, out a.z); math.sincos(math.radians(angle + debugRenderStepInDegrees), out b.x, out b.z); UnityEngine.Debug.DrawLine(a * radius, b * radius); } m_TurretActiveFromEntity.Update(ref state); var safeZoneJob = new SafeZoneJob { TurretActiveFromEntity = m_TurretActiveFromEntity, SquaredRadius = radius * radius }; safeZoneJob.ScheduleParallel(); } }
- 다음과 같이 "Scripts/Systems" 폴더에 있는 "TurretShootingSystem.cs" 파일의 내용을 수정합니다:
-
+// 슈팅 태그 컴퍼넌트의 요구로 인해 안전 영역에 있는 탱크에 대해 이 작업이 실행되는 것을 사실상 방지합니다. +[WithAll(typeof(Shooting))] [BurstCompile] partial struct TurretShoot : IJobEntity { [ReadOnly] public ComponentLookup<LocalToWorldTransform> LocalToWorldTransformFromEntity; public EntityCommandBuffer ECB; void Execute(in TurretAspect turret) { var instance = ECB.Instantiate(turret.CannonBallPrefab); var spawnLocalToWorld = LocalToWorldTransformFromEntity[turret.CannonBallSpawn]; var cannonBallTransform = UniformScaleTransform.FromPosition(spawnLocalToWorld.Value.Position); cannonBallTransform.Scale = LocalToWorldTransformFromEntity[turret.CannonBallPrefab].Value.Scale; ECB.SetComponent(instance, new LocalToWorldTransform { Value = cannonBallTransform }); ECB.SetComponent(instance, new CannonBall { Speed = spawnLocalToWorld.Value.Forward() * 20.0f }); // 아래 라인은 포탑에서 대포알까지 색을 전파합니다. ECB.SetComponent(instance, new URPMaterialPropertyBaseColor { Value = turret.Color }); } }
- 플레이 모드로 들어가면 탱크가 세이프 존 밖으로 나온 후에만 사격합니다. 보기 옵션에서 gizmos가 활성화 되었는지 확인하세요, 그렇지 않으면 흰색 원이 표시되지 않습니다.
- 여전히 플레이 모드에서, 제작된 "Config" GameObject를 선택하고 "Safe Zone Radius"를 수정합니다. "Live Baking" 덕분에 변경 사항이 실시간으로 반영됩니다.
- 플레이 모드에서 나오세요.
