Writing the Board Manager
이번 시간에는 플레이 시마다 다르게 각 레벨을 생성하는 board manager 스크립트를 작성할 것입니다.
Assets 폴더에 Scripts 폴더를 생성하고 그 안에 두 개의 빈 스크립트를 생성, 각각의 이름을 BoardManager, GameManager라고 정합니다.
그와 동시에 Hierarchy에 GameManger라는 빈 오브젝트를 하나 생성해 둡시다.
그리고, BoardManager 스크립트를 에디터로 열겠습니다.
보드매니저는 플레이어가 새로운 레벨을 시작할 때마다 현재의 레벨 넘버를 기반으로 레벨을 랜덤 생성할 것입니다.
네임스페이스 선언을 시작으로 스크립트를 작성합니다.
using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
| cs |
using System은 Serializable 어트리뷰트를 사용하여 인스펙터 상에 프로퍼티를 보여줄지 결정하기 위한 것이며, System.Collections.Generic은 리스트, Random은 유니티엔진의 랜덤 클래스를 Random이라는 이름으로 사용하기 위한 것입니다.
[Serializable]
public class Count
{
public int minimum;
public int maximum;
public Count(int min, int max)
{
minimum = min;
maximum = max;
}
}
| cs |
Count라는 최소, 최대값의 정수형 필드를 가지는 퍼블릭 클래스를 하나 작성하고 계속해서 퍼블릭 변수들을 선언합니다.
public int columns = 8; // 게임 보드의 행 수
public int rows = 8; // 게임보드의 열 수
public Count wallCount = new Count(5, 9); // 레벨 당 벽의 하한,상한값
public Count foodCount = new Count(1, 5); // 레벨 당 음식 하한,상한값
public GameObject exit; // exit 프리팹 레퍼런스
//각 타일들에 대한 레퍼런스
public GameObject[] floorTiles;
public GameObject[] wallTiles;
public GameObject[] foodTiles;
public GameObject[] enemyTiles;
public GameObject[] outerWallTiles;
| cs |
private 변수들로 이어집니다.
private Transform boardHolder; // 보드의 tranform 레퍼런스
// 타일이 놓일 수 있는 장소의 리스트
private List<Vector3> gridPositions = new List<Vector3>();
| cs |
다음으로 우리의 보드게임에 사용될 리스트를 초기화할 메소드를 하나 작성합니다.
void InitialiseList()
{
gridPositions.Clear();
for(int x = 1; x < columns - 1; x++)
{
for(int y = 1; y < rows - 2; y++)
{
gridPositions.Add(new Vector3(x, y, 0f));
}
}
}
| cs |
0과 가장 바깥 줄을 빼놓은 이유는 그곳에는 혹시나 우연히 벽으로 둘러싸여 깰수 없는 판이 생길 것을 방지하기 위해서 입니다.
그림과 같이 가장 바깥줄을 제외시킨 상태에서 리스트를 작성합니다.
다음으로 보드의 외벽과 바닥을 설정할 메소드를 작성합니다.
// outerWall과 floor 세팅
void BoardSetup()
{
// 새 Board 오브젝트를 인스턴스화하고 그 트랜스폼을 보드홀더에 저장
boardHolder = new GameObject("Board").transform;
for (int x = -1; x < columns + 1; x++)
{
for(int y = -1; y < rows + 1; y++)
{
// 바닥타일 8종 중 하나의 프리팹을 랜덤으로 고름
GameObject toInstantiate = floorTiles[Random.Range(0, foodTiles.Length)];
// 만약 위치가 테두리라면 외벽타일 중 골라 다시 저장
if (x == -1 || x == columns || y == -1 || y == rows)
{
toInstantiate = outerWallTiles[Random.Range(0, outerWallTiles.Length)];
}
// 고른 프리팹을 현재 순회중인 위치에 인스턴스화하여 저장
GameObject instance = Instantiate(
toInstantiate, new Vector3(x, y, 0f), Quaternion.identity) as GameObject;
// 생성된 인스턴스의 트랜스폼을 boardHolder의 자식으로 둠
instance.transform.SetParent(boardHolder);
}
}
}
| cs |
다음은 랜덤으로 배치할 적, 음식 등을 설정하는 메소드 차례입니다.
먼저 랜덤으로 위치를 고르는 메소드를 작성합니다.
// gridPosition에서 랜덤으로 하나 고를 수 있게 함
Vector3 RandomPosition()
{
// gridPositon으 길이 내에서 랜덤으로 인덱스 형성
int randomIndex = Random.Range(0,gridPositions.Count);
// 랜덤으로 형성한 인덱스에 해당하는 gridPositons를 저장하는 변수선언
Vector3 randomPosition = gridPositions[randomIndex];
// randomIndex에 해당하는 gridPositions값 삭제하여 사용가능하게 함
gridPositions.RemoveAt(randomIndex);
return randomPosition;
}
| cs |
다음으로, 주어진 범위 내에서 정해준 타일을 랜덤으로 생성해주는 메소드입니다.
// 주어진 상/하한 값 내에서 랜덤으로 지정한 타일을 생성해줌
void LayoutObjectAtRandom(GameObject[] tileArray,int minimum, int maximum)
{
// 랜덤으로 개수 선택
int objectCount = Random.Range(minimum, maximum + 1);
// 정한 개수만큼 오브젝트 생성
for (int i = 0; i < objectCount; i++)
{
Vector3 randomPosition = RandomPosition();
// 주어진 타일 종류 내에서 골라 저장
GameObject tileChoice = tileArray[Random.Range(0, tileArray.Length)];
// 고른 타일을 인스턴스화
Instantiate(tileChoice, randomPosition, Quaternion.identity);
}
}
| cs |
이제 실제적으로 게임매니저에서 호출하여 보드를 세팅할 수 있게 해주는 퍼블릭 메소드를 작성합니다.
public void SetupSecene(int level)
{
//외벽과 바닥 세팅
BoardSetup();
// 리스트 초기화
InitialiseList();
// 내벽 세팅
LayoutObjectAtRandom(wallTiles, wallCount.minimum, wallCount.maximum);
// 음식 세팅
LayoutObjectAtRandom(foodTiles, foodCount.minimum, foodCount.maximum);
// 적의 수는 레벨에 따라 로그함수적으로 결정
// 따라서 레벨 2에는 적 1, 4에는 적 2, 8에는 적 3
int enemyCount = (int)Mathf.Log(level, 2f);
LayoutObjectAtRandom(enemyTiles, enemyCount, enemyCount);
// 최종적으로 exit를 우상단에 생성
Instantiate(exit, new Vector3(columns - 1, rows - 1, 0f), Quaternion.identity);
}
| cs |
전체 BoardManager 스크립트는 아래와 소개하고 이 글을 마칩니다.
using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public class BoardManager : MonoBehaviour
{
[Serializable]
public class Count
{
public int minimum;
public int maximum;
public Count(int min, int max)
{
minimum = min;
maximum = max;
}
}
public int columns = 8; // 게임 보드의 행 수
public int rows = 8; // 게임보드의 열 수
public Count wallCount = new Count(5, 9); // 레벨 당 벽의 하한,상한값
public Count foodCount = new Count(1, 5); // 레벨 당 음식 하한,상한값
public GameObject exit; // exit 프리팹 레퍼런스
//각 타일들에 대한 레퍼런스
public GameObject[] floorTiles;
public GameObject[] wallTiles;
public GameObject[] foodTiles;
public GameObject[] enemyTiles;
public GameObject[] outerWallTiles;
private Transform boardHolder; // 보드의 tranform 레퍼런스
// 타일이 놓일 수 있는 장소의 리스트
private List<Vector3> gridPositions = new List<Vector3>();
// gridPositions 초기화
void InitialiseList()
{
gridPositions.Clear();
for(int x = 1; x < columns - 1; x++)
{
for(int y = 1; y < rows - 2; y++)
{
gridPositions.Add(new Vector3(x, y, 0f));
}
}
}
// outerWall과 floor 세팅
void BoardSetup()
{
// 새 Board 오브젝트를 인스턴스화하고 그 트랜스폼을 보드홀더에 저장
boardHolder = new GameObject("Board").transform;
for (int x = -1; x < columns + 1; x++)
{
for(int y = -1; y < rows + 1; y++)
{
// 바닥타일 8종 중 하나의 프리팹을 랜덤으로 고름
GameObject toInstantiate = floorTiles[Random.Range(0, foodTiles.Length)];
// 만약 위치가 테두리라면 외벽타일 중 골라 다시 저장
if (x == -1 || x == columns || y == -1 || y == rows)
{
toInstantiate = outerWallTiles[Random.Range(0, outerWallTiles.Length)];
}
// 고른 프리팹을 현재 순회중인 위치에 인스턴스화하여 저장
GameObject instance = Instantiate(
toInstantiate, new Vector3(x, y, 0f), Quaternion.identity) as GameObject;
// 생성된 인스턴스의 트랜스폼을 boardHolder의 자식으로 둠
instance.transform.SetParent(boardHolder);
}
}
}
// gridPosition에서 랜덤으로 하나 고를 수 있게 함
Vector3 RandomPosition()
{
// gridPositon으 길이 내에서 랜덤으로 인덱스 형성
int randomIndex = Random.Range(0,gridPositions.Count);
// 랜덤으로 형성한 인덱스에 해당하는 gridPositons를 저장하는 변수선언
Vector3 randomPosition = gridPositions[randomIndex];
// randomIndex에 해당하는 gridPositions값 삭제하여 사용가능하게 함
gridPositions.RemoveAt(randomIndex);
return randomPosition;
}
// 주어진 상/하한 값 내에서 랜덤으로 지정한 타일을 생성해줌
void LayoutObjectAtRandom(GameObject[] tileArray,int minimum, int maximum)
{
// 랜덤으로 개수 선택
int objectCount = Random.Range(minimum, maximum + 1);
// 정한 개수만큼 오브젝트 생성
for (int i = 0; i < objectCount; i++)
{
Vector3 randomPosition = RandomPosition();
// 주어진 타일 종류 내에서 골라 저장
GameObject tileChoice = tileArray[Random.Range(0, tileArray.Length)];
// 고른 타일을 인스턴스화
Instantiate(tileChoice, randomPosition, Quaternion.identity);
}
}
public void SetupSecene(int level)
{
//외벽과 바닥 세팅
BoardSetup();
// 리스트 초기화
InitialiseList();
// 내벽 세팅
LayoutObjectAtRandom(wallTiles, wallCount.minimum, wallCount.maximum);
// 음식 세팅
LayoutObjectAtRandom(foodTiles, foodCount.minimum, foodCount.maximum);
// 적의 수는 레벨에 따라 로그함수적으로 결정
// 따라서 레벨 2에는 적 1, 4에는 적 2, 8에는 적 3
int enemyCount = (int)Mathf.Log(level, 2f);
LayoutObjectAtRandom(enemyTiles, enemyCount, enemyCount);
// 최종적으로 exit를 우상단에 생성
Instantiate(exit, new Vector3(columns - 1, rows - 1, 0f), Quaternion.identity);
}
}
| cs |
댓글 없음:
댓글 쓰기