TIL 24.09.10(화)
❓ 레벨디자인이란 무엇일까요?
보통 레벨하면 RPG게임 캐릭터의 그것을 떠올리지만, 레벨은 단계라는 의미로서 맵이나 스테이지를 나타내기도 합니다. 레벨 디자인이란 게임의 스테이지와 같은 맵의 구성요소와 게임의 진행방식에 대해 디자인하는 것입니다.
*문체 바뀝니다. 주의*
❓ Pixels Per Unit이란 무엇인가?
Scene공간에 있는 네모칸 하나를 Unit 이라고 하는데, Pixels Per Unit은 '이 Unit(네모칸) 하나를 몇 픽셀로 할 것인가?' 를 나타내는 숫자다.
이미지의 Inspector
창을 보면 Texture Type
이 Sprite
일 때, 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 개 있는 만큼의 크기를 가지게 될 것이다.
일단 위의 구문을 보기 전에 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;
그렇다면 이제 랜덤으로 배열을 정렬해보자.
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이 랜덤으로 섞인다.
Invoke("EndGame", 1f); // 인자는 각각(함수명, 대기시간) 이다
첫 번째 인자로 함수의 이름을 string
으로 받고, 두 번째 인자로 함수 실행을 몇 초 후에 실행할 건지 대기시간 float
으로 받는다.
그런데 여기서 함수명에는 오로지 함수의 이름만 들어갈 수 있다. 메서드를 사용하는 함수지연을 하기 위해서는 Coroutine
을 사용해야 하지만 Invoke
만을 이용해 함수를 지연실행해보도록 하겠다.
다음과 같이 함수를 두개로 쪼개서 Invoke
를 사용하여 매개변수가 있는 함수를 호출할 수 있다.
// endPanel이라는 Object를 GameObject로 받았다고 한다.
//(EndPanel은 그냥 예시 GameObject이다)
public GameObject endPanel;
void Start()
{
//Invoke("endPanel.PrintEnd()", 1f); //(x)
endPanel.PrintEndInvoke(); //(o)
}
//GameObject EndPanel에 할당된 Script
public void PrintEnd()
{
Debug.Log("The End.");
}
public void PrintEndInvoke()
{
Invoke("PrintEnd", 1f);
}
Resources.Load<Sprite>($"image{idx}");
게임을 만들다 보면 많은 이미지를 Script를 이용해 object에 넣어야 할 필요가 있을 수 있다. 이 때, 사용할 수 있는 방법에 대해 알아보자. Resources폴더에 있는 것들은 모두 미리 메모리에 올라가기 때문에 최대한 줄이는 게 좋다고 한다. 하지만, 동적으로 이미지를 Object에 할당할 때 사용할 수 있다.
Assets
폴더에 Resources
폴더를 만들어서 안에 이름이 image0~9인 Sprite
를 준비.ImageObject.cs
를 가지고 있는 Square 오브젝트(object이름: ImageObject)를 Prefeb으로 생성.GameManager
생성.public SpriteRenderer imageObject;
public void Setting(int number)
{
idx = number;
imageObject.sprite = Resources.Load<Sprite>($"image{idx}");
}
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이 들어가는 <>안을 바꿔주면 될 것이다.
위의 GameManager.cs
에 imageObject가 속하게 될 ImageFrame오브젝트가 들어갈 GameObject
변수 imageFrame을 선언해주고, Instantiate
구문을 다음과 같이 바꿔준다.
//GameManager.cs
public GameObject imageFrame;
for(...) {
imageObject = Instantiate(imageObjectPrefab, imageFrame.transform);
...
}
이렇게 하면 ImageObject의 인스턴스를 생성할 때 ImageFrame의 산하에 생성되게 된다.