22.01.17 텍스트기반 게임 만들기 Part.2

2022. 1. 17. 18:57C#/수업 내용

5) 몬스터가 있는 필드로 나가 고블린 무리와 싸운다.
5-1) 몬스터를 맞닥뜨리면 해당 몬스터의 정보 텍스트가 나온다.
5-2) 나 한대, 몬스터 한대 번갈아가면서 공격한다. 공격 성공 시 적의 남은 체력상태가 표시된다.
5-3) 고블린에게 패배하면 해당 캐릭터의 정보와 모든 게임 정보가 삭제된다.
5-4) 고블린에게 승리하면 골드 보상을 얻는다.

6) 게임 세이브를 하면 게임 진행 상태를 저장시킨다.

7) 무기에 내구도를 적용시킨다. 내구도 0이 되면 파괴된다.

8) 무기를 최대 2개까지 휴대할 수 있도록 한다.


고블린과 전투

 

무기 파괴됨. 자동으로 무기 스왑

 

무기 획득 및 교체

 

무기 전환

 

소스코드--------------------------------------------------------------------------------------

 

        public App()
        {
            DataMgr mgr = DataMgr.GetInstance();
            mgr.LoadData();
            mgr.DiscernUserType();

            while (!mgr.dead)
            {
                GoWhere(mgr.gi.mapInfo.mapIndex);
                if (mgr.dead)
                {
                    mgr.dead = false;
                    mgr.DiscernUserType();
                }
            }
            mgr.gi.CheckMyStatus();
            mgr.gi.CheckWeaponStatus();
            if (!mgr.dead)
            {
                mgr.SaveData();
            }
        }

        public void GoWhere(int i)
        {
            switch (i)
            {
                case 1:
                    Smithy sm = new Smithy();
                    break;
                case 2:
                    OpenField1 op = new OpenField1();
                    break;
            }
        }
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Newtonsoft.Json;
using System.Linq;

namespace helloworldConsoleApp1
{
    class DataMgr
    {
        private static DataMgr instance;

        public bool dead = false;
        public bool TurnOn = true;

        private const string Datas_Path = "./Datas";
        private const string GAME_INFO_PATH = "game_info.json";
        private const string WEAPON_DATA_PATH = "weapon_data2.json";
        private const string CHARACTER_DATA_PATH = "character_data.json";
        private const string MONSTER_DATA_PATH = "monster_data.json";

        public GameInfo gi;

        private Dictionary<int, weapon_data> dictWeaponData = new Dictionary<int, weapon_data>();
        private Dictionary<int, Character_data> dictCharacterData = new Dictionary<int, Character_data>();
        private Dictionary<int, Monster_data> dictMonsterData = new Dictionary<int, Monster_data>();

        public void LoadData()
        {
            string path = string.Format("{0}/{1}", Datas_Path, WEAPON_DATA_PATH);
            string json = File.ReadAllText(path);
            this.dictWeaponData = JsonConvert.DeserializeObject<weapon_data[]>(json).ToDictionary(x => x.id);

            path = string.Format("{0}/{1}", Datas_Path, CHARACTER_DATA_PATH);
            json = File.ReadAllText(path);
            this.dictCharacterData = JsonConvert.DeserializeObject<Character_data[]>(json).ToDictionary(x => x.id);

            path = string.Format("{0}/{1}", Datas_Path, MONSTER_DATA_PATH);
            json = File.ReadAllText(path);
            this.dictMonsterData = JsonConvert.DeserializeObject<Monster_data[]>(json).ToDictionary(x => x.id);

            /*string getWeaponsJson = File.ReadAllText(WEAPON_DATA_PATH);

            weapon_data[] weapons = JsonConvert.DeserializeObject<weapon_data[]>(getWeaponsJson);

            foreach (weapon_data weapon in weapons)
            {
                dict.Add(weapon.id, weapon);
            }*/
        }

        public void DiscernUserType()
        {
            if (File.Exists(GAME_INFO_PATH))
            {
                Console.WriteLine("기존 유저입니다.");
                string getJson = File.ReadAllText(GAME_INFO_PATH);
                this.gi = JsonConvert.DeserializeObject<GameInfo>(getJson);
                this.gi.CheckWeaponStatus();
                this.gi.CheckMyStatus();
            } else
            {
                Console.WriteLine("신규 유저입니다.");
                this.gi = new GameInfo();
                this.gi.mapInfo = new MapControl();
                this.gi.mapInfo.Init();
                Console.WriteLine("");
                Console.WriteLine("당신은 누구인가요?");
                for (int i = 0; i < 4; i++)
                {
                    Console.WriteLine("\n{0} => {1}", i, GetCharacterData(i).name);
                }
                Console.WriteLine("");
                string choice = Console.ReadLine();
                int choice2 = Convert.ToInt32(choice);
                Console.WriteLine("");
                Character_data charData = GetCharacterData(choice2);
                this.gi.me = new Adventurer(charData.id, charData.name);
                this.gi.me.Init();
                Console.WriteLine("{0}를 결정하셨습니다.", this.gi.me.name);
                Console.WriteLine("신규 유저를 위해 5단계 무기를 지급했습니다.");
                weapon_data data = GetWeaponData(charData.default_weapon_id);
                Weapon startWeapon = new Weapon(data.id, data.name, data.damage, data.sellPrice, data.grade, 5, 50);
                this.gi.WeaponInit();
                this.gi.GetWeapon(startWeapon);
                this.gi.CheckWeaponStatus();
                this.gi.CheckMyStatus();
                gi.mapInfo.mapIndex = 1;

                string saveJson = JsonConvert.SerializeObject(this.gi);
                File.WriteAllText(GAME_INFO_PATH, saveJson);
            }
        }

        public void SaveData()
        {
            //Console.WriteLine("데이터를 저장했습니다.");
            string saveJson = JsonConvert.SerializeObject(this.gi);
            File.WriteAllText(GAME_INFO_PATH, saveJson);
        }

        public Character_data GetCharacterData(int id)
        {
            return dictCharacterData[id];
        }

        public Monster_data GetMonsterData(int id)
        {
            return dictMonsterData[id];
        }

        public weapon_data GetWeaponData(int id)
        {
            return dictWeaponData[id];
        }

        public static DataMgr GetInstance()
        {
            if(DataMgr.instance == null)
            {
                DataMgr.instance = new DataMgr();
            }
            else
            {
            }
            return DataMgr.instance;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace helloworldConsoleApp1
{
    class Weapon
    {
        public int id;
        public string name;
        public float damage;
        public int sellPrice;
        public int grade;
        public int reinforcement;
        public int durability;

        public Weapon(int id, string name, float damage, int price, int grade, int reinforcement, int durability)
        {
            this.id = id;
            this.name = name;
            this.sellPrice = price;
            this.grade = grade;
            this.reinforcement = reinforcement;
            this.damage = DataMgr.GetInstance().GetWeaponData(id).damage + (reinforcement - 1) * 1.5f;
            //this.damage = damage + reinforcement * 1 - 1; // 암시적으로 Weapon생성자가 호출되기 때문에 데미지가 계속해서 증가하는 문제가 있었다.
            this.durability = durability;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace helloworldConsoleApp1
{
    class Smithy
    {
        DataMgr mgr = DataMgr.GetInstance();

        public Smithy()
        {
            Console.WriteLine("쇠를 두들기는 소리의 근원을 따라 마을 한 구석에 도착하자, \n" +
                "팔 근육이 터질듯한 갈색의 드워프가 운영하는 대장간이 있었다. \n무엇을 할까?");

            while (true)
            {
                Console.WriteLine("\n0 => 무기 제작\n1 => 무기 강화\n2 => 나간다.\n");

                string choice = Console.ReadLine();

                if (choice == "0")
                {
                    Console.WriteLine("\n어떤 무기를 제작할까?");
                    for(int i = 0; i < 8; i++)
                    {
                        Console.WriteLine("\n{0} => {1}", i, mgr.GetWeaponData(i).name);
                    }
                    string choice2 = Console.ReadLine();
                    int choice22 = Convert.ToInt32(choice2);
                    Console.WriteLine("주인장 드워프에게 {0}을 부탁한다고 하자, 그건 자기 전문 분야라며 자신감을 뽐냈다.", mgr.GetWeaponData(choice22).name);
                    Console.WriteLine("결과를 보려면 아무키나 누르세요.");
                    this.CreateWeapon(choice22);
                    Console.ReadLine();
                    Console.WriteLine("갓 탄생한 {0}에게서 왠지 모를 강인함이 느껴진다...", mgr.GetWeaponData(choice22).name);

                }
                else if (choice == "1")
                {
                    Console.WriteLine("강화할 무기를 선택해주세요.");
                    Console.WriteLine("0 -> {0} 강화\n1 -> {1} 강화", mgr.gi.startWeapon[0].name, mgr.gi.startWeapon[1].name);
                    string choice3 = Console.ReadLine();
                    int choice33;
                    int.TryParse(choice3, out choice33);
                    this.EnhanceWeapon(choice33);
                }
                else if (choice == "2")
                {
                    Console.WriteLine("화로의 뜨거운 열기와 귀를 찌르는 금속음을 뒤로 하고 대장간을 나왔다.");
                    mgr.gi.mapInfo.mapIndex = 2;
                    break;
                }
            }
        }

        private void CreateWeapon(int id)
        {
            weapon_data info = mgr.GetWeaponData(id);
            Weapon weapon = new Weapon(info.id, info.name, info.damage, info.sellPrice, info.grade, 1, 50);
            mgr.gi.GetWeapon(weapon);
        }

        private void EnhanceWeapon(int i)
        {
            if(mgr.gi.startWeapon[i].name == "맨손" || mgr.gi.startWeapon[i].name == "없음")
            {
                Console.WriteLine("주인장 드워프 : 나더러 그걸 강화해달라는 건가?");
            } else
            {
                int beforeNum = mgr.gi.startWeapon[i].reinforcement;
                float beforeDamage = mgr.gi.startWeapon[i].damage;
                Console.WriteLine("{0}를 강화해보자!", mgr.gi.startWeapon[i].name);
                Console.WriteLine("주인장 드워프가 내 무기를 세차게 두들기고 담금질한다.");
                Console.WriteLine("결과를 보려면 아무키나 누르세요.");
                mgr.gi.startWeapon[i].reinforcement++;
                mgr.gi.startWeapon[i].damage += 1.5f;
                Console.ReadLine();
                Console.WriteLine("강화 성공!");
                Console.WriteLine("{0} {1}단계 -> {2}단계 / 무기 공격력 : {3} -> {4}",
                    mgr.gi.startWeapon[i].name, beforeNum, mgr.gi.startWeapon[i].reinforcement,
                    beforeDamage, mgr.gi.startWeapon[i].damage);
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace helloworldConsoleApp1
{
    class GameInfo// 게임 플레이의 모든 정보가 담긴 클래스, 이곳으로 접근해서 인벤토리, 스테이터스 창으로 분화된다.
    {
        public MapControl mapInfo;

        public Adventurer me;

        public Weapon[] startWeapon = new Weapon[2];

        public void CheckMyStatus()
        {
            Console.WriteLine("[Status]\n{0} Lv.{2}\n[Equipped Weapon] : {12}\n[Storing Weapon] : {13}\nHealth : {1} / {2}\nMana : {3} / {4}\nStamina : {5} / {6}\n\n[Ability Point]\nstr : {8}\nagi : {9}\nint : {10}\n\nGold : {11}",
                me.name, me.hp, me.max_hp, me.mana, me.max_mana, me.stamina, me.max_stamina, me.level, me.str, me.agi, me.inte, me.gold, startWeapon[0].name, startWeapon[1].name);
        }

        public void CheckWeaponStatus()
        {
            Console.WriteLine("[Equipped Weapon]\n{0} {1}단계 / 무기 공격력 : {2}(+{4}) / 아이템 가격 : {3}\n[Storing Weapon]\n" +
                "{5} {6}단계 / 무기 공격력 : {7}(+{9}) / 아이템 가격 : {8}", 
                startWeapon[0].name, startWeapon[0].reinforcement, DataMgr.GetInstance().GetWeaponData(startWeapon[0].id).damage, startWeapon[0].sellPrice,
                (startWeapon[0].reinforcement - 1) * 1.5f, startWeapon[1].name, startWeapon[1].reinforcement, DataMgr.GetInstance().GetWeaponData(startWeapon[1].id).damage, startWeapon[1].sellPrice,
                (startWeapon[1].reinforcement - 1) * 1.5f);
        }

        public int HowManyWeapon()
        {
            int count = 0;
            for(int i = 0; i < 2; i++)
            {
                if (this.startWeapon[i].name != "맨손" && this.startWeapon[i].name != "없음")
                {
                    count++;
                }
            }
            return count;
        }

        public void WeaponInit()
        {
            weapon_data data = DataMgr.GetInstance().GetWeaponData(8);
            this.startWeapon[0] = new Weapon(data.id, data.name, data.damage, data.sellPrice, data.grade, 1, 9999);
            weapon_data data2 = DataMgr.GetInstance().GetWeaponData(9);
            this.startWeapon[1] = new Weapon(data2.id, data2.name, data2.damage, data2.sellPrice, data2.grade, 1, 9999);
        }

        public void GetWeapon(Weapon weapon)
        {
            int n = HowManyWeapon();
            switch (n)
            {
                case 0:
                    this.startWeapon[1] = this.startWeapon[0];
                    this.startWeapon[0] = weapon;
                    break;
                case 1:
                    Console.WriteLine("교체할 무기를 선택해주세요.");
                    CheckWeaponStatus();
                    Console.WriteLine("0 -> {0}\n1 -> {1}", this.startWeapon[0].name, this.startWeapon[1].name);
                    string choice5 = Console.ReadLine();
                    int choice55;
                    int.TryParse(choice5, out choice55);
                    Console.WriteLine("{0}을 버리고 {1}을 획득했습니다.", this.startWeapon[choice55].name, weapon.name);
                    this.startWeapon[choice55] = weapon;
                    CheckWeaponStatus();
                    break;
                case 2:
                    Console.WriteLine("교체할 무기를 선택해주세요.");
                    CheckWeaponStatus();
                    Console.WriteLine("0 -> {0}\n1 -> {1}", this.startWeapon[0].name, this.startWeapon[1].name);
                    string choice4 = Console.ReadLine();
                    int choice44;
                    int.TryParse(choice4, out choice44);
                    Console.WriteLine("{0}을 버리고 {1}을 획득했습니다.", this.startWeapon[choice44].name, weapon.name);
                    this.startWeapon[choice44] = weapon;
                    CheckWeaponStatus();
                    break;
            }
        }

        public void WeaponBreak()
        {
            int n = HowManyWeapon();
            switch (n)
            {
                case 0:
                    break;
                case 1:
                    Console.WriteLine("{0}이(가) 파괴되어 {1}를 사용합니다.", this.startWeapon[0].name, this.startWeapon[1].name);
                    this.startWeapon[0] = this.startWeapon[1];
                    weapon_data data2 = DataMgr.GetInstance().GetWeaponData(9);
                    this.startWeapon[1] = new Weapon(data2.id, data2.name, data2.damage, data2.sellPrice, data2.grade, 1, 9999);
                    CheckWeaponStatus();
                    break;
                case 2:
                    Console.WriteLine("{0}이(가) 파괴되어 {1}를 사용합니다.", this.startWeapon[0].name, this.startWeapon[1].name);
                    this.startWeapon[0] = this.startWeapon[1];
                    weapon_data data = DataMgr.GetInstance().GetWeaponData(8);
                    this.startWeapon[1] = new Weapon(data.id, data.name, data.damage, data.sellPrice, data.grade, 1, 9999);
                    CheckWeaponStatus();
                    break;
            }
        }


        public void SwitchWeapon()
        {
            if(HowManyWeapon() > 0)
            {
                Console.WriteLine("{0} 수납, {1} 장착", this.startWeapon[0].name, this.startWeapon[1].name);
                Weapon weapon = this.startWeapon[0];
                this.startWeapon[0] = this.startWeapon[1];
                this.startWeapon[1] = weapon;
                CheckWeaponStatus();
            } else
            {
                Console.WriteLine("교체할 무기가 없습니다.");
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace helloworldConsoleApp1
{
    class Adventurer
    {
        public int id;
        public string name;
        public float max_hp;
        public float hp;
        public int max_stamina;
        public int stamina;
        public int max_mana;
        public int mana;
        public int level;
        public int str;
        public int agi;
        public int inte;
        public int gold;

        public Adventurer(int id, string name)
        {
            this.id = id;
            this.name = name;
        }

        public void Init()
        {
            this.max_hp = DataMgr.GetInstance().GetCharacterData(this.id).max_hp;
            this.hp = this.max_hp;
            this.max_stamina = DataMgr.GetInstance().GetCharacterData(this.id).max_stamina;
            this.stamina = this.max_stamina;
            this.max_mana = DataMgr.GetInstance().GetCharacterData(this.id).max_mana;
            this.mana = this.max_mana;
            this.level = 1;
            this.str = 0;
            this.agi = 0;
            this.inte = 0;
            this.gold = 0;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace helloworldConsoleApp1
{
    class Enemy
    {
        DataMgr mgr = DataMgr.GetInstance();

        public int id;
        public string name;
        public float damage;
        public float hp;
        public int grade;
        public int reward;

        public Enemy(int id)
        {
            this.id = id;
        }

        public void Init()
        {
            this.name = mgr.GetMonsterData(this.id).name;
            this.damage = mgr.GetMonsterData(this.id).damage;
            this.hp = mgr.GetMonsterData(this.id).max_hp;
            this.grade = mgr.GetMonsterData(this.id).grade;
            this.reward = mgr.GetMonsterData(this.id).reward;
        }

        public void DisplayEnemyStatus()
        {
            Console.WriteLine("[Enemy Status]\n{0}\nHealth : {1}\nDamage : {2}",
                this.name, this.hp, this.damage);
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace helloworldConsoleApp1
{
    class OpenField1
    {
        DataMgr mgr = DataMgr.GetInstance();

        public OpenField1()
        {
            mgr.gi.mapInfo.mapIndex = 2;
            int mapProcess = mgr.gi.mapInfo.mapProcessNum;
            Console.WriteLine("\n상태창 확인 : p\n무기 교체 : i\n");
            while(mapProcess < 10)
            {
                Console.WriteLine("{0}걸음 째...", (mapProcess + 1) * 300);
                string str = Console.ReadLine();
                if(str == "i")
                {
                    mgr.gi.SwitchWeapon();
                } else if(str == "p")
                {
                    mgr.gi.WeaponBreak();
                    mgr.gi.CheckMyStatus();
                    mgr.gi.CheckWeaponStatus();
                }
                mgr.gi.mapInfo.mapProcessNum = mapProcess;
                if(mapProcess == 0)
                {
                    Console.WriteLine("\n사람 키만한 풀숲이 우거진 수풀지대에 도착했다.");
                }
                else if (mapProcess == 3)
                {
                    Console.WriteLine("<고블린 출몰 지역>");
                } else if(mapProcess == 6)
                {
                    Console.WriteLine("고블린이 모습을 드러냈다.");
                    Enemy goblin = new Enemy(1);
                    goblin.Init();
                    goblin.DisplayEnemyStatus();
                    Console.WriteLine("[전투 시작]");
                    Console.WriteLine("뭘 할까?\n0 -> 공격\n1 -> 도망\n2 -> 저장");
                    string choice = Console.ReadLine();
                    int choice2;
                    bool b = Int32.TryParse(choice, out choice2);
                    switch (choice2)
                    {
                        case 0:
                            int count = 0;
                            while (true)
                            {
                                if (mgr.gi.me.hp > 0)
                                {
                                    goblin.hp -= mgr.gi.startWeapon[0].damage;
                                    mgr.gi.startWeapon[0].durability--;
                                    count++;
                                    Console.WriteLine("{0}가 {5}{1} {2}의 피해를 입혔습니다.\n{3}의 남은 체력 {4}", mgr.gi.me.name,
                                        mgr.GetCharacterData(mgr.gi.me.id).default_attack_action_text, mgr.gi.startWeapon[0].damage,
                                        goblin.name, goblin.hp, mgr.gi.startWeapon[0].name);
                                    Console.WriteLine("{0} 남은 내구도 : {1}", mgr.gi.startWeapon[0].name, mgr.gi.startWeapon[0].durability);
                                    if(mgr.gi.startWeapon[0].durability <= 0)
                                    {
                                        mgr.gi.WeaponBreak();
                                    }
                                }
                                else
                                {
                                    Console.WriteLine("\n혀에서 묽고 비린 피맛이 느껴진다. 입에서 막을 새도 없이 피가 뿜어져 나온다....\n치명상인 듯 하다.\n시야가 좁아진다..\n" +
                                        ".......................\n...............\n..........\n.\n              YOU DIED");
                                    File.Delete("game_info.json");
                                    mgr.dead = true;
                                    break;
                                }

                                if (goblin.hp > 0)
                                {
                                    Console.ReadLine();
                                    mgr.gi.me.hp -= goblin.damage;
                                    count++;
                                    Console.WriteLine("{0}이 얍삽한 몸놀림과 함께 뭉툭한 둔기로 옆구리를 가격한다.\n나의 남은 체력 {1} / {2}",
                                        goblin.name, mgr.gi.me.hp, mgr.gi.me.max_hp);
                                }
                                else
                                {
                                    Console.WriteLine("{0}이 쓰러졌다.", goblin.name);
                                }

                                if (mgr.gi.me.hp > 0 && goblin.hp <= 0)
                                {
                                    Console.WriteLine("{0}합 만에 승부가 났다...", count);
                                    mgr.gi.me.gold += goblin.reward;
                                    Console.ReadLine();
                                    Console.WriteLine("\n[전리품]\n+{0} Gold", goblin.reward);
                                    Console.ReadLine();
                                    break;
                                }
                                Console.ReadLine();
                            }
                            break;
                        case 1:
                            Console.WriteLine("무사히 도망치는 데 성공했다!");
                            Console.ReadLine();
                            break;
                        case 2:
                            mgr.SaveData();
                            Console.WriteLine("<저장 완료>");
                            Console.ReadLine();
                            mapProcess--;
                            break;
                    }
                }
                if (mgr.dead)
                {
                    break;
                }
                mapProcess++;
                mgr.SaveData();
            }
            if (!mgr.dead)
            {
                mgr.gi.mapInfo.mapProcessNum = 0;
                mgr.gi.mapInfo.mapIndex = 1;
                Console.WriteLine("살아서 수풀지대를 빠져나왔다!");
                Console.WriteLine("\n게임을 계속하시겠습니까? y/n");
                string tof = Console.ReadLine();
                if (tof == "y")
                {
                    Console.WriteLine("게임을 진행합니다.");
                    mgr.TurnOn = true;
                }
                else if (tof == "n")
                {
                    Console.WriteLine("게임을 중단합니다.");
                    mgr.TurnOn = false;
                }
            }
        }
    }
}

언젠가 코드를 청소한다면 일단 지저분하게 산재한 코드를

기능에 따라 함수화시켜야 할 것이다...