문제의 발견
몬스터 인스턴스가 700개가 넘어갈때쯤 60프레임 이하로 떨어지기 시작했다
수백 수천마리의 몬스터가 나오는 게임에서 이 이상 프레임이 드랍되는건 지양해야하고
또 개발환경은 PC지만 실 플레이는 모바일이기때문에 성능이 더 낮은 모바일 기기에서는
이것보다 더 적은 수에서부터 연산에 과부하가 올것이다.
먼저 충돌 처리에 대해 적합한 방법을 살펴봤다
https://velog.io/@sjhbelieve/Unity%EC%B6%A9%EB%8F%8C%EC%B2%98%EB%A6%AC
Unity_충돌처리
https://cakelemon.tistory.com/3https://3dev.tistory.com/533D 게임을 하다보면 두 물체가 서로 부딪쳤을 때나 혹은 플레이어의 캐릭터가 지형에 겹쳐서 이상하게 반응하거나 하는 경우를 볼 수 있다. 보통 이런
velog.io
AABB의 핵심은 각 오브젝트가 가상의 범위를 가지고있고, 이 범위에 다른 범위가 겹치는지 판단해서 충돌여부를 판단하는것이다.
using UnityEngine;
public class AABB : MonoBehaviour
{
public Vector2 size; // 사각형의 크기
public Vector2 position; // 사각형의 중심 위치
// AABB 충돌 감지 함수
public static bool CheckAABBCollision(Vector2 pos1, Vector2 size1, Vector2 pos2, Vector2 size2)
{
// 각 축에 대해 겹치는지 확인
bool overlapX = Mathf.Abs(pos1.x - pos2.x) < (size1.x / 2 + size2.x / 2);
bool overlapY = Mathf.Abs(pos1.y - pos2.y) < (size1.y / 2 + size2.y / 2);
// 두 축 모두 겹치면 충돌이 발생한 것
return overlapX && overlapY;
}
void Update()
{
// 임의의 다른 사각형을 설정
Vector2 otherPos = new Vector2(2.0f, 2.0f);
Vector2 otherSize = new Vector2(3.0f, 3.0f);
// 현재 사각형과 다른 사각형의 충돌 여부 확인
if (CheckAABBCollision(position, size, otherPos, otherSize))
{
Debug.Log("AABB 충돌 발생!");
}
}
}
먼저 GPT에게 AABB를 구현하는 방법에 대해 물어봤다.
해당 코드에서는 임의로 정해둔 또다른 사각형과의 충돌 여부를 판정한다.
하지만 내가 만드려는것은 수도 없이 많은 오브젝트끼리 상호 비교해야한다.
그래서 여러 물체의 충돌판정을 확인하는 방법을 다시 물어봤다.
요점은 쿼드트리, 그리드분할을 사용해서 AABB를 더욱더 효과적으로 사용할 수있다는것이다.
AABB로 충돌판단을 하되, 무작정 전범위를 체크하는것이 아니라,
특정 조건에 해당하는 대상과 충돌판단을 해서ㅡ 무의미한 연산을 줄이는것이다.
쿼드트리의 핵심은 공간을 지정하고 그 공간의 오브젝트를 관리하는것이다
한 노드가 관리하는 오브젝트가 지정된 숫자를 넘어가면 자식노드 4개로 분할하고,
이는 각각 상좌, 상우, 하좌, 하우로 나뉘고 부모 노드가 가지고있던 오브젝트는 자식노드에게 넘긴다.
충돌판정을 처리하고자 할때, 자신과 같은 노드에 속한 오브젝트를 선별함으로써 불필요한 연산을 줄이는 것이다.
using System.Collections.Generic;
using UnityEngine;
public class AABBQuadTreeTest : MonoBehaviour
{
public List<Rect> rectangles; // 사각형 리스트
private QuadTree quadTree; // 쿼드 트리
void Start()
{
// 쿼드 트리 초기화 (전체 게임 월드의 크기를 나타내는 Rect 설정)
quadTree = new QuadTree(0, new Rect(0, 0, 100, 100));
// 사각형들을 쿼드 트리에 삽입
foreach (Rect rect in rectangles)
{
quadTree.Insert(rect);
}
}
void Update()
{
// 충돌 검사 수행
foreach (Rect rect in rectangles)
{
List<Rect> possibleCollisions = new List<Rect>();
quadTree.Retrieve(possibleCollisions, rect);
foreach (Rect otherRect in possibleCollisions)
{
if (rect != otherRect && AABB.CheckAABBCollision(rect, otherRect))
{
Debug.Log($"충돌 발생: {rect}와 {otherRect}");
}
}
}
}
}
GPT에서 제공한 코드를 그대로 복붙하기에는 내 상황에 안맞는 연산과 리턴값이 미묘하게 잘못 설계되어있어서 내 상황에 맞게 수정해서 사용했다 start함수에서 처음에만 초기화하지만, 나는 실시간으로 계속 변하는 위치값을 파악해서 사용해야하고,
qyadTree.Retrieve는 List<Rect>를 반환하지만 반환값을 받는 부분이 없다.
foreach문에서는 possiblecollisions을 순회하지만 비어있는 리스트이고 리스트에 요소를 넣는 코드가 없다.
특정 Rect가 속한 쿼드의 오브젝트 리스트를 리턴받아 충돌여부를 검사하지만,
나는 굳이 리턴받을필요없이 해당 쿼드에서 바로 충돌여부를 파악하는게 더 빠른 연산을 할 수 있을것같다.
하지만 rect만을 인자로 넘기니 해당 쿼드에서 바로 오브젝트를 제어할수가없어 Enemy 클래스를 넘기는 방식으로 변경해야한다.
마지막으로 각 오브젝트들이 Rect를 가지고있지않으니, 해당 오브젝트에게 Rect를 붙여줘야한다.
몬스터의 rigidbody와 colliderbox 2d를 제거하고 AABB와 쿼드 트리만을 적용해봤다.
몬스터의 rect를 시각적으로 파악하기위해 Line 이펙트를 그려놨다.
충돌판정을 제대로 받아 각 오브젝트가 겹치지않는 모습을 볼수있다. 다만 충돌반응이 어색해서 불필요하게 떠는 모습등이 보인다
발견한 문제점
1. 하나의 쿼드가 수용하는 오브젝트 제한이 적어지면, 충돌판정을 제대로 확인하지못하는 문제
2. 충돌시 서로 반대 방향으로 밀려나는 반응을 구현하였지만, 결과적으로 떨림현상이 나타나는 문제
이부분을 다시 수정해야할것같다.