오늘 학습 키워드
Enum 순회, Class, List
오늘 학습 한 내용을 나만의 언어로 정리하기
Enum을 순회하는 방법
public enum Jobs
{
Warrior,
Mage,
}
이걸 순회하고자 했음.
foreach (Jobs job in Enum.GetValues(typeof(Jobs)))
{
Console.WriteLine(job);
}
여기서 Enum.GetValues는 Enum 안에 value값으로 지정된 정수들을 list로 반환함. Enum.GetValues는 인자로 특정 Enum의 타입 정보를 요구함 그래서 typeof(Jobs)가 필요함.
>>> Class는 값이 아니고 참조 형식이다 <<< !!!
public void EquipmentChanged(int itemIndex, bool isEquip)
{
Item item = GameManager.instance.playerData.Items[itemIndex];
Console.Clear();
if (isEquip)
{
Console.WriteLine($"{item.Name} 아이템을 장착했습니다.");
GameManager.instance.playerData.Items[itemIndex].IsEquip = true;
if (GameManager.instance.playerData.EquipItem[(int)item.ItemType].IsEquip)
{
GameManager.instance.playerData.Items[(x => x.Name == item.Name].IsEquip = false;
}
GameManager.instance.playerData.EquipItem[(int)item.ItemType] = item;
}
else
{
Console.WriteLine($"{item.Name} 아이템을 해제했습니다.");
GameManager.instance.playerData.Items[itemIndex].IsEquip = false;
GameManager.instance.playerData.EquipItem[(int)item.ItemType] = null;
}
}
위 코드를 보면 알겠지만, item에다가 itemIndex 위치에 맞는 플레이어 아이템을 넣어 두긴 했으나…
이게 값 복사 형식인줄 알고 무서워서 밑에서 안썼음..
근데? 생각해보니 클래스는 참조 형식이라 원본 위치 고~대로 가져옴
내가 바보였다.
List에서 특정 조건으로 내부 값 찾기
- FindIndex를 사용함
int index = GameManager.instance.playerData.Items.FindIndex(x => x.Name == item.Name);
if (index >= 0)
{
GameManager.instance.playerData.Items[index].IsEquip = false;
}
- FirstOrDefault를 사용함
var targetItem = GameManager.instance.playerData.Items.FirstOrDefault(x => x.Name == item.Name);
if (targetItem != null)
{
targetItem.IsEquip = false;
}
같은 카테고리의 아이템은 하나만 착용하게 하기
public void EquipmentChanged(int itemIndex, bool isEquip)
{
Item item = GameManager.instance.playerData.Items[itemIndex];
Console.Clear();
if (isEquip)
{
Console.WriteLine($"{item.Name} 아이템을 장착했습니다.");
item.IsEquip = true;
Item alreadyEquip = GameManager.instance.playerData.EquipItem[(int)item.ItemType];
if (alreadyEquip != null && alreadyEquip.IsEquip)
{
var alreadyEquipInItems = GameManager.instance.playerData.Items.FirstOrDefault(x => x.Name == alreadyEquip.Name);
if (alreadyEquipInItems != null) alreadyEquipInItems.IsEquip = false;
}
GameManager.instance.playerData.EquipItem[(int)item.ItemType] = item;
}
else
{
Console.WriteLine($"{item.Name} 아이템을 해제했습니다.");
item.IsEquip = false;
GameManager.instance.playerData.EquipItem[(int)item.ItemType] = null;
}
}
- item을 착용하려는건지 확인 (if (isEquip))
- alreadyEquip에 item 카테고리로 이미 입고있는 아이템 넣기
- alreadyEquip이 null이 아니고, IsEquip 확인
- alreadyEquip을 플레이어의 Items에서 찾은 후 IsEquip false 해주기
변경된 구조
classDiagram direction TB class IGameScene { +SetNextScene(IGameScene nextScene) +SetPrevScene(IGameScene prevScene) +StartScene() +PrintNextScenes() +EndScene(int nextSceneIdx) } class PlayerData { +Name +Level +Job +ATK +DEF +HP +Gold +List EquipItems +List Items +List Skills } class GameScene { List nextScenes IGameScene prevScene sceneIndex +SetNextScene(IGameScene nextScene) +SetPrevScene(IGameScene prevScene) +StartScene() +PrintNextScenes() +EndScene() } class FirstScene { } class TownScene { } class ProfileScene { } class InventoryScene { } class InnScene { } class Item { +Name +Description +Stat +Price +IsEquip +ItemType } class Skill { +Name +Description +Cooldown +Power +isMultiply } class GameManager { +enum SceneType +GameManager instance +Dictionary sceneString +Dictionary scenes +Dictionary itemTypeString +PlayerData playerData +string path +SceneSetting() +GameExit() +NewPlayerData(string playerName) +LoadPlayerData() +SavePlayerData() } class Dungeon { +Name +Description +GoldReward +ExperienceReward +NeedDEF +List monsters } class Monster { +Name +ATK +DEF +HP +MaxHP +IsDead } class ShopItem { +isSoldOut +string ToShopString() } class SkillTreeSkill { +isLearned +needLevel +needJob +UpdateCanILearn() +ToSkillTreeString() } class SkillInventoryScene { +List skillTreeSkills } class ShopScene { +List shopItems } class DungeonScene { +List dungeons } <<Interface>> IGameScene <<Class>> PlayerData <<Class>> GameScene <<Class>> FirstScene <<Class>> TownScene <<Class>> ProfileScene <<Class>> InventoryScene <<Class>> InnScene <<Class>> Item <<Class>> Skill <<Class>> GameManager <<Class>> Dungeon <<Class>> Monster <<Class>> ShopItem <<Class>> SkillTreeSkill <<Class>> SkillInventoryScene <<Class>> ShopScene <<Class>> DungeonScene GameManager o-- IGameScene GameManager o-- PlayerData IGameScene <|.. GameScene GameScene <|-- FirstScene GameScene <|-- TownScene GameScene <|-- ProfileScene GameScene <|-- InventoryScene GameScene <|-- SkillInventoryScene GameScene <|-- ShopScene GameScene <|-- InnScene GameScene <|-- DungeonScene PlayerData o-- Item PlayerData o-- Skill DungeonScene o-- Dungeon Dungeon o-- Monster Item -- ShopItem ShopScene -- ShopItem Skill -- SkillTreeSkill SkillInventoryScene -- SkillTreeSkill
Scenes 안에 함수들은 너무 많아서 따로 정리 안함..
json 저장할 때 쓸만한 것
나중에 써먹으려고 저장함
[JsonConverter(typeof(JsonStringEnumConverter))]
Enum 형식의 데이터를 json 으로 저장할 때, value인 정수로 저장하는 것이 아니고 key값인 문자열로 저장하는 방식을 쓰도록 함.
학습하며 겪었던 문제점 & 에러
문제 1
- 문제&에러에 대한 정의
두 마리의 슬라임을 던전에 배치했을 때, 첫 번째 슬라임을 공격해도 두 마리에게 모두 데미지가 일어남 ⇒ 알고보니 같은 오브젝트를 두 번 넣다보니 그냥 그림자 분신술이 일어난 것과 같음
- 해결 방법
같은 기수 분한테 아이디어를 얻음 슬라임의 부모 클래스인 Monster 안에 새 인스턴스를 반환하는 MakeClone() 함수를 만들어서 그걸 부르는 것
- 새롭게 알게 된 점
C#은 참조 형태의 깊은 복사를 허용하지 않는다.
- 이 문제&에러를 다시 만나게 되었다면?
자주 생겨야되는 데이터는 새 인스턴스 반환하는 함수를 만들어두자.
문제 2
- 문제&에러에 대한 정의
분명 파이어볼과 메테오는 법사 전용 스킬인데, 게임을 껐다가 키면 전사 전용으로 바뀌어 있음. 애초에 직렬화가 제대로 안된것같음.
- 해결 방법
public 프로퍼티 Get, Set을 만들어 준다
- 새롭게 알게 된 점
System.Text.Json의 기본 직렬화 정책은 Public 프로퍼티 만 직렬/역직렬화 한다. ⇒ 필드를 무시한다!!!!
- 이 문제&에러를 다시 만나게 되었다면?
get/set 을 만들어두자!!!
내일 학습 할 것은 무엇인지
완성한 TextRPG ReadMe 작성하기 딸기밭 팀프로젝트 진행