ETC/Unity

[Unity] 2D 쿼터뷰 공간 바닥에 랜덤 스폰하기

Jade Choe 2024. 4. 4. 13:28
SMALL

개발 진행중인 프로젝트는 2D게임인데, 쿼터뷰 형식으로 되어있다.

3D공간에 물체를 배치하고 Orthographic View로 보여주는게 아니라 각각의 장소가 모두 1장의 Sprite이다.

 

그렇기 때문에 공간 내에 물체를 랜덤하게 배치할 때 계산을 자칫 잘못하면 맵 밖으로 튀어나가거나 공중에 붕 떠있는 것처럼 보이게 된다.

 

 

 

위와 같은 상황을 방지하기 위해 바닥면을 기준으로 오브젝트를 배치해 주어야 하는데,

바닥면의 좌표를 구하는 방법은 축과 평행하지 않은 평면상의 좌표를 구하는 것과 같다.

 

먼저 바닥 위에 배치할 오브젝트 Sprite의 Pivot포인트를 Bottom으로 설정해 준다.

 

그 다음 위 그림과 같이 바닥면의 네 꼭짓점에 적당한 Padding을 준 위치에 네 개의 Empty Object를 생성한다.

 

 

    public GameObject[] vertexList = new GameObject[4];

그 다음 스크립트를 생성해 네 꼭짓점의 GameObject를 담아준다.

    public Vector2 GetRandomPosInPlace()
    {
        Vector3 top = vertexList[0].transform.position;
        Vector3 bottom = vertexList[1].transform.position;
        Vector3 left = vertexList[2].transform.position;
        Vector3 right = vertexList[3].transform.position;
        
        Vector2 diagonalPoint1 = Vector2.Lerp(top, bottom, Random.value);
        Vector2 diagonalPoint2 = Vector2.Lerp(left, right, Random.value);
        
        return Vector2.Lerp(diagonalPoint1, diagonalPoint2, Random.value);
    }

 

각 대각선 방향 점 사이의 좌표를 선형 보간 함수로 랜덤하게 뽑은 다음

두 좌표 사이를 다시 선형 보간하면 최종적으로 아래 그림과 같이 나온다.

 

 

여기서 끝내면 정말 좋겠지만...

아래 그림과 같이 Sprite의 순서가 맞지 않으면 부자연스러워진다.

 

Y좌표를 먼저 정규화한 뒤 100을 곱해보자

 

    public Vector2 GetRandomPosInPlace(out int OrderInLayer)
    {
        Vector3 top = vertexList[0].transform.position;
        Vector3 bottom = vertexList[1].transform.position;
        Vector3 left = vertexList[2].transform.position;
        Vector3 right = vertexList[3].transform.position;

        Vector2 diagonalPoint1 = Vector2.Lerp(top, bottom, Random.value);
        Vector2 diagonalPoint2 = Vector2.Lerp(left, right, Random.value);

        Vector2 finalPos = Vector2.Lerp(diagonalPoint1, diagonalPoint2, Random.value);

        float Normalized_FinalPosY = (finalPos.y - top.y) / (top.y - bottom.y);
        OrderInLayer = System.Math.Abs((int)(Normalized_FinalPosY * 100));

        return finalPos;
    }

 

 

 

 

    public void SpawnNPC(string npcName)
    {
        int OrderInLayer;
        Vector3 pos = CurrentPlace.GetComponent<SpawnOnFloor>().GetRandomPosInPlace(out OrderInLayer);
        GameObject npc = Instantiate(npcList[npcName], pos, Quaternion.identity);
        npc.transform.SetParent(CurrentPlace.transform);

        SpriteRenderer sr = npc.GetComponent<SpriteRenderer>();
        sr.sortingOrder = OrderInLayer;
    }
BIG