1. App.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Study09
{
    public class App
    {
        // 생성자
        public App()
        {
            Game game = new Game();
            game.Start();
        }
    }
}

2. Game.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json;


namespace Study09
{
    public class Game
    {
        private Character character;

        // 생성자
        public Game()
        {
            this.LoadDatas();
        }

        public void Start()
        {
            if (this.IsNewbie())
            {
                Console.WriteLine("<메이플 스토리>");
                Console.WriteLine("신규 유저입니다.");
                Console.Write("캐릭터 이름을 정하세요: ");
                string inputName = Console.ReadLine();
                Console.Write("직업을 선택하세요(0. 전사, 1. 마법사, 2. 도적): ");
                int job = Convert.ToInt32(Console.ReadLine());

                CharacterData data = DataManager.instance.GetLoadCharacterData(job);
                this.character = new Character(inputName, data);
            }
            else
            {
                Console.WriteLine("기존 유저입니다.");
                CharacterInfo info = this.LoadCharacterInfo();
                this.character = new Character(info);
                this.character.ShowStatus();
                this.character.Hit(2);
                this.character.ShowStatus();
                this.character.GetExp(100);
                this.character.ShowStatus();
            }

            // 이벤트 구독
            this.character.onUpdateStatus += (sender, args) =>
            {
                CharacterInfo info = args.Info;
                this.Save(info);
            };

            if (this.IsNewbie())
            {
                this.character.Hit(3);
                this.character.GetExp(10);
            }
        }

        // 데이터 정보를 저장할 json 파일 생성
        // 역직렬화: 객체 -> 문자열
        private CharacterInfo LoadCharacterInfo()
        {
            string json = File.ReadAllText("./character_info.json");
            return JsonConvert.DeserializeObject<CharacterInfo>(json);
        }

        private bool IsNewbie()
        {
            var exists = File.Exists("./character_info.json");
            return !exists;
        }

        private void LoadDatas()
        {
            DataManager.instance.LoadCharacterDatas();
            DataManager.instance.LoadExpDatas();
        }

        private void Save(CharacterInfo info)
        {
            Console.WriteLine("Save Game");
            // 저장될 때 현재 변화한 데이터가 담긴 info를 저장
            //Console.WriteLine(info);
            // 직렬화 사용 ( .json 파일에 담겨야하기 때문에)
            string json = JsonConvert.SerializeObject(info);
            File.WriteAllText("./character_info.json", json);
            Console.WriteLine("Save Complete");
        }
    }
}

3. DataManager.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json;
using System.Linq;

namespace Study09
{
    // 싱글톤 클래스: 생성자를 private로 사용
    // sealed: 다른 클래스에서 상속받지 못하게 함
    // DataManager 클래스: 데이터시트를 딕셔너리로 관리
    public sealed class DataManager
    {
        // readonly 키워드 사용하여 읽기 전용으로 필드 생성
        public static readonly DataManager instance = new DataManager();

        // 데이터를 읽어올 딕셔너리 생성
        private Dictionary<int, CharacterData> dicCharacters;
        private Dictionary<int, ExpData> dicExp;

        //생성자
        private DataManager()
        {

        }

        public void LoadCharacterDatas()
        {
            string json = File.ReadAllText("./character_data.json");
            var arr = JsonConvert.DeserializeObject<CharacterData[]>(json);
            // 배열 요소를 사전에 넣기
            this.dicCharacters = arr.ToDictionary(x => x.id);
            
        }

        public void LoadExpDatas()
        {
            string json = File.ReadAllText("./exp_data.json");
            var arr = JsonConvert.DeserializeObject<ExpData[]>(json);
            // 배열 요소를 사전에 넣기
            this.dicExp = arr.ToDictionary(x => x.id);
        }

        public CharacterData GetLoadCharacterData(int job)
        {
            CharacterData data = this.dicCharacters.Values.Where(x => x.job == job).First();
            return data;
        }

        public ExpData GetRequireExpData(int level)
        {
            ExpData data = this.dicExp.Values.Where(x => x.level == level).First();
            return data;
        }
    }
}

4. CharacterData.cs

*  데이터시트를 기반하여 제작, 변수 정의 후 수정X

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Study09
{
    // 바인딩 클래스
    public class CharacterData
    {
        public int id;
        public int job;
        public float max_hp;
        public float damage;
    }
}

5. CharacterInfo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Study09
{
    public class CharacterInfo
    {
        public string Name { get; set; }
        public int Id { get; set; }
        public int Level { get; set; }
        public float Hp { get; set; }
        public float MaxHp { get; set; }
        public float Damage { get; set; }
        public int CurrExp { get; set; }

        // 생성자
        public CharacterInfo()
        {

        }

        // 생성자
        public CharacterInfo(string name, int id, int level, float hp, float maxHp, float damage, int currExp)
        {
            Name = name;
            Id = id;
            Level = level;
            Hp = hp;
            MaxHp = maxHp;
            Damage = damage;
            CurrExp = currExp;
        }
    }
}

6. Character.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace Study09
{
    public class Character
    {
        public class GetExpEventArgs : EventArgs
        {
            public float per;
        }

        // 캐릭터 정보를 업데이트하는 이벤트 작성
        public class UpdateStatusEventArgs: EventArgs
        {
            public CharacterInfo Info { get; set; }
        }

        public event EventHandler<UpdateStatusEventArgs> onUpdateStatus;
        public event EventHandler<GetExpEventArgs> onGetExp;

        public enum eJob
        {
            Warrior,
            Wizard,
            Assassin
        }

        private eJob job;
        private int reqExp;

        private CharacterInfo info;

        public Character(CharacterInfo info)
        {
            this.info = info;
            // 저장된 레벨, 경험치 가져옴
            ExpData expData = DataManager.instance.GetRequireExpData(this.info.Level);
            this.reqExp = expData.require_exp;
        }

        // 생성자
        // 신규 유저
        public Character(string name, CharacterData data)
        {
            this.info = new CharacterInfo();
            this.info.Id = data.id;
            this.info.Name = name;
            this.job = (eJob)data.job;
            this.info.Level = 1;
            this.info.MaxHp = data.max_hp;
            this.info.Hp = this.info.MaxHp;
            this.info.Damage = data.damage;
            this.info.CurrExp = 0;
            ExpData expData = DataManager.instance.GetRequireExpData(this.info.Level);
            this.reqExp = expData.require_exp;
        }

        public void Hit(int damage)
        {
            this.info.Hp -= damage;
            

            this.UpdateStatus();

            if (this.info.Hp <= 0)
                this.info.Hp = 0;

            if (this.info.Hp <= 0)
            {
                this.ShowDie();
                this.info.Hp = this.info.MaxHp;
                this.info.CurrExp -= this.reqExp / 10;
            }
        }

        public void UpdateStatus()
        {
            if (this.onUpdateStatus != null)
            {
                this.onUpdateStatus(this, new UpdateStatusEventArgs() { Info = this.info});
            }
        }

        public void ShowDie()
        {
            Console.WriteLine("***************************");
            Console.WriteLine("죽었습니다.");
            Console.WriteLine("마을에서 다시 태어났습니다.");
            Console.WriteLine("경험치를 -{0} 잃었습니다.", this.reqExp / 10);
            Console.WriteLine("***************************");
        }

        public void GetExp(int exp)
        {
            this.info.CurrExp += exp;
            if (this.info.CurrExp >= 100)
            {
                this.ShowLevelUp();
                this.LevelUp();
                //this.LevelUp();
            }
                

            this.UpdateStatus();
        }

        public void LevelUp()
        {
            this.info.Level++;
            this.info.Damage++;
            this.info.MaxHp = this.info.MaxHp + 10;
            this.info.Hp = this.info.MaxHp;
            int restExp = this.info.CurrExp - this.reqExp;
            this.info.CurrExp = restExp;
            ExpData expData = DataManager.instance.GetRequireExpData(this.info.Level);
            this.reqExp = expData.require_exp;
            this.UpdateStatus();
        }

        public void ShowLevelUp()
        {
            Console.WriteLine("***************************");
            Console.WriteLine("LEVEL UP !");
            Console.WriteLine("레벨: {0} -> {1}", this.info.Level, this.info.Level + 1);
            Console.WriteLine("체력: {0} -> {1}", this.info.MaxHp, this.info.MaxHp + 10);
            Console.WriteLine("공격력: {0} -> {1}", this.info.Damage, this.info.Damage + 1);
            Console.WriteLine("***************************");
        }

        public string GetStringJob()
        {
            switch (this.job)
            {
                case eJob.Warrior: return "전사";
                case eJob.Wizard: return "마법사";
                case eJob.Assassin: return "도적";
                default: return "";
            }
        }

        public void ShowStatus()
        {
            Console.WriteLine("--------------------");
            Console.WriteLine("이름: {0}", this.info.Name);
            Console.WriteLine("직업: {0}", this.GetStringJob());
            Console.WriteLine("체력: {0} / {1}", this.info.Hp, this.info.MaxHp);
            Console.WriteLine("공격력: {0}", this.info.Damage);
            Console.WriteLine("레벨: {0}", this.info.Level);
            Console.WriteLine("경험치: {0} / {1} ({2}%)", this.info.CurrExp, this.reqExp, (float)this.info.CurrExp / this.reqExp * 100f);
            Console.WriteLine("--------------------");
        }
    }
}

7. ExpData.cs

*  데이터시트를 기반하여 제작, 변수 정의 후 수정X

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Study09
{
    // 바인딩 클래스
    public class ExpData
    {
        public int id;
        public int level;
        public int require_exp;   // 레벨업 후 필요한 경험치
    }
}

8. ExpInfo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Study09
{
    public class ExpInfo
    {
        public int level;
        public float reqExp;

        // 생성자
        public ExpInfo(int level, float reqExp)
        {
            this.level = level;
            this.reqExp = reqExp;
        }
    }
}

9. Exp.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Study09
{
    public class Exp
    {
        private int id;
        private int level;
        private float requireExp;

        private ExpInfo info;

        // 생성자
        public Exp(ExpInfo info)
        {
            this.info = info;
        }
    }
}

 

'C# > 수업 내용' 카테고리의 다른 글

[Unity2D] Swipe 이용하여 표창 날리기  (0) 2022.07.07
[C#] 알고리즘 문제  (0) 2022.07.06
Json 연습 - 같은 아이템의 개수(amount) 증가  (0) 2022.06.20
대리자 연습  (0) 2022.06.16
2차원 배열 맵타일  (0) 2022.06.15

+ Recent posts