Posted in: Unity, 메서드 & 팁 정리

Instantiate | 유니티 랜덤 오브젝트 생성

참고문헌
Retro 의 Udemy 유니티 강좌

게임 개발을 하다보면 랜덤으로 게임 오브젝트를 생성해야 할 때가 있습니다. 예를 들면 보스가 대량의 무기를 소환해서 공격한다던가 그런 상황이죠.

이번 게시물에서는 랜덤 오브젝트 생성 방법에 대해 정리 해보겠습니다.

오브젝트가 생성되는 위치와 범위를 먼저 정하자


오브젝트가 생성되는 위치를 정하는 방법은 여러가지 방법이 있을 것입니다. 게임 오브젝트를 하나만 생성할 경우는 매우 간단하니까 패스하고 많은 게임 오브젝트를 한 번에 생성되는 경우를 보겠습니다.

저는 빈 게임오브젝트(Create Empty)를 생성한 후 Box Collider를 컴포넌트 하였습니다. 그 이유는 Box Collider는 사이즈를 가집니다. 이 사이즈를 활용해서 게임 오브젝트의 생성 위치를 설정할 수 있습니다.

무엇보다 좋은 점은 유니티 화면에서 생성되는 위치(범위)를 직관적으로 볼 수 있다는 점입니다.

당연히 Is Trigger 를 체크해서 다른 게임 오브젝트와 충돌하지 않게 해야겠죠? 그리고 빈 게임 오브젝트의 이름을 적절하게 바꿔줍시다. Spawn뭐시기 로 바꾸는 게 좋겠군요.

생성 위치와 오브젝트 생성 스크립트를 만들자


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class 스크립트이름 : MonoBehaviour
{
    public GameObject[] prefabs; //찍어낼 게임 오브젝트를 넣어요
                                 //배열로 만든 이유는 게임 오브젝트를
                                 //다양하게 찍어내기 위해서 입니다
    private BoxCollider area;    //박스콜라이더의 사이즈를 가져오기 위함
    public int count = 100;      //찍어낼 게임 오브젝트 갯수
    
    private List<GameObject> gameObject = new List<GameObject>();
    
    void Start()
    {
        area = GetComponent<BoxCollider>();
        
        for(int i = 0; i < count; ++i)//count 수 만큼 생성한다
        {
            Spawn();//생성 + 스폰위치를 포함하는 함수
        }
        
        area.enabled = false;
    }
//밑에 코드가 더 있습니다

대략적인 스크립트 구조는 위와 같습니다.

prefabs 를 배열로 선언한 이유는 찍어낼 게임 오브젝트의 종류가 여러개이기 때문입니다. 물론 한 종류만 찍어낸다면 굳이 배열로 선언할 이유는 없습니다.

유니티 인스펙터에서 미리 만들어놓은 프리팹에서 복사할 오브젝트들을 넣기만 하면 됩니다.

area 는 위 사진에서 본 것 처럼 BoxCollider 컴포넌트의 size를 사용하기 위함입니다. 박스 콜라이더의 크기가 랜덤으로 생성되는 오브젝트들의 위치인 것이죠.

count 는 말 그대로 생성되는 오브젝트의 갯수입니다.

gameObject 를 리스트로 선언한 이유는 생성되는 게임 오브젝트들을 각각 관리하기 위함입니다. 생성되면 등록해서 관리하면 되는 것이죠.

//해당 함수들은 위 스크립트에 포함되는 함수들임

    private Vector3 GetRandomPosition()
    {
        Vector3 basePosition = transform.position;
        Vector3 size = area.size;
        
        float posX = basePosition.x + Random.Range(-size.x/2f, size.x/2f);
        float posY = basePosition.y + Random.Range(-size.y/2f, size.y/2f);
        float posZ = basePosition.z + Random.Range(-size.z/2f, size.z/2f);
        
        Vector3 spawnPos = new Vector3(posX, posY, posZ);
        
        return spawnPos;
    }

박스 콜라이더가 가지고 있는 size를 활용해서 일정 범위내 랜덤한 위치의 Vector3 값을 반환하는 함수입니다.

basePosition 은 기준이 되는 위치(Vector3)입니다. 게시물 위에서 만들었던 빈 게임오브젝트의 위치죠. 박스 콜라이더는 빈 게임 오브젝트를 기준으로 사이즈를 설정할 수 있으므로 유니티 scene 창에서 원하는 위치로 이동해 놓는 게 중요합니다.

해당 오브젝트의 위치를 기준으로 박스 콜라이더의 size의 범위를 랜덤하게 반환해서 X, Y, Z 값을 구합니다. Random.Range 함수를 적절하게 사용하였죠.

그리고 X, Y, Z 값을 하나로 묶어 새로운 Vector3 변수를 만들고 그 위치가 생성되는 게임 오브젝트의 위치가 됩니다. 그렇다면 게임 오브젝트를 생성하는 코드를 알아봅시다.

//해당 함수들은 위 스크립트에 포함되는 함수들임

    private void Spawn()
    {
        int selection = Random.Range(0, prefabs.Length);
        
        GameObject selectedPrefab = prefabs[selection];
        
        Vector3 spawnPos = GetRandomPosition();//랜덤위치함수
        
        GameObject instance = Instantiate(selectedPrefab, spawnPos, Quaternion.identity);
        gameObject.Add(instance);
    }
}//스크립트 종료

랜덤한 게임 오브젝트를 생성하는 함수입니다. 앞서 랜덤위치함수를 먼저 알아보았는데요. 게임 오브젝트를 생성하면서 위치를 설정해줘야 하기 때문에 랜덤 위치 함수를 먼저 설명했습니다.

selection int형 변수를 랜덤한 값(생성할 오브젝트의 종류 중에서)으로 초기화하여 선언하였습니다. 그 이유는 처음 스크립트를 만들면서 우리는 prefabs 라는 게임오브젝트 타입의 배열을 만들었습니다. 그 배열의 길이를 Random.Range로 랜덤하게 설정하면 selection 변수는 랜덤한 정수가 나오겠지요.

selectedPrefab 는 게임 오브젝트인데 보시면 아시겠지만 selection 변수를 활용해서 배열 내에서 게임 오브젝트를 선택해 대입시켜 주고 있습니다. 결과적으로 랜덤 게임 오브젝트가 선택되는 것입니다.

spawnPos 는 위에서 설명했었던 스폰되는 위치(박스 콜라이더의 사이즈를 활용한) 랜덤 위치를 대입받습니다.

instance 는 아시다싶이 Instantiate 함수로 복제품을 찍어냅니다. Instantiate 함수는 원본, 위치값, 회전값을 매개변수로 받습니다. 위 코드를 보면 순서대로 잘 넣어져 있습니다. Quaternion.identity 는 회전값이 0을 뜻합니다.

그리고 마지막으로 리스트에 복제된 게임 오브젝트를 넣어(Add)줍니다. 이는 각각의 게임 오브젝트를 관리하기 위함입니다.

정상적으로 2종류의 게임 오브젝트가 랜덤하게 생성되었습니다. 생성되는 위치는 박스 콜라이더 사이즈 랜덤 위치입니다.

Comments (3) on "Instantiate | 유니티 랜덤 오브젝트 생성"

  1. (살짝 수정) box colider 공간 내에 물체가 충돌을 인식하면 box colider 안에서 랜덤 이동 할 수 있나요?

    1. 해당 물체가 출동하면 호출되는 OnCollisionEnter 메서드를 활용하고
      레퍼런스로 물체를 옮길 box collider를 가져온 후 box collider 사이즈 안에서 랜덤값으로 물체를 이동시키면 되겠네요.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다