개인과제 제출일이다.
노동요와 함께 힘차게 달려보자.
https://www.youtube.com/watch?v=A0dDIt9aAKI
오늘의 작업일지
인벤토리에서 아이템이 나오게 구현해보자.
기존에는 Console.WriteLine로 일일히 작성하여 나오게끔 했지만,그건 그저 보여주기식일뿐, 아이템을 장착/해제 하기 위해서는 실제 아이템을 구현하는게 필요하다.
그래서 어제 만들어둔 ItemData 클래스를 기반으로 itemsInDatabase라는 아이템리스트를 새로 만들었다.
그리고 거기에 아이템들을 추가했는데 상점에만 표시할 아이템과 소유중 아이템 리스트를 따로 분간할 필요 없이 ItemData에 bool값을 지정해주어 이 아이템을 플레이어가 소유했는지 안했는지를 참거짓으로 판별하게 해준 뒤 아이템리스트에 몽땅 때려 넣었다.
IsItemEquipped는 이 아이템을 장착했는지 안했는지를 참거짓으로 판별하는 bool로 기본적으로 아무 아이템도 장착하지 않은 채로 게임에 시작하기 때문에 false로 지정해줬다.
그 뒤 리스트의 Count만큼 반복하여 출력하게끔 for 반복문을 작성하였다. 리스트의 index는 0부터 시작하기에 아이템번호는 1부터 시작하도록 i+1 을 해주었고, ItemData item = itemsInDatabase[i]로 리스트 내의 아이템들을 호출하여 item.itemName 등을 불러와주었다. 그리고 가지고 있지 않은 아이템, 즉 bool IsPlayerOwned가 false인 경우에는 continue;로 표시되지 않게 넘겨주었다.
또한 아이템을 장착했을때 앞에 [E]를 띄워주는 것이 어찌보면 이번 과제의 핵심이므로, string ItemEquipped; 를 작성해 변수를 만들어주고, 이는 item.IsItemEquipped 가 참인지 거짓인지에 따라 나오거나 안나오게 해줘야 한다.
그래서 삼항연산자를 사용해 참일경우 "[E] ", 거짓일경우 ""가 출력되게 했다.
isItemEquipped의 디폴트값은 false이므로, 현재는 실행하면 "[E] " 가 출력되지 않아야 정상이고, 정상적으로 작동함을 확인했다.
한가지 문제가 있다면 ItemData와 itemsInDatabase의 아이템 정보에는 공격력과 방어력을 둘 다 가지고 있지만, 공격력과 방어력 둘 중에 하나만 표기되게끔 해야한다는 것이다. 그래서 공격을 보여줄지 방어를 보여줄지 조건을 달아주는 메서드를 작성했다.
다음은 장착 관리 메서드다.
전체적인 틀은 인벤토리의 것을 가져와서 복붙한다음 내용만 조금 다듬어주면 된다.
중요한 것은 장착하지 않은 아이템 번호를 선택했을때 아이템을 장착하고, 장착한 아이템 번호를 선택했을때 장착해제를 하는 것이다.
일단 0을 선택하면 다시 인벤토리로 이동을 하게끔 하고, 아이템 번호에 해당하는 아이템을 장착한 뒤 다시 장착관리창으로 돌아와 장착관리를 할 수 있게끔 해줬다.
여기서 입력한 아이템 번호, 즉 input은 index보다 +1인 상태이므로 itemsInDatabese[input -1]을 해준뒤 이를 ItemData selectedItem이라는 변수로 지정해준다. 즉 플레이어가 입력한 아이템 번호에 해당하는 아이템 리스트의 인덱스에 맞춰서 selectedItem으로 지정한 것.
그리고 ItemEquip이라는 메서드를 만들어 ItemData의 item을 매개변수로 쥐어주고, 아이템 장착/해제를 적용할 수 있도록 item.IsItemEquipped = !item.IsItemEquppied 하여 해당 bool을 on/off 하게 해준다.
생각해보니 장착한 아이템들을 관리해줄 리스트도 필요하다. 그래서 playerEquippedItems라는 리스트도 새로 만들어줬다. 그리고 item.IsItemEquipped라면 playerEquippedItems 리스트에 Add(item)을, 아니라면 Remove(item)을 해주어 장착아이템을 playerEquippedItems 리스트를 통해 관리하게끔 했다.
그 뒤에 확인을 해보니 장착한 아이템 능력치가 플레이어의 능력치에는 반영되지 않았다.
단순히 아이템을 장착 리스트에 담아둔다고 될게 아니라 아이템의 능력치를 플레이어의 능력치에 더해줘야했다.
그래서 UpdatePlayerStats라는 메서드를 만들었다.
totalAtk와 totalDef라는 변수를 만들어 초기값을 0으로 설정한 뒤,
foreach 문을 통해 리스트 playerEquippedItems 내부의 아이템들의 공격력과 방어력을 totalAtk, totalDef에 더해준다.
그리고 playerStat의 AtkValue와 DefValue에 더해주면 되는데, 기본 공격력, 방어력과 totalAtk, totalDef를 더해주면 플레이어의 스텟에 아이템의 수치가 더해져 능력치에 반영이 될것이다.
정상적으로 반영되기는 했으나 공격력 방어력에는 합산만 나오고 얼마만큼의 능력치가 아이템으로 인해 더해졌는지는 나오지 않는다.
이거는 Status 부분을 고쳐줘야하는데..
대충 이런 상태로 8분정도 있다가 퍼뜩 방금전에 썼던 BaseAtkValue와 BaseDefValue 가 생각이 났다.
그리고 C# 문법 강의를 통해 이미 조건이 해당하지 않는다면 출력되지 않게끔 해주는 조건문이란 것도 배웠다.
그렇다면 플레이어의 현재 공격력에서 기본 공격력을 뺀 값이 0보다 크다면 그것을 Console.Write로 출력해주는 조건문을 짜면 되지 않을까?
위 의식의 흐름을 바로 코드에 우겨넣었다.
WriteLine을 쓰면 그 밑의 줄에 해당 내용을 표기할테니 Console.Write를 쓰고, 이스케이프 시퀀스 중 줄바꿈을 해주는 \n을 활용하여 방어력을 다음줄로 넘겨줬다.
자 과연 제대로 보여줄지?
일단 가장 큰 벽이라고도 볼 수 있었던 아이템 장착/해제 부분은 무사히 마무리 지었다.
자 다음은 상점 파트다.
상점 역시 기본적인 인터페이스는 인벤토리와 비슷하다고 볼 수 있는데, 차이점은 플레이어가 소지한 골드를 보여준다는 것과 아이템 설명 이후의 가격란이 있다는 것, 그리고 이미 소지하고 있는 아이템에는 구매완료를 띄워야한다는 것이다.
ItemData와 리스트를 만들땐 할당했지만 인벤토리를 만들때는 쓰지 않았던 itemPrice를 쓸 차례가 왔다.
몇번 하니까 금방 감을 잡고 작성해냈다.
인벤토리에서 썼던 item.IsPlayerOwned를 활용함에 있어서, 인벤토리에서는 IsPlayerOwned가 false라면 continue로 그 아이템을 나타내지않고 패스했다면, 이번에는 아이템의 가격이 나오게끔 해줬다.
그리고 구매완료된 아이템에 대해서는 한눈에 알 수 있도록 색깔도 입혀줬다. (색 입히는 법은 구글링해서 찾아냈다.)
자 이렇게 실행을 해보면?
정상적으로 작동하는... 어...
스파르타의 갑옷이 방어력이 너무 높아 혼자 두자릿수라 한칸 삐져나온 모습이다.
이건 도저히 참을수가 없다.
바로 수정작업 들어간다.
기존에 item.ItemAtk과 item.ItemDef가 0 이상이면 출력되던거에 조건을 좀 더 달았다.
기존의 조건문들은 공격력과 방어력이 10 미만일때만 출력되게끔 하고
공격력, 방어력이 10 이상일 경우에 출력될 조건문을 새로 작성했다.
깔끔하게 정렬된 모습을 보니 속이 편안해진다.
이런 사소한 부분을 개선함으로 편안함을 느끼는 것이 개발함에 있어서 활력이 되어주는게 아닐까 싶다.
잠시 환기도 했으니 다시 상점에 몰두할 차례다.
일단 상점의 틀은 마련했으니 바로 아이템 구매 창으로 넘어간다.
아이템 구매도 인벤토리-장착관리와 마찬가지로 상점의 내용을 복사붙여넣기 하고 내부 내용을 조금 다듬었다.
기존 상점에서는 아이템 번호가 뜨지 않았던것을 아이템 번호가 뜨게끔 변경해주었고, 아이템 번호로 아이템을 구매할 수 있게끔 메뉴란도 손봤다.
그 뒤 input이 0일때는 아예 상점에서 나가지게끔,
input이 0이 아니면서 itenmsInDatabase.Count보다 작거나 같다면 인벤토리에서 그랬던것과 마찬가지로 input - 1을 selectedShopItem으로 지정해주었다.
그리고 조건을 달아 playerStat.Gold가 selectedShopItem.ItemPrice보다 적다면 골드부족 안내문을,
playerStat.Gold가 selectedShopItem.ItemPrice보다 크거나 같다면 구매완료 후 selectedShopItem.IsPlayerOwned를 true로 바꿔주었고, playerStat.Gold에서 selectedShopItem.ItemPrice를 빼주었다.
그리고 이미 구매완료한 상품이라면 구매완료 안내문을 띄우게끔 해주었다.
그러고나서 보니 아이템 구매 관련해서는 구매하지 않은 아이템에 맞게끔 안내문을 띄워줘야하므로 골드부족이나 구매완료 조건문은 selectedShopItem.IsPlayerOwned 가 false여야했으므로 조건문에 추가해주었다.
그리고 Thread.Sleep(); 이라는 기능을 통해 아이템 구매에서 항목을 선택한 뒤, 만족되는 조건문을 실행한 뒤 3초 뒤에 다시 아이템 구매항목으로 돌아가게끔 코드 작성을 했다.
이로써 상점부분 구현까지 마무리했다.
라고 생각했는데 잘못된 입력을 했을때에 실행할 것이 빠졌다.
개인과제 구현목록에는 "잘못된 입력입니다." 출력이라고 되어있지만, 실수로 게임이 그대로 끝나버리는건 좀 그렇다는 생각이 들어서, 아무키나 누르면 처음화면으로 돌아가는 쪽으로 노선을 바꿔봤다.
그리고 찾아보니 Console.ReadKey(true);를 쓰면 어떤 키를 눌렀을때에 그 다음에 오는 기능을 실행할 수 있게끔 되어있더라.
그래서 이런 메서드를 만들어서 각 장면마다 하나씩 넣어주었다.
오류 수정
이것 저것 실행을 해보는 와중에 치명적인 버그를 발견해냈다.
인벤토리 - 상점을 왔다갔다 하면 아이템이 무한 증식을 하는 것이다.
기껏 잘만들어놨더니 웬 버그냐.. 진짜 속상하다..
하지만 속상해한다고 버그가 고쳐지진 않는다.
그래서 뭐가 문제인가 해서 비주얼 스튜디오를 차근차근 살펴봤더니
개인과제를 싸그리 갈아엎기전에는 Main에 스파르타마을씬을 넣어놨었고, 지금은 MainScene으로 스파르타 마을을 따로 분리를 해놓고, Main에는 플레이어의 초기 능력치를 정의하고, 리스트 ItemsDatabase에게 new ItemData를 Add하는 명령을 실행시켜 초기에 플레이어가 들고갈 아이템을 설정을 해주었다.
근데 문제는 ItemsDatabase는 단순히 초기에 플레이어가 들고갈 아이템 뭉치가 아니라 총 아이템 덩어리들에서 true, false값만 설정해 초기 아이템 설정을 했던 것이고, 상점에서 0을 입력하면 MainScene을 호출하는 것이 아니라 Main을 호출하기때문에 ItemsDatabase는 Main을 호출할때마다 new ItemData를 Add했던 것이다.
답을 찾았으니 해결법은 간단하다. Main을 MainScene으로 고쳐주기만 하면 되는 것.
버그도 깔끔하게 해결해냈다.
아직 필수구현기능만 담아넣었지만 참 긴 싸움이었다.
Github로 레퍼지토리 생성 후 제출도 완료했으니 이제 추가구현기능이 남았다.
그 중에서 일단 쉬운 것부터 해보고 그 뒤에 어려운 과제를 시도해보고자 한다.
일단 추가 아이템 구현 같은 경우는 공격과 방어 능력치 모두 올려주는 아이템이나, 체력을 올려주는 아이템을 추가해보면 어떨까 싶다.
체력 올리는 아이템은 리스트 근본부터 뜯어고쳐야 하는데 마감기한이 있는 촉박한 과제는 아니니 느긋하게 하다보면 되지 않을까?
추가기능구현
- 나만의 아이템 추가 및 체력을 더해주는 아이템 추가
체력 아이템 구현을 위해 클래스에 public int ItemHp를 추가 하고 생성자에도 추가로 넣어줬다.
생성자의 매개변수가 변했으니 당연히 아이템리스트내부의 아이템들에도 체력 능력치를 넣어줘야한다.
하는김에 아이템도 마구 추가해서 리스트도 갱신해줬다.
그 뒤에는 공격력이냐 방어력이냐를 보여주는 메서드에 체력 항목을 추가하여 만들고
UpdatePlayerStats에 체력도 추가하여 아이템에 적용된 체력 능력치가 플레이어의 체력 능력치에 반영이 되게끔 했다.
그 뒤 장비를 착용함으로 체력을 얻은 체력 표기까지 공격력 방어력과 마찬가지로 작업해주었다.
정상적으로 잘 작동하는 모습이다.
근데 체력 아이템을 구현하고 나니 또 한가지 문제가 생겼다.
공 방 체 모두 갖춘 아이템의 경우 체력 증가량이 표기가 되지 않던 부분이다.
공격력이냐 방어력이냐 부분에 추가하기에는 (이미 충분히 번잡하지만) 너무 코드가 번잡해질거 같아서 아이템 선택 화면을 메서드없이 if문 이하에 새로이 만들었다.
이렇게 하면 적어도 아이템 구매를 할때만이라도 아이템에 붙어있는 체력 능력치까지 모두 확인이 가능해진다.
추가기능 중 나만의 아이템 만들기와 그것을 자연스럽게 만들어줄 여러 기능들을 추가해봤다.
프로그래밍은 단순히 아이템만 하나 띡 만들고 끝나는게 아니라 이미 작성된 코드의 여러부분들을 다시금 다듬는, 세심한 작업이 요구됨을 배우게 되었다.
오늘의 회고
머리가 터지게 고민하고 이해가 안된 부분들은 이해하려고 노력하고 구글링해보고 해서 나온 결과물이 생각보다 괜찮게 작동해서 많이 뿌듯한 하루였다.
그저 C# 언어에 대해서 배울때는 머리가 지끈거렸는데 그 결과물이 한눈에 볼 수 있게끔 나타나니 보람차다.
어쩌면 이게 게임제작의 큰 매력이 아닐까?
주말동안은 C# 문법 4,5주차 강의를 수강하고 3주차 과제도 한번 해보려고 한다.
과연 내 열정이 나의 게으름을 이길 수 있을지..