[Unity] 특정 범위 내에서 랜덤한 위치에 오브젝트 스폰하기

PenguinGod·2021년 7월 11일
8
post-thumbnail
post-custom-banner

unity에서 특정 범위 내에 랜덤한 위치에 오브젝트를 생성하는 방법을 알아보겠습니다.

우선 unity에서 원하는 범위를 특정해봅시다.

저는 이 Plane 오브젝트 위에서 랜덤한 위치에 캡슐이 생성되었으면 좋겠네요

그러기 위해 우선 Plane에 자식 오브젝트인 RespawnRange를 추가하고 Plane의 크기와 얼추 비슷하게 콜라이더를 부여합시다.


위치가 Plane의 가운데에 오도록 position은 0, 0, 0 으로 하겠습니다

그리고 바로 코드를 짜보도록 합시다.
코드를 짤 때 가장 중요한 요점은 저희가 정한 범위 내에서 랜덤하게 나오는 Vector값을 얻는 것입니다.

저는 원하는 값을 얻기 위해 RespawnRange의 포지션 값을 지닌 Vector3 변수를 만들고 콜라이더의 사이즈를 이용해 콜라이더 범위 내에서 랜덤한 위치를 가진 백터값을 구한 후 서로의 백터값을 더하도록 할 생각입니다. 말로 하면 어렵기만 하니 바로 코드를 짜보죠

    // 위에서 언급한 Plane의 자식인 RespawnRange 오브젝트
    public GameObject rangeObject;
    BoxCollider rangeCollider;
    
    private void Awake()
    {
        rangeCollider = rangeObject.GetComponent<BoxCollider>();
    }
    
    Vector3 Return_RandomPosition()
    {
        Vector3 originPosition = rangeObject.transform.position;
        // 콜라이더의 사이즈를 가져오는 bound.size 사용
        float range_X = rangeCollider.bounds.size.x;
        float range_Z = rangeCollider.bounds.size.z;
        
        range_X = Random.Range( (range_X / 2) * -1, range_X / 2);
        range_Z = Random.Range( (range_Z / 2) * -1, range_Z / 2);
        Vector3 RandomPostion = new Vector3(range_X, 0f, range_Z);

        Vector3 respawnPosition = originPosition + RandomPostion;
        return respawnPosition;
    }

우선 위 코드는 제가 설정한 콜라이더 범위 내에서 랜덤한 위치의 Vector3 값을 반환하는 함수를 만드는 코드입니다.

먼저 Plane의 자식인 RespawnRange를 GameObject변수인 rangeObject로 가져오고 콜라이더의 사이즈를 가져오기 위해 필요한 변수 rangeCollider를 Awake에서 할당합니다.

이제 함수 내부를 봅시다.
먼저 rangeObject의 현재 위치값을 가진 Vector 변수인 originPosition을 선언합니다.

그 후 위에서 설정한 콜라이더의 사이즈를 가져온 후 좌표 방향에 맞게
range_X, range_Z 변수에 할당합니다. 이러면 range_X는 콜라이더의 x범위 range_Z는 z범위를 가지게 됩니다.
그리고 Random.Range() 함수를 이용해 콜라이더의 사이즈를 반으로 나눈 값에 -1을 곱한 값부터 곱하지 않은 값이 랜덤으로 나오게 하였고 이를 이용해 새로운 Vector3 변수인 RandomPostion을 선언합니다.

그 후 위에서 구한 두 변수를 합한 respawnPosition 선언한 후 return합니다.

위에서 중요한 부분은 originPosition 변수는 생성 위치에 기준이 되는 값이고 랜덤하게 이동하는 값은 콜라이더의 사이즈를 기반으로 만든 RandomPostion 변수라는 부분입니다.


이제 위에서 만든 함수를 사용해 실제로 오브젝트를 소환합시다.

    // 소환할 Object
    public GameObject capsul;
    private void Start()
    {
        StartCoroutine(RandomRespawn_Coroutine());
    }

    IEnumerator RandomRespawn_Coroutine()
    {
        while (true)
        {
            yield return new WaitForSeconds(1f);

            // 생성 위치 부분에 위에서 만든 함수 Return_RandomPosition() 함수 대입
            GameObject instantCapsul = Instantiate(capsul, Return_RandomPosition(), Quaternion.identity);
        }
    }

오브젝트를 1초마다 소환하도록 코루틴을 사용했습니다.

위 코드에서 중요한 부분은 Instantiate() 함수 사용 부분이겠죠
GameObject변수를 소환해주는 함수인 Instantiate는 인자값으로 소환할 오브젝트, 오브젝트를 소환할 위치, 오브젝트의 회전값을 받습니다.

주목할 부분은 오브젝트를 소환할 위치 부분입니다. 저는 소환 위치에 위에서 제작한 함수 Return_RandomPosition() 넣어 제가 원하는 범위 내에서 랜덤한 위치에 오브젝트가 생성되도록 하였습니다.


이제 unity에서 실행해 봅시다.

물론 그 전에 Scirpt를 오브젝트에 할당해야겠죠? 저는 미리 만들어놓은 GameManager 오브젝트를 사용하겠습니다.


미리 만들어놓은 Capsule 프리펩과 ResapwRange를 알맞은 변수에 대입해주겠습니다.


자 이제 진짜로 실행을 해보겠습니다.

저희가 원하는 범위 내에서 캡슐이 소환됩니다.

그리고 이 코드의 특징이라 할 수 있는 부분은 Plane의 위치를 바꿔도 콜라이더 범위 내에서 캡슐이 생성된다는 점입니다.
이 부분을 이해하기 위해서는 position과 localposition의 차이를 알아야 하는데요
인스펙터 창에서 RespawnRange의 transform 포지션 값은 0, 0, 0으로 되어 있지만 이는 제가 코드를 짤 때 시용한 transform.position 이 아닌 transform.localposition 값입니다. localpositon은 부모 트랜스폼에 대한 상대적인 위치를 나타내며 월드 공간에서의 위치를 나타내는positoin값과는 다릅니다.

위 2장의 사진 중 첫번째 사진을 보시면 Plane의 위치를 바꿔도 인스텍터 창의 position값은 부모인 Plane과 얼마나 차이가 나는지를 나타내는 localposition값이기 때문에 0, 0, 0으로 나오지만 더 이상 Plane의 자식이 아닌 2번째 사진에서는 값이 -6.98, 0, 1.53으로 값이 다르게 나오는 것을 볼 수 있습니다.

그리고 저는 코드를 짤 때 2번째 사진에 나오는 값인 transform.position을 기준으로 오브젝트의 생성 위치를 구했습니다.

그렇기 때문에 위에 사진에서 Plane의 위치를 바꿔도 콜라이더 내에서 캡슐이 생성되는 모습을 확인할 수 있습니다.


위의 내용이 여러분에게 조금이라도 도움이 되었기를 바라며 끝까지 봐주셔서 갑사합니다.

혹여 틀리거나 잘못된 내용이 있다면 과감히 지적해 주시기 바랍니다.

profile
수강신청 망친 새내기 개발자
post-custom-banner

4개의 댓글

comment-user-thumbnail
2021년 7월 12일

감사합니다~!!!
이거 궁금했었는데 해결됐어요 ^^

답글 달기
comment-user-thumbnail
2022년 5월 29일

혹시 GameManager는 어떻게 만드셨는 지 알 수 있을까요...? 처음부터 따라해보려고 하는데 어떻게 만드셨는지 몰라 참고하고싶어 여쭤봅니다...ㅎ

1개의 답글
comment-user-thumbnail
2022년 10월 12일

유용한 정보글 감사합니다!

답글 달기