2023. 11. 22. 13:23ㆍIT/TIL
오늘의 TIL은 약 1주간 진행했던 팀 프로젝트에서 구현한 내용들의 소개이다.
내가 진행한 작업은 Status Scene을 꾸미는 작업으로,
기본적으로 Base Scene과 SceneManger 등의 기초 뼈대는 이미 있는 공간에 작업을 시작한 것으로
중점적으로 했던 작업은
1. 다른 Scene 들과의 잘 이어지는 연결(통일성 유지)
2. Status Scene을 통해 자신의 현재 상태를 잘 알 수 있게 표현
3. 기본 UI에서 Status의 중요한 부분 표시하기
의 세 가지를 중점으로 생각하며 진행했다.
1. 다른 Scene 들과의 잘 이어지는 연결(통일성 유지)
전체적인 게임의 Scene 연결도를 그려보면 아래와 같은데
Status Scene은 게임의 기본 Scene인 Town Scene과 연결되어 있으며,
Inventory Scene과도 연결되어 있기 때문에
이 두 Scene과의 이동 시에 부자연스러운 부분이 없게 전체적인 통일성을 유지해야되는데,
기본적으로 사용하는 UI를 통일시켜 통일성을 유지했다.
또, 화면 외부의 Border를 작성하는 과정에서 작업자들 간의 차이가 있어서 이를 통일시켜주는 작업을 했다.
아래는 해당 Scene들의 사진이다.
2. Status Scene을 통해 자신의 현재 상태를 잘 알 수 있게 표현
이 부분은 내가 작업했던 Status Scene에 대한 전반적인 소개인데, Status Scene을 소개하면
기본적인 화면은 아래와 같다.
원래는 좌측에 있는 푸른 테두리의 글씨만 가운데에 적용했던 아래의 디자인이었으나,
시각적으로 직관성이 떨어지고 허전한 느낌이 있어서
위의 사진처럼 글씨로 알 수 있는 데이터는 좌측으로 옮기고
우측에 캐릭터 아바타를 만든 후에 장착하는 장비에 따라서 장비를 추가로 그려주는 디자인을 만들었다.
위의 사진은 무기와 방어구, 장신구를 착용한 상태의 사진으로
좌측의 데이터에서 공격력과 방어력, 체력이 아이템에 의해 상승되었는데,
공격력과 방어력의 경우 최종 공격력과 방어력을 적어준 뒤에, 아이템으로 인해 상승한 수치를 뒤에 +로 표기해줬다.
체력의 경우 아이템에 의해 상승한 최종 체력만을 표시했다.
우측의 아바타에서도 무기를 착용하면 빨간색의 무기 이미지가 추가되게,
방어구를 착용하면 파란색의 방어구 이미지가 추가되게,
장신구를 착용하면 노란색의 장신구 이미지가 추가되게 설정했다.
또, 추가로 구현했던 기능은 좌측의 데이터에서 해당하는 키워드를 선택하는 경우,
키워드에 대한 추가적인 내용을 적을 수 있게 구현했다.
처음의 디자인에서 기본적인 RPG에서 사용하는 레벨, 공격력, 방어력, 체력, 마나라는 키워드 대신
다른 타입의 키워드를 사용하는 것으로 진행할 수도 있기에 추가했던 기능이다.
(게임 디자인이 전통 RPG가 아니라 현실과 비슷한 배경을 디자인하였기에
레벨 -> 연차, 공격력 -> 협상력 혹은 화술, 방어력 -> 상대방의 화술에 대항할 수 있는 능력
체력 -> 멘탈, 마나 -> 기력 등의 키워드를 사용한다면 해당하는 키워드를 설명하고자 하였기 때문이다)
위의 사진처럼 키워드를 선택하는 경우, 키워드에 대한 설명과 힌트를 추가하는 방식으로 구현했다.
또, switch 문을 사용하여 해당하는 Border와 Text를 출력하게 구현했기에 아래처럼 이미지를 추가로 출력할 수도 있다.
이런 식으로 이스터에그를 만들었는데,
게임을 제작하는 과정에서 이스터에그를 왜 만드는지 이해할 수 있었고,
게임을 만드는 과정이 더 재미있게 진행되었으며, 이를 플레이어들이 찾아주기를 바라는 마음도 생기는 작업이었다.
아래는 작업하는데 사용했던 코드들 중에 중요하다고 생각하는 내용이다.
내가 작업하는데 사용한 코드들은 최대한 기본적인 코드들을 사용했다.
우선은 다른 class에서 데이터를 가져오는 코드로
internal class StatusScene : BaseScene
{
private BaseItem statusWeapon;
private BaseItem statusArmor;
private BaseItem statusAccessory;
public override void EnterScene()
{
for (int i = 0; i < Inventory.GetListCount(ItemType.Weapon); i++)
statusWeapon = Inventory.GetItem(i, ItemType.Weapon);
for (int i = 0; i < Inventory.GetListCount(ItemType.Armor); i++)
statusArmor = Inventory.GetItem(i, ItemType.Armor);
for (int i = 0; i < Inventory.GetListCount(ItemType.Accessory); i++)
statusAccessory = Inventory.GetItem(i, ItemType.Accessory);
StatusMain();
}
}
라고 표현할 수 있는데,
내가 작업했던 StatusScene에서 다른 Script에 있는 Item의 데이터를 가져오는 과정으로
우선 내가 작업하는 Script의 최상위에서
private BaseItem statusWeapon;
이라고 BaseItem class를 선언한 뒤에
Item의 데이터를 가져오려는 함수(EnterScene은 Main에 해당)에서
Inventory.GetListCount(ItemType.Weapon) 과
Inventory.GetItem(i, ItemType.Weapon)
을 통해서 아이템의 사이즈와 이름을 가져오는 코드를 사용했다.
사용했던 코드 중에 두 번째로 소개하고 싶은 내용은
글씨에 색을 입히는 코드로
public static void LeftHiText(ConsoleColor col, string text1, string text2 = "")
{
Console.ForegroundColor = col;
Console.Write(text1);
Console.ResetColor();
Console.WriteLine(text2);
}
위와 같이 만든 코드인데,
LeftHiText 라는 함수는 LeftHilightedText의 줄임말로,
텍스트를 2개 사용하는 경우 왼쪽에 있는 텍스트에 색을 넣는다는 의미이다.
따라서 LeftHiText에는 색상, text1, text2가 들어가는데,
text2의 경우에는 빈칸으로 사용할 수 있게 만들었다.
세 번째는 아이템을 착용하는지 판단하는 내용으로
위에서 가져온 item 의 데이터 중에서 Armor를 예로 들면 아래와 같은 코드를 작성할 수 있는데
for (int i = 0; i < Inventory.GetListCount(ItemType.Armor); i++)
{
statusArmor = Inventory.GetItem(i, ItemType.Armor);
if (statusArmor != null && statusArmor.ItemType == ItemType.Armor)
{
if (statusArmor.IsEquip == true)
{
StatusArmorImage();
}
}
}
for 문에서 statusAmror는 Inventory 에서 데이터를 가져온 뒤에
if 문에서 그 데이터가 null 값이 아니고 타입이 Armor인 경우에 착용하고 있는지 파악하도록 작성했다.
만약 착용하고 있는 경우(if (statusArmor.IsEquip == true))라면 이미지를 출력하도록 했다.
마지막은 글씨를 가운데 정렬하는 기능으로
우선은 그림으로 표현하면 아래와 같은데,
시작 지점이 (90, 0)이고 끝 지점이 (121, 0)인 공간에 가운데 정렬을 하고 싶은 경우,
위의 그림처럼 수학적으로 계산하여 가운데 정렬 시의 시작 x 좌표를 구할 수 있는데
이를 코드로 작성하면 아래와 같다.
int startXpos = 90;
int endXpos = 121;
string str1 = "text1";
string str2 = "안녕하세요";
int str1Len = (endXpos - startXpos - KoreanStrLength(str1)) / 2;
int str2Len = (endXpos - startXpos - KoreanStrLength(str2)) / 2;
Console.SetCursorPosition(startXpos + str1Len, 1);
Console.WriteLine(str1);
Console.SetCursorPosition(startXpos + str2Len, 2);
Console.WriteLine(str2);
static int KoreanStrLength(string str)
{
int length = 0;
foreach (char c in str)
{
length += IsKorean(c) ? 2 : 1;
}
return length;
}
static bool IsKorean(char c)
{
return (c >= '가' && c <= '힣') || (c >= 'ㄱ' && c <= 'ㅣ') || (c >= 'ㅏ' && c <= 'ㅣ');
}
시작 X 좌표는 startXpos로, 끝 X 좌표는 endXpos로, 출력할 Text는 str1 으로 선언하면
위의 그림에 따라
2a + str1.Length = endXpos - startXpos 이된다.
따라서 a = (endXpos - startXpos - str1.Length) / 2 가 된다.
여기서 a는 str1Len 이 되는데,
str2 의 경우 한국어이므로, 한국어인지 확인하여 text의 길이를 측정하는 과정이 필요하다.
따라서 해당하는 Text가 한국어인지 확인한 뒤에 (IsKorean), 길이를 측정하여(KoreanStrLength)
str1.Length에 넣어주는 과정을 거치면
int str1Len = (endXpos - startXpos - KoreanStrLength(str1)) / 2;
로 작성할 수 있다.
이후 Console.SetCursorPosition(startXpos + str1Len, 1);
를 통해서 X 좌표의 값을 조정해주면 가운데 정렬을 할 수 있다.
3. 기본 UI에서 Status의 중요한 부분 표시하기
마지막으로 진행했던 작업은 기본 UI에 Status 데이터들을 표시하는 작업이었는데
메인 화면이라고 할 수 있는 Town에서 표시되는 UI를 Battle Scene에서도 사용하는데,
좌측 아래의 체력과 마나는 다른 팀원분께서 작업하신 내용이 있었기에 그대로 진행했으며,
가운데 아래 부분은 Battle Scene에서는 선택지가 있는 부분이기에 빈칸으로 두었다.
그 이후에 남은 우측 아래 부분을 Status 데이터로 채우는 작업을 진행했는데,
주어진 칸의 너비는 28칸, 높이는 8칸으로 이곳에 어떤 데이터를 채워야 좋을지 고민했는데,
좌측에 체력과 마나는 있기 때문에 남는 플레이어의 데이터는 레벨, 이름, 공격력, 방어력, 소지금으로
플레이어의 이름은 자신의 이름이기에 딱히 계속적으로 표현할 필요가 없다고 생각했다.
이후에 나머지 데이터 중에서 어떤 데이터를 UI에서 표시하면 좋을지 고민했는데,
이 UI는 Battle Scene에서도 표시되기에 Battle Scene에서 부족한 요소를 보면서 판단했다.
위의 사진은 Battle Scene으로 좌측에는 플레이어의 캐릭터가, 우측에는 몬스터와 몬스터의 데이터가 표시된다.
해당 화면에서 플레이어의 상태를 표현해주는 요소가 없기에 아래쪽의 UI로 표시해주는데,
몬스터의 데이터는 이름, 레벨, 공격력, 체력으로 표시되기에 이에 해당하는 데이터들이 UI에 있어야 된다고 생각했다.
따라서 우측 하단에는 레벨, 공격력, 방어력, 소지금을 표시해주기로 결정했는데,
몬스터들과의 전투가 끝난 후에 레벨이 오르는 요소와 골드를 획득하는 요소가 있기 때문에
지금 플레이어가 얼마나 전투를 했는지를 파악할 수 있게 해주는 요소로 두 데이터를 넣었으며,
몬스터들과의 전투에서 내 공격력이 얼마나 되는지 알아야 몬스터를 공략하는 순서를 정할 수 있기에 공격력을,
몬스터의 공격력과 나의 방어력을 비교하여 어느 몬스터가 더 위협적인지 판단할 수 있기에 방어력을
UI에 추가하기로 했다.
약 일주일간 진행했던 팀 프로젝트를 통해 게임을 만드는 전반적인 과정을 경험했다.
게임의 주제가 주어졌을 때, 이 주제를 가지고 어떻게 게임을 디자인할 것인지
전반적인 게임의 스토리, 컨셉, 화면 크기, 화면을 구상하는 요소 등의 기본 작업을 회의를 통해 도출했으며,
매일의 스크럼을 통해 해당 아이디어들을 어떻게 게임에 녹여낼 것인지, 추가 혹은 제거할 요소가 있는지 대화했다.
이후 집중적으로 구현하는 과정에서는 자신에게 부족한 코딩 능력을 팀원들 혹은 튜터님께 질문하면서
C#의 기본적인 문법에서 이해하지 못했던 것을 좀 더 이해할 수 있었고,
다른 팀원들이 코딩한 내용을 보면서 이 코드는 이런식으로 작성하면 되겠구나,
내가 작성했던 코드와는 이런 점이 다르구나 하는 등의 데이터를 얻을 수 있었다.
특히 여기서 좋았던 점은 실용화된 코드와 프로그램이 아닌,
팀원들과 시행착오를 겪어가며 만드는 코드라 좀 더 Raw한 코드들을 볼 수 있었던 점이 좋았다.
이후에 어느정도 구현이 끝난 Scene들을 통합하는 과정에서 생기는 오류들을 해결하면서
소위 말하는 조립하는 과정을 진행했는데, 이 과정도 나름의 재미가 있었다.
단순히 코드들을 이어붙이는 것이 아니라, Script가 나눠져있기에 Scene Manager를 통해
A Scene이 끝난 뒤에 B Scene이 나오게 한다거나
A Scene에서 선택을 통해 B Scene이나 C Scene으로 진행할 수 있게 선택지를 준다거나
하는 등의 조립 과정은 혼자서 작업하는 경우에는 하기 어려운 경험이었다.
조립이 끝난 후에는 프로토 타입이라고 할 수 있는 게임이 완성되었는데,
이 타입에서 각 Scene 들의 디자인 통일성을 만들어주고,
각 작업자가 사용했던 단어들을 통일해주는 등의 게임의 완성도를 높이는 과정을 거쳤는데,
그 중에서도 가장 많이 수행한 작업은 오류 해결로
게임을 플레이하는 과정에서 작업자가 생각했었던 방식이 아닌
다른 방식으로 게임을 플레이하면(코드를 실행하면) 발생할 수 있는 오류들이 매우 많은 것을 느꼈다.
나의 경우에는 플레이어가 착용하는 아이템을 맨 위로 혹은 맨 아래로 두는 과정을 거쳤기에
착용중인 아이템의 데이터는 맨 아래의 아이템을 가지고 판단하도록 작업했었는데,
다른 팀원이 작성한 데이터는 중간에 있는 아이템을 착용하는 경우에 위치를 변경하지 않았기에
착용중인 아이템은 전체 아이템을 대상으로 판단하도록 수정하는 등의 작업을 하도록 변경했다.
이 뿐만 아니라 게임을 많이 플레이하면서 발견한 오류들을 수정하는 작업을 거쳤으며,
RPG 게임이기 때문에 밸런스를 맞춰 몬스터를 잡으면 획득하는 경험치와 골드를 조정하고
레벨과 아이템의 공격력, 방어력과 몬스터의 공격력, 방어력, 체력 등을 조정하고
최종적으로 플레이어가 어느 정도 수준이 되면 (레벨과 아이템이 어느 정도 갖춰지면)
보스를 잡고 엔딩을 볼 수 있게 조정하는 법을 배웠다.
짧다면 짧고 길다면 길다고 할 수 있는 일주일의 게임 만들기 작업이었는데,
개인적으로는 매우 만족스러운 결과물과 개발의 진행 과정을 경험했다고 느꼈다.
'IT > TIL' 카테고리의 다른 글
20231124_카드뭉치(프로그래머스) (1) | 2023.11.24 |
---|---|
20231123_2016년(프로그래머스) (1) | 2023.11.24 |
20231121_기록_유니티에서의 Static (1) | 2023.11.21 |
20231120_기록_C# Console에서의 글 정렬 (1) | 2023.11.20 |
20231117_기록_팀 프로젝트 (0) | 2023.11.17 |