[Unity]레벨 디자인, Pixels Per Unit, Invoke, 이미지 동적 할당, Instatiate

ggm-_-·2024년 9월 11일
0

TIL (Tody I Learn)

목록 보기
2/27
post-custom-banner

TIL 24.09.10(화)

TIL

1. 레벨 디자인

❓ 레벨 디자인이란?

❓ 레벨디자인이란 무엇일까요?

보통 레벨하면 RPG게임 캐릭터의 그것을 떠올리지만, 레벨은 단계라는 의미로서 맵이나 스테이지를 나타내기도 합니다. 레벨 디자인이란 게임의 스테이지와 같은 맵의 구성요소와 게임의 진행방식에 대해 디자인하는 것입니다.

  • 레벨 디자인은 게임 기획과 아트 디자인의 성격을 모두 가지고 있습니다. 게임의 구성요소, 즉 맵에서 구조물들과 아이템, 장애물 등을 어떻게 구성할지 디자인해야 되고 게임진행방식과 난이도 등을 기획해야 됩니다.
  • 레벨 디자이너는 레벨 디자인을 통해 유저들에게 지속적으로 선택지와 여러가지 게임 패턴을 제공하여 실력에 맞는 적절한 난이도를 제공함으로서 유저들의 몰입감을 향상시켜주는 아주 중요한 역할을 맡고 있습니다.

*문체 바뀝니다. 주의*


2. 이미지가 들어간 Sprite의 크기 조정

☝ Pixels Per Unit

❓ Pixels Per Unit이란 무엇인가?
Scene공간에 있는 네모칸 하나를 Unit 이라고 하는데, Pixels Per Unit은 '이 Unit(네모칸) 하나를 몇 픽셀로 할 것인가?' 를 나타내는 숫자다.

이미지의 Inspector창을 보면 Texture TypeSprite일 때, Pixels Per Unit 이라는 기능이 있다.

이미지는 결국엔 n x n 픽셀로 이루어져 있는데 이것을 Unity 공간에서 표현할 때 해당 이미지가 Unit 하나를 몇 픽셀로 간주할 것이냐를 표현해주는 것이 Pixels Per Unit이라고 생각하면 된다.

📘 예시를 들어보자.
100 x 100 의 책 이미지를 Pixels Per Unit을 100으로 설정했다면 책은 Unit 하나에 딱 들어맞는 크기가 될 것이다. 반면에, Pixels Per Unit을 50으로 설정한다면 책은 Unit이 가로로 2개 세로로 2개 해서 Unit이 2 x 2 개 있는 만큼의 크기를 가지게 될 것이다.


3. 배열 내부 원소들을 랜덤으로 섞기

👉 arr.OrderBy(x => Random.Range(0f, 1f)).ToArray();

❓ OrderBy를 먼저 알아보자

일단 위의 구문을 보기 전에 arr.OrderBy(x => x)에 대해 설명하자면, 배열 arr의 각 요소 x를 x를 기준으로 오름차순으로 정렬하는 것이다.
만약, arr가 다음과 같다면,

int[] arr = { 4, 2, 3, 1, 5};

arr.OrderBy(x => x)에 의해 정렬된 값은 1, 2, 3, 4, 5의 순서대로 존재하게 되는 것이다.

이 때, OrderBy의 결과값의 Type은 배열이 아니므로 정렬된 결과를 ToArray를 사용하여 배열로 받을 수 있다.

arr = arr.OrderBy(x => x).ToArray(); //결과 arr = {1, 2, 3, 4, 5};
  • 참고) OrderBy는 다음과 같은 using문이 필요하다.
using System.Linq;

❗ 랜덤을 적용한 OrderBy

그렇다면 이제 랜덤으로 배열을 정렬해보자.
arr.OrdryBy(x => x)가 각 요소 x를 기준으로 배열을 정렬했다면, arr.OrderBy(x => Random(0f, 1f))Random(0f, 1f)를 기준으로 배열을 정렬한다.
Random(0f, 1f)를 이용해 각 요소와 매칭할 때마다 랜덤으로 0~1사이의 숫자가 나오며 이것의 순서대로 오름차순으로 배열이 정렬된다. 이 때, 원래 배열의 요소값은 바뀌지 않는다. Random(0f, 1f)는 단지 정렬을 위한 기준이 될 뿐이다.

arr = arr.OrderBy(x => Random.Range(0f, 1f)).ToArray();//정렬된 arr이 랜덤으로 섞인다.

4. 함수를 n초 뒤에 실행해주세요 (feat. 메서드)

🔜 Invoke 사용하기

💡 Invoke 함수 사용법

Invoke("EndGame", 1f); // 인자는 각각(함수명, 대기시간) 이다

첫 번째 인자로 함수의 이름을 string으로 받고, 두 번째 인자로 함수 실행을 몇 초 후에 실행할 건지 대기시간 float으로 받는다.

그런데 여기서 함수명에는 오로지 함수의 이름만 들어갈 수 있다. 메서드를 사용하는 함수지연을 하기 위해서는 Coroutine을 사용해야 하지만 Invoke만을 이용해 함수를 지연실행해보도록 하겠다.

✌ 함수를 2개로 쪼개기

다음과 같이 함수를 두개로 쪼개서 Invoke를 사용하여 매개변수가 있는 함수를 호출할 수 있다.

  • GameManager.cs
// endPanel이라는 Object를 GameObject로 받았다고 한다.
//(EndPanel은 그냥 예시 GameObject이다)
public GameObject endPanel;

void Start()
{
	//Invoke("endPanel.PrintEnd()", 1f); //(x)
    endPanel.PrintEndInvoke(); //(o)
}
  • EndPanel.cs
//GameObject EndPanel에 할당된 Script 
public void PrintEnd()
{
	Debug.Log("The End.");
}
public void PrintEndInvoke()
{
	Invoke("PrintEnd", 1f);
}

5. Script를 이용해서 자동으로 여러 이미지(Sprite)를 인스턴스에 할당하기

🚗 Resources.Load 사용하기

Resources.Load<Sprite>($"image{idx}");

게임을 만들다 보면 많은 이미지를 Script를 이용해 object에 넣어야 할 필요가 있을 수 있다. 이 때, 사용할 수 있는 방법에 대해 알아보자. Resources폴더에 있는 것들은 모두 미리 메모리에 올라가기 때문에 최대한 줄이는 게 좋다고 한다. 하지만, 동적으로 이미지를 Object에 할당할 때 사용할 수 있다.

✅ 준비물

  • Assets폴더에 Resources폴더를 만들어서 안에 이름이 image0~9인 Sprite를 준비.
  • ImageObject.cs를 가지고 있는 Square 오브젝트(object이름: ImageObject)를 Prefeb으로 생성.
  • image0~9를 자동으로 ImageObject에 넣어줄 GameManager생성.
  • ImageObject.cs
public SpriteRenderer imageObject;
public void Setting(int number)
{
    idx = number;
    imageObject.sprite = Resources.Load<Sprite>($"image{idx}");
}
  • GameManager.cs
public GameObject imageObjectPrefab;//인스턴스화할 ImageObject의 프리펩 받기
GameObject imageObject;
for (int i = 0; i < 10; i++)
{
	imageObject = Instatiate(imageObjectPrefab);
	imageObject.GetComponent<ImageObject>().Setting(i);
}

다음과 같은 코드를 이용해 ImageObject의 인스턴스를 10번 생성하는데 각각 image0~9까지의 이미지를 삽입하게 했다. 이로서 10개의 Prefab을 만들지 않고 10개의 이미지가 들어간 Object를 만드는 방법을 알 수 있다.

➕고찰➕

이 코드를 이용하면 여러 이미지를 자동으로 Object에 넣어서 생성할 수 있게 되어 좋지만, 모두 ImageObject라는 class Type(ImageObject.cs Script를 이용해 만들었다는 뜻이다)을 가지게 된다. 만약 어떤 이미지는 다른 Type의 오브젝트가 되고 싶다면, if문을 통해 i값에 따라 Type이 들어가는 <>안을 바꿔주면 될 것이다.


6. 인스턴스를 다른 Ojbect에 속한 상태로 생성하기

🎁 Instatiate(instanceObject, otherObject.transform) 사용하기

위의 GameManager.cs에 imageObject가 속하게 될 ImageFrame오브젝트가 들어갈 GameObject변수 imageFrame을 선언해주고, Instantiate구문을 다음과 같이 바꿔준다.

//GameManager.cs
public GameObject imageFrame;
for(...) {
	imageObject = Instantiate(imageObjectPrefab, imageFrame.transform);
    ...
}

이렇게 하면 ImageObject의 인스턴스를 생성할 때 ImageFrame의 산하에 생성되게 된다.

profile
미숙한 초보 게임 개발자
post-custom-banner

0개의 댓글