c# 강의/과제

20200427 - 싱글톤

쪼혀 2020. 4. 28. 00:43

> 기능 및 특징

1. 싱글톤  ManagerData.cs

2. Chatacter.cs 상속

   - Hero.cs

   - Monster.cs

3. HeroInfo.cs 저장될 데이터 클래스, 선택적 매개변수 생성자 활용

4. Data파일들

- HeroData

- ClassData

- ExpData

- GoldData

- ItemData

- MonsterData

 

> 추후 개선시 참고사항

- UI  / 기능,데이터의  명확한  역할 구분 

- 매니저클래스에 제너릭 활용

- enum 및 데이터 파일 저장 등

 

 

> JSON Data

더보기

1. class_data.json

[{
        "id": 100,
        "class_type": 0,
        "class_name": "초보자",
        "require_level": 0
    },
    {
        "id": 101,
        "class_type": 1,
        "class_name": "검사",
        "require_level": 10
    },
    {
        "id": 102,
        "class_type": 1,
        "class_name": "파이터",
        "require_level": 30
    },
    {
        "id": 103,
        "class_type": 1,
        "class_name": "크루세이더",
        "require_level": 50
    },
    {
        "id": 104,
        "class_type": 1,
        "class_name": "히어로",
        "require_level": 90
    },
    {
        "id": 105,
        "class_type": 1,
        "class_name": "하이퍼 히어로",
        "require_level": 120
    },
    {
        "id": 106,
        "class_type": 2,
        "class_name": "아처",
        "require_level": 10
    },
    {
        "id": 107,
        "class_type": 2,
        "class_name": "헌터",
        "require_level": 40
    },
    {
        "id": 108,
        "class_type": 2,
        "class_name": "레인저 ",
        "require_level": 80
    },
    {
        "id": 109,
        "class_type": 2,
        "class_name": "보우마스터",
        "require_level": 120
    },
    {
        "id": 110,
        "class_type": 2,
        "class_name": "하이퍼 보우마스터",
        "require_level": 160
    }
]

 

2. exp_data.json

[
	{
		"exp_id": 100000,
		"level": 1,
		"require_exp": 50
	},
	{
		"exp_id": 100001,
		"level": 2,
		"require_exp": 100
	},
	{
		"exp_id": 100002,
		"level": 3,
		"require_exp": 150
	},
	{
		"exp_id": 100003,
		"level": 4,
		"require_exp": 225
	},
	{
		"exp_id": 100004,
		"level": 5,
		"require_exp": 337
	},
	{
		"exp_id": 100005,
		"level": 6,
		"require_exp": 506
	},
	{
		"exp_id": 100006,
		"level": 7,
		"require_exp": 759
	},
	{
		"exp_id": 100007,
		"level": 8,
		"require_exp": 1139
	},
	{
		"exp_id": 100008,
		"level": 9,
		"require_exp": 1708
	},
	{
		"exp_id": 100009,
		"level": 10,
		"require_exp": 2562
	},
	{
		"exp_id": 100010,
		"level": 11,
		"require_exp": 3844
	}
]

 

3. gold_data.json

[{
	"id": 100,
	"name": "골드"
}]

 

4. hero_data.json

[{
    "id": 1000,
    "class_id": 100,
    "hp": 50,
    "mp": 30,
    "damage": 1.5
}]

 

5. item_data.json

[
	{
		"id": 100,
		"name": "초록 달팽이 껍질",
		"resource_name": "green_snail_shell",
		"icon_name": "ico_green_snail_shell",
		"sell_price": 1,
		"item_type": 0
	},
	{
		"id": 101,
		"name": "파란 달팽이 껍질",
		"resource_name": "bule_snail_shell",
		"icon_name": "ico_bule_snail_shell",
		"sell_price": 1,
		"item_type": 0
	},
	{
		"id": 102,
		"name": "빨간 달팽이 껍질",
		"resource_name": "red_snail_shell",
		"icon_name": "ico_red_snail_shell",
		"sell_price": 1,
		"item_type": 0
	},
	{
		"id": 103,
		"name": "매소 (소 )",
		"resource_name": "meso_small",
		"icon_name": "ico_meso_small",
		"sell_price": 0,
		"item_type": 4
	},
	{
		"id": 104,
		"name": "매소 (중)",
		"resource_name": "meso_midium",
		"icon_name": "ico_meso_midium",
		"sell_price": 0,
		"item_type": 4
	},
	{
		"id": 105,
		"name": "매소 (대)",
		"resource_name": "meso_large",
		"icon_name": "ico_meso_large",
		"sell_price": 0,
		"item_type": 4
	}
]

 

6. monster_data.json

[
  {
    "id": 1000,
    "name": "초록 달팽이",
    "hp": 25,
    "damage": 2.5,
    "exp": 1,
    "drop_item_id": 100
  },
  {
    "id": 1001,
    "name": "파란 달팽이",
    "hp": 25,
    "damage": 2.8,
    "exp": 2,
    "drop_item_id": 101
  },
  {
    "id": 1002,
    "name": "빨간 달팽이",
    "hp": 25,
    "damage": 3,
    "exp": 3,
    "drop_item_id": 102
  },
  {
    "id": 2000,
    "name": "머쉬맘",
    "hp": 1000,
    "damage": 8,
    "exp": 10,
    "drop_item_id": 103
  }
]

 

 

> Code

1. Data 클래스

더보기
    class MonsterData
    {
        public int id;
        public string name;
        public int hp;
        public float dmage;
        public int exp;
        public int drop_item_id;

    }
    class ItemData
    {
        public int id;
        public string name;
        public string resource_name;
        public string icon_name;
        public int sell_price;
        public int item_type;

    }
class HeroData
    {
        public int id;
        public int class_id;
        public int hp;
        public int mp;
        public float damage;

        public HeroData(int id, int class_id, int hp, int mp, float damage)
        {
            this.id = id;
            this.class_id = class_id;
            this.hp = hp;
            this.mp = mp;
            this.damage = damage;
        }
    }
    class GoldData
    {
        public int id;
        public string name;
    }
    class ExpData
    {
        public int exp_id;
        public int level;
        public int require_exp;
    }
    class ClassData
    {
        public int id;
        public int class_type;
        public string class_name;
        public int require_level;

    }

    class Character
    {
        public Character()
        {
        }
        public virtual void Attack(Character target) { }

        public virtual void Hit(float damamge) { }

        public virtual void Die() { }
    }

 

 

2. Info 클래스

더보기
    class HeroInfo
    {
        public string name;
        public int level;
        public int classType; // 직업타입
        public int classGrade; // 등급 id 검사or 파이터등 등급을 말하는 것?
        public float damage;
        public int hp;
        public int mp;
        public int exp;
        public int gold;

        // 선택적 매개변수 뒤쪽에 배치 필요
        public HeroInfo(string name, int hp, int mp, float damage,
             int level = 1, int classType = 0, int classGrade = -1, int exp = 0, int gold=0)
        {
            this.name = name;
            this.level = level;
            this.classType = classType;
            this.classGrade = classGrade;
            this.hp = hp;
            this.mp = mp;
            this.damage = damage;
            this.exp = exp;
            this.gold = gold;
        }
    }

 

3. 싱글톤 매니저 클래스

더보기
    class DataManager
    {
        private static DataManager singleTone;

        private Dictionary<int, HeroData> dicHeroData;
        private Dictionary<int, ClassData> dicClassData;
        private Dictionary<int, ExpData> dicExpData;
        private Dictionary<int, GoldData> dicGoldData;
        public Dictionary<int, ItemData> dicItemData;
        private Dictionary<int, MonsterData> dicMonsterData;

        public static DataManager GetInstance()
        {

            if (DataManager.singleTone == null)
            {
                DataManager.singleTone = new DataManager();
                return DataManager.singleTone;
            }
            else
            {
                return DataManager.singleTone;
            }

        }// GetInstance end;

        public void LoadDatas()
        {
            string json = "";
            string path = "";

            try
            {
                // 영웅 생성
                path = "./data/hero_data.json";
                if (File.Exists(path))
                {
                    json = File.ReadAllText(path);
                    this.dicHeroData = JsonConvert.DeserializeObject<HeroData[]>(json).ToDictionary(x => x.id, x => x);
                }

                // 몬스터 생성
                path = "./data/monster_data.json";
                if (File.Exists(path))
                {
                    json = File.ReadAllText(path);
                    this.dicMonsterData = JsonConvert.DeserializeObject<MonsterData[]>(json).ToDictionary(x => x.id, x => x);
                }

                // 아이템 생성
                path = "./data/item_data.json";
                if (File.Exists(path))
                {
                    json = File.ReadAllText(path);
                    this.dicItemData = JsonConvert.DeserializeObject<ItemData[]>(json).ToDictionary(x => x.id, x => x);
                }

                // 전직 데이터
                path = "./data/class_data.json";
                if (File.Exists(path))
                {
                    json = File.ReadAllText(path);
                    this.dicClassData = JsonConvert.DeserializeObject<ClassData[]>(json).ToDictionary(x => x.id, x => x);
                }

                // 경험치 데이터
                path = "./data/exp_data.json";
                if (File.Exists(path))
                {
                    json = File.ReadAllText(path);
                    this.dicExpData = JsonConvert.DeserializeObject<ExpData[]>(json).ToDictionary(x => x.exp_id, x => x);
                }

                // 골드 데이터
                path = "./data/gold_data.json";
                if (File.Exists(path))
                {
                    json = File.ReadAllText(path);
                    this.dicGoldData = JsonConvert.DeserializeObject<GoldData[]>(json).ToDictionary(x => x.id, x => x);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                throw;
            }
        }

        public HeroData GetCharacterDataById(int id)
        {
            return this.dicHeroData[id];
        }

        public MonsterData GetMonsterDataById(int id)
        {
            return this.dicMonsterData[id];
        }

        public ExpData GetExpDataByLevel(int level){
            var result = this.dicExpData.FirstOrDefault(v => v.Value.level == level).Value;
            return result;
        }

        public ClassData GetClassDataByClassType(int classType){ 
            var result = this.dicClassData.FirstOrDefault(v => v.Value.class_type == classType).Value;
            return result;
        }

        public GoldData GetGoldDataById(int id){
            return this.dicGoldData[id];
        }

        public ItemData GetItemDataById(int dropItemId){
            return this.dicItemData[dropItemId];
        }
    }

 

4. Monster / Hero 클래스

더보기
    class Monster : Character
    {
        public int id;
        public string name;
        public float hp;
        public float damage;
        public int exp;
        public int drop_item_id;
        public float maxHp;

        public Monster(MonsterData data)
        {
            this.id = data.id;
            this.name = data.name;
            this.hp = data.hp;
            this.damage = data.dmage;
            this.exp = data.exp;
            this.drop_item_id = data.drop_item_id;
            this.maxHp = data.hp;

            Console.WriteLine(this.name + " 이 생성되었습니다.");
        }

        public override void Attack(Character target)
        {
            Console.WriteLine(target);
            target.Hit(this.damage);
        }

        public override void Hit(float damage)
        {
            Console.WriteLine("몬스터 hit");
            this.hp -= damage;
            if (this.hp <= 0)
            {
                this.Die();
            }
        }

        public override void Die()
        {
            Console.WriteLine("몬스터가 죽었습니다.");
        }

        public bool IsDie() {
            this.hp = 0; //강제 죽임 test
            if (this.hp <= 0) {
                return true;
            }
            return false;
        }
    }

    class Hero : Character
    {
        // 데이터 변경과 에니메이션 담당 -> 외부에 결과 전달(App())
        public HeroInfo info;
        public Hero()
        {
            Console.WriteLine("영웅이 생성되었습니다.");
        }

        public void Init(HeroInfo info)
        {
            this.info = info;
        }

        public override void Attack(Character target)
        {
            target.Hit(this.info.damage);
        }

        public override void Hit(float damage)
        {
            Console.WriteLine($"{this.info.name}이  {damage} 피해를 입어습니다.");
        }

        public override void Die()
        {
           this.info.hp = 0;
            Console.WriteLine("- game over 주인공이 죽었습니다.");
        }

        // 경험치 획득
        public void GetExp(int getExp) {
            this.info.exp += getExp;
            Console.WriteLine($"{this.info.exp} 경험치 획득");
            Console.WriteLine();
        }

        // 경험치 확인
        public void CheckExp(Hero hero) {
          var dataManager = DataManager.GetInstance();
          var exp = hero.info.exp; // 현재 경험치

          //현재 레벨로 가져온 exp데이터
          var expData = dataManager.GetExpDataByLevel(hero.info.level); 
            
          //다음레벨 exp데이터 
          var nextData = dataManager.GetExpDataByLevel(hero.info.level+1); 

          // 레벨업 체크
          if(exp >= expData.require_exp){
             this.LevelUp(hero);
          }else{
            Console.WriteLine($"-Lev{hero.info.level} / {hero.info.exp} -> -Lev{nextData.level} / {expData.require_exp} 필요");
          }
            Console.WriteLine();
        }

        // 레벨 업
        public void LevelUp(Hero hero)
        {
            // 전직 여부 체크
            var dataManager = DataManager.GetInstance();

            if(hero.info.classType == 0 ){ // 초보자 일경우
                Console.WriteLine("- 축하합니다. 전직이 가능합니다.");
                this.ClassChange();
                this.HeroPrint();
            }else{
                // 레벨업
                Console.WriteLine("- 레벨이 올랐습니다.");
                this.UpGrage();
                this.HeroPrint();
            }
        }

        // 스텟 상향
        public void UpGrage(){
             var dataManager = DataManager.GetInstance();

              var classData = dataManager.GetClassDataByClassType(this.info.classGrade+1);

              this.info.classGrade = classData.id;
              this.info.name = classData.class_name;
              this.info.level +=1;
        }

        public void HeroPrint(){
            var hero = this.info;
            Console.WriteLine($"name:{hero.name}/ Lev:{hero.level} / (hp:{hero.hp}/hp:{hero.mp})");
        }

        // 전직
        public void ClassChange()
        {
            var dataManager = DataManager.GetInstance();
            var choiceClass1 = dataManager.GetClassDataByClassType(1);
            var choiceClass2 = dataManager.GetClassDataByClassType(2);

            Console.WriteLine($"1.{choiceClass1.class_name} / 2.{choiceClass2.class_name} 선택");
            Console.WriteLine("1번 선택");
            var userInput=1;

            switch (userInput)
	        {
                case 1:
                    Console.WriteLine("검사를 선택하셨습니다.");
                    this.info.name = choiceClass1.class_name;
                    this.info.classType = choiceClass1.class_type;
                    this.info.classGrade = choiceClass1.id; // 검사 101
                    this.info.level +=1;
                    break;
                case 2:
                    Console.WriteLine("아처를 선택하셨습니다.");
                    this.info.name = choiceClass2.class_name;
                    this.info.classType = choiceClass2.class_type;
                    this.info.classGrade = choiceClass2.id; // 아처 10
                    this.info.level +=1;
                    break;
		        default:
                    break;
	        }
                    Console.WriteLine();
        }

        //아이템 획득
        public void PickItem(Monster target){
            var dataManager = DataManager.GetInstance();
            var getItem = dataManager.GetItemDataById(target.drop_item_id);

            Console.WriteLine($"- 아이템획득: {getItem.name} / 판매가격:{getItem.sell_price} / {getItem.resource_name}");
            Console.WriteLine();
        }

        //골드 획득
        public void PickGold(int id){
            var dataManagere = DataManager.GetInstance();
            GoldData goldData = dataManagere.GetGoldDataById(id);

            this.info.gold += goldData.id;

            Console.WriteLine($"- {goldData.name}({goldData.id}) 획득!");
            Console.WriteLine();
        }
    }

 

5. App 클래스

더보기
    class App
    {
        public App()
        {
            // 데이터 로드
            // 영웅 생성
            // 몬스터 생성
            // 몬스터 공격
            // 몬스터 처치
            // 아이템 드랍
            // 경험치, 아이템 획득
            // 레벨업
            // 전직

            var dataManager = DataManager.GetInstance();
            dataManager.LoadDatas();


            Hero hero  = this.CreateDefaultHero();
            Monster monster = this.CreateMonster(1000);

            //몬스터 공격
            hero.Attack(monster);

            Console.WriteLine($"({monster.hp}/{monster.maxHp})" );

            // 죽임
            monster.Die();
            monster.IsDie();


            // 경험치 획득 
            if (monster.IsDie())
            {
                hero.GetExp(monster.exp);
                hero.CheckExp(hero);

                // 강제 레벨업 - 전직
                hero.LevelUp(hero);

                // 아이템 획득
                hero.PickItem(monster);

                // 골드획득 - 몬스터 고유 id 전달하여 해당 수치만큼 골드 수급
                hero.PickGold(100);
            }
        }


        
        public Monster CreateMonster(int id)
        {
            var monsterData = DataManager.GetInstance().GetMonsterDataById(id);

            return new Monster(monsterData);
        }

        public Hero CreateDefaultHero()
        {
            var characterData = DataManager.GetInstance().GetCharacterDataById(1000);

            var heroInfo = new HeroInfo("홍길동", characterData.hp, characterData.mp, characterData.damage);
            Hero hero = new Hero();
            hero.Init(heroInfo);
            Console.WriteLine(hero.info.name + " 님이 입장하셨습니다.");
            return hero;
        }
    }