내일배움캠프/프로젝트

개인프로젝트 - 텍스트RPG : 던전기능 구현

서보훈 2024. 9. 24. 14:33

플레이어의 능력치에 따라 체력을 잃고 골드를 획득하는 던전 기능을 구현하였습니다.

해당 기능을 구현하면서 체력을 모두 잃으면 게임이 종료되도록 만들어주었습니다.

 


변경점 - 게임 진행 판정

//본 게임
while (playerChar.IsAlive)
{
    TextCreater("마을에 오신것을 환영합니다.\n어떤 행동을 할지 선택해주세요.\n\n");
    TextCreater("1.상태창\n2.인벤토리\n3.상점\n4.던전입장\n5.휴식하기\n\n");

    TextCreater("행동 입력");
    input = InputInt(Console.ReadLine());
}

게임의 순환을 당담하는 while문의 조건이 playerChar의 IsAlive 프로퍼티로 변경되었습니다.

 

이에따라 해당 프로퍼티와 관련된 내용이 Character 클래스에 추가되었습니다.

public bool IsAlive { get; private set; }

//생성자, 게임 시작시 이름과 직업을 고르고 그에 맞게 캐릭터 생성
public Character()
{
    UserName = "User";
    KorJobName = string.Empty;

    Level = 1;
    PlayerGold = 100;
    Exp = 0;
    IsAlive = true;
}

//체력 잃음, 사망판정
public void LoseHealth(float health)
{
    HealthPoint -= health;
    if(HealthPoint <= 0)
    {
        HealthPoint = 0;
        IsAlive = false;
    }
}

클래스의 객체가 생성될때 프로퍼티에 true 가 저장되며 체력을 잃을때 체력이 0 이하가되면 해당 프로퍼티가 false로 변경되도록 만들어주었습니다.

 


Dungeon 클래스와 DungeonDatabase 클래스

던전 입장시 성공, 실패 판정과 보상을 당담할 던전 클래스와 이 클래스를 관리할 던전 데이터베이스 클래스를 추가하였습니다.

 

던전 데이터베이스 클래스는 아이템 데이터베이스 클래스와 같은 동작을 하며, 던전을 생성하고 접을을 관리하는 역할을 합니다.

internal class DungeonDatabase
{
    private List<Dungeon> dungeons = new List<Dungeon>();
    public List<Dungeon> Dungeons { get { return dungeons; } }

    public DungeonDatabase()
    {
        dungeons.Add(new Dungeon("초급 던전", 5, 10, 1000));
        dungeons.Add(new Dungeon("중급 던전", 13, 25, 1700));
        dungeons.Add(new Dungeon("상급 던전", 21, 32, 2500));
    }
}

 

던전 클래스 입니다.

더보기

 

internal class DungeonDatabase
{
    private List<Dungeon> dungeons = new List<Dungeon>();
    public List<Dungeon> Dungeons { get { return dungeons; } }

    public DungeonDatabase()
    {
        dungeons.Add(new Dungeon("초급 던전", 5, 10, 1000));
        dungeons.Add(new Dungeon("중급 던전", 13, 25, 1700));
        dungeons.Add(new Dungeon("상급 던전", 21, 32, 2500));
    }
}

internal class Dungeon
{
    public string DungeonName { get; private set; }
    public int RequireDef { get; private set; }
    public int AddtinalRewardAtk { get; private set; }
    private int rewardGold;

    public Dungeon(string name, int requiredDef, int requiredAttack, int _rewardGold)
    {
        DungeonName = name;
        RequireDef = requiredDef;
        AddtinalRewardAtk = requiredAttack;
        rewardGold = _rewardGold;
    }

    //던전 플레이 함수
    public bool PlayDungeon(float playerDef, float playerAtk, out int reward, out int usedHp)
    {
        //체력 소모
        Random rand = new Random();
        //20 ~ 35 사이의 체력 피해 지정
        int lostHp = rand.Next(20, 36);

        //방어력 계산, 성공 실패와 체력소모 기준
        float defCalc = RequireDef - playerDef;

        //최소 10의 체력 소모
        lostHp = (lostHp + RequireDef < 10) ? 10 : lostHp + RequireDef;
        //out에 입력
        usedHp = lostHp;

        //성공판정
        bool isSucces;
        if(defCalc > 0)
        {
            //0 ~ 9 까지 무작위 숫자 생성
            int randInt = rand.Next(0, 10);
            //생성된 숫자가 3보다 작으면 성공(40%)
            if(randInt <= 3)
            {
                isSucces = true;
            }
            else
            {
                isSucces= false;
            }
        }
        else
        {
            isSucces = true;
        }

        //보상 계산
        if(isSucces)
        {
            //추가보상을 받기위한 최소 공격력 계산
            int atkCalc = (int)(playerAtk - AddtinalRewardAtk);
            //추가 보상 계산, 최소 공격력을 넘으면 넘은수치 ~ 넘은수치 * 2 % 만큼의 추가보상 획득
            int additinalReward = (int)(rewardGold * (1 + (rand.Next(atkCalc, atkCalc * 2 + 1) / 100f)));
            reward = (atkCalc <= 0) ? rewardGold : rewardGold * additinalReward;
            return true;
        }
        else
        {
            //보상을 주지 않음
            reward = 0;
            return false;
        }
    }

    public string DungeonInfoText()
    {
        string info;
        info = DungeonName.PadRight(8 , ' ');
        info = info + " | " + "방어력 " + RequireDef + " 이상 권장";

        return info;
    }
}

던전의 이름과 요구방어력 수치, 추가보상 요구 수치, 보상 을 필드로 가지고있으며 이 내용을 생성자를 통해 저장하게 됩니다.

 

PlayDungeon() 함수를 통해 성공과 실패 여부를 반환하고, 추가적으로 out 보상과 소모된 체력 수치를 넘겨줍니다.

 

체력 소모를 결정하는 코드입니다.

//체력 소모
Random rand = new Random();
//20 ~ 35 사이의 체력 피해 지정
int lostHp = rand.Next(20, 36);

//방어력 계산, 성공 실패와 체력소모 기준
float defCalc = RequireDef - playerDef;

//최소 10의 체력 소모
lostHp = (lostHp + RequireDef < 10) ? 10 : lostHp + RequireDef;
//out에 입력
usedHp = lostHp;

최소 10의 체력을 소모하도록 구성하였으며, 요구치에 비해 방어력이 낮을경우 그 값만큼 추가적인 체력을 소모하도록 구현하였습니다.

 

공략 성공여부를 당담하는 코드입니다.

//성공판정
bool isSucces;
if(defCalc > 0)
{
    //0 ~ 9 까지 무작위 숫자 생성
    int randInt = rand.Next(0, 10);
    //생성된 숫자가 3보다 작으면 성공(40%)
    if(randInt <= 3)
    {
        isSucces = true;
    }
    else
    {
        isSucces= false;
    }
}
else
{
    isSucces = true;
}

방어력이 부족할경우 0 ~ 9 까지의 숫자를 생성한 뒤, 3이하의 숫자가 나오면 던전 공략에 성공하도록 만들어주었습니다.

방어력이 충분할경우 100%확률로 공략을 성공합니다.

 

보상을 계산하는 코드입니다.

//보상 계산
if(isSucces)
{
    //추가보상을 받기위한 최소 공격력 계산
    int atkCalc = (int)(playerAtk - AddtinalRewardAtk);
    //추가 보상 계산, 최소 공격력을 넘으면 넘은수치 ~ 넘은수치 * 2 % 만큼의 추가보상 획득
    int additinalReward = (int)(rewardGold * (1 + (rand.Next(atkCalc, atkCalc * 2 + 1) / 100f)));
    reward = (atkCalc <= 0) ? rewardGold : rewardGold * additinalReward;
    return true;
}
else
{
    //보상을 주지 않음
    reward = 0;
    return false;
}

여기에서 성공,실패값을 반환하게되며 공략에 실패할경우 보상이 주어지지 않기 때문에 out reward 에 0을 반환하게됩니다.

 

공략에 성공할경우 추가보상에 필요한 최소 공격력을 계산하며 최소공격력이 넘을경우 골드를 추가 지급하고, 넘지 못했을경우 기본보상만이 주어집니다.

 

 

DungeonInfoText() 함수는 아이템에 존재하는 함수처럼 자신의 던전 정보를 반환하여 콘솔에 던전 리스트를 출력하는것을 당담합니다.


메인함수 - 던전 구현

메인함수에 던전을 구현한 내용입니다.

4번을 선택하면 던전을 선택하는 콘솔을 출력합니다.

case 4:
    {
        DungeonSelecter();
        
        break;
    }

반복문을 사용하지 않았는데, DungeonSelecter() 에서 던전 플레이 선택시 결과를 출력하는 함수로 연결되며, 이 함수에서 다시 DungeonSelecter() 를 호출하는 방식으로 반복을 구현하였기 때문에 여기선 반복문을 사용하지 않았습니다.

 

DungeonSelelcter() 함수입니다.

//던전 함수
public static void DungeonSelecter()
{
    Console.Clear();
    TextCreater("[던전 입구]");
    TextCreater("입장할 던전을 선택할 수 있습니다.");
    Console.WriteLine();

    int doungeonCount = dungeonDb.Dungeons.Count;
    for(int i = 0; i < dungeonDb.Dungeons.Count; i++)
    {
        string text = (i + 1) + ". " + dungeonDb.Dungeons[i].DungeonInfoText();
        TextCreater(text);
    }
    TextCreater("0. 나가기");
    Console.WriteLine();

    TextCreater("원하시는 행동을 입력해주세요.");
    int input = InputInt(Console.ReadLine());
    if(input >= 1 && input <= doungeonCount)
    {
        //던전 플레이
        PlayDungeon(input);
    }
    else
    {
        Console.Clear();
    }
}

콘솔에 던전 리스트를 띄우는 역할을 하며 추가 입력으로 던전 리스트의 번호를 입력하면 해당 던전을 플레이합니다.

리스트에 맞지 않는 입력을 할 경우 이 창에서 벗어나 다시 마을 선택지로 돌아갑니다.

 

던전을 플레이하는 함수입니다.

더보기
public static void PlayDungeon(int input)
{
    Console.Clear();
    int reward;
    int usedHp;
    bool isSucces = dungeonDb.Dungeons[input - 1].PlayDungeon(playerChar.DefencePoint, playerChar.AttackPoint, out reward, out usedHp);
    if(isSucces)
    {
        TextCreater("[공략 성공]");
        string outText = dungeonDb.Dungeons[input - 1].DungeonName +"을 클리어 하였습니다.";
        TextCreater(outText);
        Console.WriteLine();

        TextCreater("[탐험 결과]");
        string resultText = "체력 " + playerChar.HealthPoint + " -> " + (playerChar.HealthPoint - usedHp);
        TextCreater(resultText);
        resultText = "Gold " + playerChar.PlayerGold + " G -> " + (playerChar.PlayerGold + reward) + " G";
        TextCreater(resultText);
    }
    else
    {
        TextCreater("[공략 실패]");
        string outText = dungeonDb.Dungeons[input - 1].DungeonName + "공략에 실패하였습니다.";
        TextCreater(outText);
        Console.WriteLine();

        TextCreater("[탐험 결과]");
        string resultText = "체력 " + playerChar.HealthPoint + " -> " + (playerChar.HealthPoint - usedHp);
        TextCreater(resultText);
    }

    Console.ReadLine();

    playerChar.GetGold(reward);
    playerChar.LoseHealth(usedHp);
    if(playerChar.IsAlive)
    {
        DungeonSelecter();
    }
    else
    {
        GameOver();
    }
}

클리어 보상과 소모된 체력량을 받아줄 변수를 선언한 뒤, 선택한 던전의 PlayDungeon() 함수를 불러와 캐릭터의 공격력, 방어력을 매개변수로 넣어 성공 실패 판정을 반환 받아줍니다.

int reward;
int usedHp;
bool isSucces = dungeonDb.Dungeons[input - 1].PlayDungeon(playerChar.DefencePoint, playerChar.AttackPoint, out reward, out usedHp);

 

공략에 성공할경우의 행동입니다.

if(isSucces)
{
    TextCreater("[공략 성공]");
    string outText = dungeonDb.Dungeons[input - 1].DungeonName +"을 클리어 하였습니다.";
    TextCreater(outText);
    Console.WriteLine();

    TextCreater("[탐험 결과]");
    string resultText = "체력 " + playerChar.HealthPoint + " -> " + (playerChar.HealthPoint - usedHp);
    TextCreater(resultText);
    resultText = "Gold " + playerChar.PlayerGold + " G -> " + (playerChar.PlayerGold + reward) + " G";
    TextCreater(resultText);
}

사용된 체력과 획득한 보상을 텍스트로 출력해줍니다.

 

공략에 실패한경우입니다.

else
{
    TextCreater("[공략 실패]");
    string outText = dungeonDb.Dungeons[input - 1].DungeonName + "공략에 실패하였습니다.";
    TextCreater(outText);
    Console.WriteLine();

    TextCreater("[탐험 결과]");
    string resultText = "체력 " + playerChar.HealthPoint + " -> " + (playerChar.HealthPoint - usedHp);
    TextCreater(resultText);
}

텍스트의 내용이 일부 달라지며, 잃은 체력만을 출력합니다.

 

텍스트를 발생시킨 후, 어떤 입력이든 받으면 다음 화면으로 넘어갈 준비를 합니다.

또한 이때 탐색 결과로 얻은 보상과 잃은 체력을 캐릭터 객체에 적용합니다.

Console.ReadLine();

playerChar.GetGold(reward);
playerChar.LoseHealth(usedHp);
if(playerChar.IsAlive)
{
    DungeonSelecter();
}
else
{
    GameOver();
}

적용 후, 캐릭터가 생존했다면 다시 던전을 선택하도록 하고 아닐경우 게임오버 이벤트를 보여줍니다.

 

게임오버 연출은 다음과 같습니다.

//게임오버 연출
private static void GameOver()
{
    Console.Clear();
    Console.Write("게");
    Thread.Sleep(100);
    Console.Write(" 임");
    Thread.Sleep(100);
    Console.Write(" 오");
    Thread.Sleep(100);
    Console.Write(" 버");

    Thread.Sleep(100);
    Console.WriteLine();
    TextCreater("당신은 사망하였습니다...");
}

게임오버 연출 이후 while문의 조건을 축족하지 않기 때문에 게임이 종료되게 됩니다.