본문 바로가기
게임 프로그래밍/게임개발 중급

게임개발 중급(28) - 3D 게임 만들기(8)

by jyppro 2023. 5. 19.

3D 게임 만들기(8)

이전에는 경계의 생성방식을 다르게 하여 만들어 보았습니다. 원래는 이번에 플레이어가 아이템을 먹으면 일정시간이 지난 후, 같은 자리에 다시 생겨나도록 하는 아이템 리스폰에 대해 알아보려 했으나 생각해보니 같은 자리에 생성되면 의미가 없다고 생각하여 랜덤하게 생성하는 방법에 대해 알아보겠습니다.

 

아이템 프리팹화

저는 초반에 프리팹을 사용하지 않아도 될 것 같다고 판단하여 아이템을 프리팹화 시키지 않고 사용했습니다. 하지만 이렇게 생성과 관련된 일을 해줘야 할 때에는 프리팹화가 거의 필수적입니다. 아이템으로 사용중이던 오브젝트 하나를 그대로 프리팹화 시켜서 Prefabs 폴더를 만들어 보관해 줍니다. 프리팹화 시켰다면, 기존의 아이템 오브젝트들은 전부 삭제합니다. 이제 스크립트를 작성해 주어야 합니다. 이번에는 조금 복잡할 수 있습니다.

 

ItemManager

using UnityEngine;

public class ItemManager : MonoBehaviour
{
    public GameObject itemPrefab;
    public int itemCount = 10;

    private void Start()
    {
        SpawnItems();
    }

    private void SpawnItems()
    {
        for (int i = 0; i < itemCount; i++)
        {
            Vector3 spawnPosition = GetRandomSpawnPosition();
            Instantiate(itemPrefab, spawnPosition, Quaternion.identity);
        }
    }

    public void RespawnItem(GameObject item)
    {
        StartCoroutine(RespawnAfterDelay(item));
    }

    private System.Collections.IEnumerator RespawnAfterDelay(GameObject item)
    {
        yield return new WaitForSeconds(3f);
        Vector3 spawnPosition = GetRandomSpawnPosition();
        item.transform.position = spawnPosition;
        item.SetActive(true);
    }

    private Vector3 GetRandomSpawnPosition()
    {
        // 아이템이 생성될 위치를 랜덤하게 결정합니다.
        // 원하는 위치 범위에 맞게 수정해주세요.
        float x = Random.Range(-3f, 3f);
        float y = Random.Range(0f, 2f);
        float z = Random.Range(-3f, 3f);

        return new Vector3(x, y, z);
    }
}

새로운 ItemManager 스크립트를 생성하였습니다. 이것은 아이템 프리팹을 사용하여 게임을 시작할 때에 일정 갯수만큼의 아이템을 생성하고, 플레이어가 아이템을 먹을 때마다, 일정 시간이 지난 후 랜덤한 위치에 아이템이 리스폰되게 하는 코드입니다. 즉, 무한히 아이템을 먹을 수 있는 것입니다. 생성하는 아이템의 갯수나 랜덤생성 위치, 생성시간 등은 제 게임에 맞도록 임의로 설정한 것이니 수치 변경이 가능합니다.

 

해당 스크립트에서 중요한 역할을 해주는 반복 코드가 있습니다. 바로 Instantiate()와 StartCoroutine()입니다. Instantiate()는 이전에 프리팹을 생성할 때 사용되는 것이라 설명을 드렸습니다. StartCoroutine()은 앞으로 유니티의 많은 부분에서 사용하게 될 코루틴의 일종입니다. 코루틴은 말 그대로 계속 반복되는 Routine(루틴)같은 행동을 묶어서 동작시키는 방식이라 생각하시면 편합니다. 해당 스크립트에서는 코루틴에서 3초의 대기시간설정, 스폰위치 설정, 아이템 활성화를 담당하고 있습니다. 사실상 리스폰의 역할을 하고있는 셈입니다. 코루틴을 사용하는 데에는 특정한 문법이 정해져있습니다. 그것에 대해선 추후에 더 자세히 설명하겠습니다.

 

해당 스크립트는 아이템을 먹는 처리를 해주는 PlayerController가 있는 오브젝트에 넣어주어야 합니다. 그러니 플레이어에게 스크립트를 적용시켜줍니다. 그렇게 하는 이유는  RespawnItem 함수를 PlayerController에서 실행 시켜줘야 하기 때문입니다. 또한, PlayerController도 약간의 코드변경이 필요합니다.

other.gameObject.SetActive(false);

GetComponent<ItemManager>().RespawnItem(other.gameObject);

이것은 PlayerController안에 아이템과 충돌처리를 해주는 코드인 OnTriggerEnter()의 일부입니다. 기존의 Destroy()를 사용해서 아예 삭제했던 것을 SetActive를 사용해서 오브젝트를 비활성화 하도록 바꿔주고, GetComponent를 추가해 연결시켜주는 코드를 추가해줍니다.

 

이제는 당연한 것이지만, 프리팹을 사용하려면 프리팹 오브젝트를 연결해줘야 합니다. 이제부턴 프리팹에 관한 설명은 생략하겠습니다. 모든 준비가 되었다면 게임을 실행시켜서 잘 작동하는지 확인해보겠습니다.

 

아이템-리스폰
아이템이 계속 리스폰되는 모습

원래대로라면, 100점까지만 먹을 수 있도록 10개의 아이템을 생성했었지만, 계속 먹어도 랜덤한 위치에 다시 생겨나기 때문에 280점을 달성했습니다. 그리고 아이템의 갯수는 여전히 10개입니다. 잘 작동하고 있습니다.

 

<NEXT>

이번에는 아이템의 랜덤위치 리스폰에 대해 알아보았습니다. 그런데 저희가 게이지 시스템을 아이템 10개에 맞춰 만들었었는데, 이제는 쓸모가 없어져 버렸습니다. 그래서 다음에는 게이지를 사용해 일정 개수마다 스테이지를 넘어갈 수 있도록 만들어 보겠습니다. 감사합니다.