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;
}
}
}