Config 싱글톤, 실시간 변환.
1. "Authoring/Components" 폴더에 "Shooting.cs"라는 이름의 새 C# 소스 파일을 만들고 아래 코드를 작성합니다.
using Unity.Entities;
// 이것은 "Enableable Component"이기도 한 태그 구성 요소입니다.
// 이러한 Component는 Entity에 남아 있는 동안 켜고 끌 수 있습니다.
// 그렇게 하는 것이 Component를 추가하고 제거하는 것보다 훨씬 효율적입니다.
struct Shooting : IComponentData, IEnableableComponent
{
}
2. "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)
});
+ // Enableable Component는 초기에 항상 활성화됩니다.
+ AddComponent<Shooting>();
}
}
}
struct Turret : IComponentData
{
// 이 Entity는 포탄이 스폰되는 포탄의 포문을 참조합니다.
public Entity CannonBallSpawn;
// 이 Entity는 대포가 발사될 때마다 생성되는 Prefab을 참조합니다.
public Entity CannonBallPrefab;
}
3. "Scripts/Systems" 폴더에 "SafeZoneSystem.cs"라는 새 C# 소스 파일을 만들고 아래 코드를 작성합니다.
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
// 처리하지 않고 Turret 유형이 필요합니다(Execute 메서드의 일부가 아님).
[WithAll(typeof(Turret))]
[BurstCompile]
partial struct SafeZoneJob : IJobEntity
{
// 이 Job을 병렬로 실행할 때 안전 시스템은 다른 스레드에서 동일한 Entity에 액세스하면 문제가 발생할 수 있으므로 ShootingLookup과의 잠재적 경쟁 조건(race condition)에 대해 불평합니다.
// 하지만 이 Job의 코드는 현재 처리 중인 Entity만 TurretActiveFromEntity에서 조회하도록 작성되어 이 프로세스를 안전하게 만듭니다.
// 따라서 병렬 안전 검사를 비활성화할 수 있습니다.
[NativeDisableParallelForRestriction] public ComponentLookup<Shooting> ShootingLookup;
public float SquaredRadius;
void Execute(Entity entity, TransformAspect transform)
{
// Tag Component인 Shooting은 탱크가 주어진 범위 밖에 있는 경우에만 활성화됩니다.
ShootingLookup.SetComponentEnabled(entity, math.lengthsq(transform.Position) > SquaredRadius);
}
}
[BurstCompile]
partial struct SafeZoneSystem : ISystem
{
// ComponentLookup 임의 접근자(random accessors)는 그 자리에서 생성되어서는 안 됩니다.
// EntityQuery와 마찬가지로 한 번 생성되어 필드에 저장되어야 합니다.
ComponentLookup<Shooting> m_ShootingLookup;
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<Config>();
m_ShootingLookup = 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
{
ShootingLookup = m_ShootingLookup,
SquaredRadius = radius * radius
};
safeZoneJob.ScheduleParallel();
}
}
4. "Scripts/Systems" 폴더에 있는 "TurretShootingSystem.cs" 파일의 내용을 아래와 같이 수정합니다.
+// Shooting Tag Component를 요구하면 Safe Zone에 있는 탱크에 대해 이 Job이 실행되는 것을 효과적으로 방지할 수 있습니다.
+[WithAll(typeof(Shooting))]
[BurstCompile]
partial struct TurretShoot : IJobEntity
{
[ReadOnly] public ComponentLookup<WorldTransform> WorldTransformLookup;
public EntityCommandBuffer ECB;
void Execute(in TurretAspect turret)
{
var instance = ECB.Instantiate(turret.CannonBallPrefab);
var spawnLocalToWorld = WorldTransformLookup[turret.CannonBallSpawn];
var cannonBallTransform = LocalTransform.FromPosition(spawnLocalToWorld.Position);
cannonBallTransform.Scale = WorldTransformLookup[turret.CannonBallPrefab].Value.Scale;
ECB.SetComponent(instance, cannonBallTransform);
ECB.SetComponent(instance, new CannonBall
{
Speed = spawnLocalToWorld.Value.Forward() * 20.0f
});
// 아래 코드는 포탑에서 대포알로 색상을 전파합니다.
ECB.SetComponent(instance, new URPMaterialPropertyBaseColor { Value = turret.Color });
}
}
5. 플레이 모드로 들어가십시오. 탱크는 Safe Zone을 벗어나야만 사격을 합니다. view options에서 Gizmos 활성화되어 있는지 확인하십시오. 그렇지 않으면 흰색 원이 표시되지 않습니다.
6. 여전히 플레이 모드에서 authoring GameObject "Config"를 선택하고 "Safe Zone Radius"를 수정합니다. "라이브 변환" 덕분에 변경 사항이 실시간으로 반영됩니다 (Unity 설정(Preferences)의 "Entities" 참조).
7. 플레이 모드를 종료합니다.
'Unity Entities Tutorial' 카테고리의 다른 글
Unity Entities 1.0.0 Tutorial - Step 9. Camera follow (0) | 2023.01.29 |
---|---|
Unity Entities 1.0.0 Tutorial - Step 7. Colored tanks and cannon balls (0) | 2023.01.29 |
Unity Entities 1.0.0 Tutorial - Step 6. Spawning many tanks (0) | 2023.01.29 |
Unity Entities 1.0.0 Tutorial - Step 5. Cannon ball movement (0) | 2023.01.29 |
Unity Entities 1.0.0 Tutorial - Step 4. Cannon Balls (1) | 2023.01.28 |