이번엔 전투의 일부를 구현하였다.
아래는 전투가 이루어지는 레벨의 코드 전체이다.
using System;
using System.Collections.Generic;
using System.Diagnostics.SymbolStore;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace C_Study
{
public class FightLevel : GameLevel
{
public override void Update()
{
Console.Clear();
if(SelectedMonster == null)
{
SelectMonster();
}
else
{
Fight();
}
}
public FightLevel(GameCore parrentCore)
{
_parentCore = parrentCore;
_playerLog = null;
_monsterLog = null;
}
public void Fight()
{
if(_selectedMonster == null)
{
return;
}
DevFunctions.WriteLineColored("플레이어 정보", ConsoleColor.Blue);
Console.WriteLine("HP : {0} / {1}", _parentCore.CurrentPlayer.CurrentHP, _parentCore.CurrentPlayer.MaxHP);
Console.WriteLine();
DevFunctions.WriteLineColored("몬스터 정보", ConsoleColor.Red);
Console.WriteLine("이름 : {0}", _selectedMonster.Name);
Console.WriteLine("HP : {0} / {1}", _selectedMonster.CurrentHP, _selectedMonster.MaxHP);
Console.WriteLine();
if (_selectedMonster.CurrentHP <= 0)
{
Win();
}
else if(_parentCore.CurrentPlayer.CurrentHP <= 0)
{
Lose();
}
else
{
WriteFightLog();
SelectBehavior();
MonsterBehavior();
}
}
private void Win()
{
Console.WriteLine("전투에서 승리하였습니다!");
_parentCore.CurrentPlayer.CurrentEXP += _selectedMonster.WinEXP;
_parentCore.CurrentPlayer.Money += _selectedMonster.WinMoney;
Console.WriteLine("아무 키나 입력시 메뉴 선택창으로 돌아갑니다.");
Console.Read();
_selectedMonster = null;
_monsterLog = null;
_playerLog = null;
_parentCore.CurrentLevel = LevelType.Menu;
}
private void Lose()
{
Console.WriteLine("전투에서 패배하였습니다..");
Console.WriteLine("아무 키나 입력시 메뉴 선택창으로 돌아갑니다.");
Console.Read();
_selectedMonster = null;
_monsterLog = null;
_playerLog = null;
_parentCore.CurrentPlayer.CurrentHP = 1;
_parentCore.CurrentLevel = LevelType.Menu;
}
private void WriteFightLog()
{
DevFunctions.WriteLineColored("나의 행동", ConsoleColor.Blue);
if(_playerLog != null)
{
Console.WriteLine("{0}", _playerLog);
Console.WriteLine();
}
DevFunctions.WriteLineColored("적의 행동", ConsoleColor.Red);
if(_monsterLog != null)
{
Console.WriteLine("{0}", _monsterLog);
}
Console.WriteLine();
}
private void SelectBehavior()
{
Console.WriteLine("1. 공격한다.\n2. 아이템을 사용한다.\n3. 도망친다.");
string input = Console.ReadLine();
if (DevFunctions.IsNumeric(input) == false)
{
return;
}
if (input.Length > 1)
{
return;
}
int toInt = int.Parse(input);
switch (toInt)
{
case 1:
PlayerAttack();
break;
}
}
private void PlayerAttack()
{
int Damage = GameFunctions.GetCalculatedDamage(_parentCore.CurrentPlayer, _selectedMonster);
bool isCritical = GameFunctions.isCritical(_parentCore.CurrentPlayer);
string CriticalMsg = "";
if(isCritical == true)
{
Damage = (int)(Damage * _parentCore.CurrentPlayer.CriticalPower);
CriticalMsg = "[크리티컬!] ";
}
_playerLog = "적에게 공격 : " + CriticalMsg + Damage.ToString() + "의 피해를 입혔습니다.";
_selectedMonster.CurrentHP -= Damage;
}
private void MonsterBehavior()
{
if(_selectedMonster.CurrentHP <= 0)
{
_monsterLog = "사망하였습니다.";
return;
}
int Damage = GameFunctions.GetCalculatedDamage(_selectedMonster, _parentCore.CurrentPlayer);
bool isCritical = GameFunctions.isCritical(_selectedMonster);
string CriticalMsg = "";
if (isCritical == true)
{
Damage = (int)(Damage * _selectedMonster.CriticalPower);
CriticalMsg = "[크리티컬!] ";
}
_monsterLog = "플레이어에게 공격 : " + CriticalMsg + Damage.ToString() + "의 피해를 입혔습니다.";
_parentCore.CurrentPlayer.CurrentHP -= Damage;
}
private void SelectMonster()
{
DevFunctions.WriteLineColored("전투하고 싶은 몬스터를 선택하세요.", ConsoleColor.DarkCyan);
Console.WriteLine();
Console.WriteLine("1. 고블린 (적정 레벨 : 1)");
Console.WriteLine("2. 오우거 (적정 레벨 : 5)");
Console.WriteLine("3. 드래곤 (적정 레벨 : 10)");
Console.WriteLine("4. 이전으로 돌아간다.");
string input = Console.ReadLine();
if (DevFunctions.IsNumeric(input) == false)
{
return;
}
if (input.Length > 1)
{
return;
}
int toInt = int.Parse(input);
switch (toInt)
{
case 1:
_selectedMonster = new Goblin();
break;
case 4:
_parentCore.CurrentLevel = LevelType.Menu;
_selectedMonster = null;
break;
}
}
public static Monster SelectedMonster
{
get { return _selectedMonster; }
set { _selectedMonster = value; }
}
private static Monster _selectedMonster;
private static string _playerLog;
private static string _monsterLog;
}
}
현재는 공격에 대한 기능만 구현이 되어있고, 아이템 사용은 아직 구현하지 않았다.
공격을 실시하면 몬스터의 HP가 깎이고 몬스터도 플레이어에게 즉시 공격을 실시한다.
몬스터의 HP가 0이 되면, Win함수가 호출되고 적의 HP가 0이되면 Lose함수가 호출된다.
Win함수가 호출되면, 플레이어는 경험치와 돈을 획득한다.
아래는 플레이어 경험치 변수의 set이 호출될 때 작업을 작성한 것이다.
여기서 레벨 업이 진행되도록 하였다.
public int CurrentEXP
{
get { return _currentEXP; }
set
{
_currentEXP = value;
if (_currentEXP >= _maxEXP)
{
LevelUp();
}
}
}
private void LevelUp()
{
_currentEXP -= _maxEXP;
Console.WriteLine("레벨이 상승하였습니다!");
MaxEXP = (int)(_maxEXP * 1.1f);
_level++;
_attPower += 10;
_defPower += 2;
}
레벨이 오르면, 경험치 수치가 조정되고 공격력과 방어력이 일정 수치만큼 오르도록 하였다.
최대 경험치 수치도 동시에 증가한다.
아래 코드는 데미지를 계산하는 것과 크리티컬 여부를 판단하는 함수이다.
public class GameFunctions
{
public static int GetCalculatedDamage(ICreatureStat attacking, ICreatureStat attacked)
{
Random random = new Random();
int MinAtt = (int)(attacking.AttPower * 0.9f);
int MaxAtt = (int)(attacking.AttPower * 1.1f);
int Att = random.Next(MinAtt, MaxAtt);
int Def = attacked.DefPower;
float DefRate = Def / 100.0f;
DefRate = 1.0f - DefRate;
return (int)(Att * DefRate);
}
public static bool isCritical(ICreatureStat attacking)
{
Random random = new Random();
int randomValue = random.Next(0, 100);
if (randomValue <= attacking.CriticalProb_100)
{
return true;
}
else
{
return false;
}
}
}
이 함수를 활용하여 최종 데미지를 산출하였다.
아래 동영상은 구현된 결과이다.
이렇게 공격을 주고받는 기능은 구현하였다.
다음 번엔 아이템을 사용하는 것과 무기의 특수효과를 적용할 예정이다.
그리고 추가적으로 인벤토리 아이템을 출력할 때, 아이템을 이름 순으로 정렬하도록 했는데 정렬 방법이 C++과 조금 달랐다. C++은 비교 연산자를 오버로딩하여 사용하지만 C#은 IComparable 인터페이스를 상속받은 뒤 CompareTo라는 함수를 구현해야 정렬이 가능했다.
int IComparable<Item>.CompareTo(Item other)
{
if(other.Name.CompareTo(Name) > 0)
{
return -1;
}
else
{
return 1;
}
}
그래서 Item 클래스에 요런 함수를 추가로 작성해주었다.
'프로젝트 > C# 머드게임' 카테고리의 다른 글
C# 머드 게임 프로젝트 (3) (0) | 2024.07.30 |
---|---|
C# 머드 게임 프로젝트 (2) - 구조 변경, 기능 추가 (0) | 2024.07.28 |
C# 머드 게임 프로젝트 (1) (0) | 2024.07.28 |