1. Bullet, Character 충돌 처리
foreach ((var bullet, var bulletTransform, var bulletHitLayer) in SystemAPI.Query<RefRW<BulletComponent>, RefRO<LocalTransform>, RefRO<HitLayerComponent>>())
{
foreach ((var character, var characterTransform, var characterHitLayer) in SystemAPI.Query<RefRW<CharacterComponent>, RefRO<LocalTransform>, RefRO<HitLayerComponent>>())
{
if (math.distancesq(new Vector2(characterTransform.ValueRO.Position.x, characterTransform.ValueRO.Position.z), new Vector2(bulletTransform.ValueRO.Position.x, bulletTransform.ValueRO.Position.z)) <= (characterHitLayer.ValueRO.hitboxRadius + bulletHitLayer.ValueRO.hitboxRadius) * (characterHitLayer.ValueRO.hitboxRadius + bulletHitLayer.ValueRO.hitboxRadius) &&
bulletHitLayer.ValueRO.attackLayerMask.HasFlag(characterHitLayer.ValueRO.hitLayer) == true)
{
character.ValueRW.HP = math.max(character.ValueRO.HP - bullet.ValueRO.Damage, 0);
bullet.ValueRW.isDestroyed = true;
}
}
}
간단하게 2중으로 쿼리를 해서 만들었는데 정상 작동합니다.
문제는 Character와 Bullet이 늘어나면 GC문제도 프레임드랍이 발생한다는 것.
오늘은 이걸 해결해보기 위해 여러 방법을 사용해 봤습니다.
2. JobSystem으로 시도
일단 첫 번째 문제가 발생했는데 위 코드처럼 2중반복문 처럼 돌아가려면 bullet 루프 도는 Job 하나, character 루프 도는 Job 하나 이렇게 둘로 나뉘어서 Job에서 Job을 Schedule할 수 있도록 짤 예정이었다.
하지만, character Job으로 BulletComponent를 넘겨주고 수정이 이루어져야 하는데 이 부분을 해결하지 못해서 Job System으로는 포기함.
어떻게든 Job System으로 하고싶은데 혹시 아는 분 댓글 남겨주세요.
3. Physics로 시도
이전에 Physics 패키지를 등록하고 Trigger이벤트를 동작시켰을 때 처럼 해보려고 시도함.
물론 기존 유니티에서 Rigidbody처럼 사용하려고 Freeze Position, Freeze Rotation에 체크했는데, 이게 동작하지 않아서 사실상 다른 게 잘 동작하더라도 쓸 수가 없다.
4. 코드 개선
var characterQuery = state.EntityManager.CreateEntityQuery(typeof(CharacterComponent), typeof(LocalTransform), typeof(HitLayerComponent));
var characterEntities = characterQuery.ToEntityArray(Allocator.Temp);
var characters = characterQuery.ToComponentDataArray<CharacterComponent>(Allocator.Temp);
var characterTransforms = characterQuery.ToComponentDataArray<LocalTransform>(Allocator.Temp);
var characterHitLayers = characterQuery.ToComponentDataArray<HitLayerComponent>(Allocator.Temp);
foreach ((var bullet, var bulletTransform, var bulletHitLayer) in SystemAPI.Query<RefRW<BulletComponent>, RefRO<LocalTransform>, RefRO<HitLayerComponent>>())
{
for (int i = 0; i < characterEntities.Length; i ++)
{
var characterTransform = characterTransforms[characterIndex];
var characterHitLayer = characterHitLayers[characterIndex];
var checkDistance = math.distancesq(new float2(characterTransform.Position.x, characterTransform.Position.z), new float2(bulletTransform.ValueRO.Position.x, bulletTransform.ValueRO.Position.z)) <= (characterHitLayer.hitboxRadius + bulletHitLayer.ValueRO.hitboxRadius) * (characterHitLayer.hitboxRadius + bulletHitLayer.ValueRO.hitboxRadius);
var checkLayer = (bulletHitLayer.ValueRO.attackLayerMask & characterHitLayer.hitLayer) > 0;
if (checkDistance && checkLayer)
{
var character = characters[i];
character.HP = math.max(character.HP - bullet.ValueRO.Damage, 0);
state.EntityManager.SetComponentData(characterEntities[i], character);
bullet.ValueRW.isDestroyed = true;
}
}
}
characterEntities.Dispose();
characters.Dispose();
characterTransforms.Dispose();
characterHitLayers.Dispose();
characterQuery.Dispose();
일단은 쿼리를 두 번 하는 게 너무 부담이라 character 쿼리는 먼저 하기로 했다.
var characterTransform = characterTransforms[characterIndex];
var characterHitLayer = characterHitLayers[characterIndex];
Profiler를 계속 보면서 알게 된 내용인데, NativeArray에서 값을 참조해 올 때마다 GC가 꽤 발생한다.
한번 이렇게 변수에 담아두고 쓰는 게 좋다.
대충 시간 기준으로는 반토막 낸 것 같다.
오늘 삽질의 경험 잊지 않는다.
'Study Log' 카테고리의 다른 글
Unity ECS Study Log - 8 (0) | 2023.01.24 |
---|---|
Unity ECS Study Log - 6 (0) | 2023.01.15 |
Unity ECS Study Log - 5 (0) | 2023.01.14 |
Unity ECS Study Log - 4 (0) | 2023.01.09 |
Unity ECS Study Log - 3 (1) | 2023.01.07 |