XR 플밍 - 4. 객체지향 프로그래밍과 데이터 구조 - (6) 콘솔 프로젝트 - Text RPG (4/1)

이형원·2025년 4월 1일
0

XR플밍

목록 보기
30/215
post-thumbnail

지금까지 들었던 수업을 바탕으로, 또 다시 콘솔 프로젝트를 만들어 보고자 한다.
이번에는 전에 제작했던 미로게임과 달리, 객체 지향 프로그래밍과 관련된 내용을 배웠기 때문에 객체 지향 프로그래밍을 반영한 상태로 게임을 만들 것이다.

1. 프로젝트를 시작할 때 제일 먼저 해야하는 것?

게임을 만들자, 라고 마음을 먹었으면 제일 먼저 해야 할 것이 무엇인가?
게임의 구상? 틀 잡기? 아니다

깃부터 만들어야 한다.

앞으로도 게임을 제작하는 과정에서 그 과정에 대한 백업을 하는 건 매우 중요한 요소이다.
그러니 깃을 활용하는 것은 절대로 까먹지 말도록 하자.

그래서 우선은 깃을 만들고 새 프로젝트를 만들었다. 게임을 구상하는 건 이 다음의 일이다.

2. 게임의 틀을 잡기

아래부터 서술할 게임 제작 과정에서 내용에 대한 부분은 최대한 생략하고, 틀을 만들고 구성하는 과정 위주로 작성할 예정이다.

우리가 만드는 것은 Text RPG이다. 게임의 큰 틀은 아래와 같이 시작할 것이다.

  1. 게임의 시작 ( Start )
  2. 게임의 진행 ( Run )
  3. 게임의 끝 ( End )

이와 같이 설정하고 우선 게임의 전반을 관리하는 Game 클래스를 만들자.

public static class Game
{
    // 게임에 필요한 정보들

    // 게임에 필요한 기능들
    // 게임 시작
    public static void Start()
    {

    }
	// 게임 종료
    public static void End()
    {

    }
	// 게임 진행
    public static void Run()
    {

    }
}

이렇게만 만들고 메인에는 아래와 같이 간단하게 표현할 수 있다.

internal class Program
{
    static void Main(string[] args)
    {
        Game.Start();
        Game.Run();
        Game.End();
    }
}

그 다음으로 게임이 진행되는 동안 어떻게 해야 할까? 만들었던 Run() 에 들어가야 할 내용을 생각해보자.

  1. 상황에 대한 출력이 필요하다. ( Render )
  2. 상황에 대해 플레이어의 선택지를 준다. ( Select Choice )
  3. 플레이어에게 입력을 받는다. ( Input )
  4. 결과를 출력한다. ( Result )
  5. 플레이어가 결과를 읽을 동안 시간을 줘야 하므로 기다리는 시간을 준다. ( Wait )
  6. 다음 상황으로 넘어간다. ( Next )

이와 같은 순서를 생각하고, 해당 과정을 구성하기 위한 클래스를 새로 만들겠다.
이를 Scene이라는 클래스로 만들었고, 추상클래스 형태로 만들었다.

public abstract class Scene
{
    protected ConsoleKey input;
    
    public abstract void Render();
    public abstract void SelectChoice();
    
    // input의 경우에는 처음엔 추상함수로 작성했으나,
    // 모든 씬에서 입력이 동일하게 작용할 것 같아 부모클래스 내용으로 변경함
    public void Input()		
	{
    	input = Console.ReadKey(true).Key;
	}
    
    public abstract void Result();
    public abstract void Wait();
    public abstract void Next();
}

이런 식으로 전체적인 틀을 잡았으니, 이제 다음 단계는 Scene을 상속 받을 자식 씬을 만들 차례이다.

3. 씬을 만들고, 씬 전환하기

우선 Title Scene을 만들었다.

public class TitleScene : Scene
{
    public override void Render()
    {
        Console.WriteLine("***************************************");
        Console.WriteLine("*              레전드 RPG             *");
        Console.WriteLine("***************************************");
        Console.WriteLine();
    }

	// 타이틀 씬에서는 딱히 결과를 표시할 필요가 없어서 생략
    public override void Result() { }

    public override void SelectChoice()
    {
        Console.WriteLine("1. 게임 시작");
        Console.WriteLine("2. 불러오기(미구현)");
        Console.WriteLine("3. 게임 종료");
    }

	// 타이틀 씬에서는 기다려줄 시간을 줄 필요가 없어서 생략
    public override void Wait() { }

    public override void Next()
    {
        // TODO : 다음 씬으로 전환하기
    }
}

여기에서 유용한 기능을 하나 소개하려 하는데, Next 쪽에 넣은 주석으로 TODO 와 함께 적은 내용이다.

TODO를 키워드로 만든 주석은 아래와 같이 작업목록으로 모아볼 수 있다.

TODO 리스트 중에 하나를 골라서 더블클릭하면 바로 그 코드가 있는 줄까지 이동하니, 나중에 구현해야 할 내용을 이런 식으로 미리 기록하는 것이 좋아 보인다.

타이틀 씬을 만들었으니, 이제 이 타이틀 씬을 어떻게 불러올 지 생각해 봐야 한다. 다시 Game 클래스로 돌아가서, 아래와 같이 작성해주었다.

public static class Game
{
    // 게임에 필요한 정보들
    private static bool gameOver;

    // 씬 모음
    private static Dictionary<string, Scene> sceneDic;
    // 초기 씬
    private static Scene curScene;
    
    // 게임에 필요한 기능들
    public static void Start()
    {
        // 게임에 있는 모든 씬들을 보관하고 빠르게 찾아줄 용도로 쓸 자료구조
        sceneDic = new Dictionary<string, Scene>();
        sceneDic.Add("Title", new TitleScene());

        // 처음 시작할 씬을 선정
        curScene = sceneDic["Title"];
    }

    public static void End()
    {

    }

    public static void Run()
    {
        while (gameOver == false)
        {
            Console.Clear();

            curScene.Render();
            Console.WriteLine();
            curScene.SelectChoice();
            Console.WriteLine();
            curScene.Input();
            curScene.Result();
            Console.WriteLine();
            curScene.Wait();
            curScene.Next();
        }
    }

    public static void ChangeScene(string sceneName)
    {
        curScene = sceneDic[sceneName];
    }
}

앞으로 추가될 씬은 딕셔너리로 추가하고, 씬 전환을 위한 ChangeScene 함수를 추가하였다.

Start문에 딕셔너리를 추가하여 타이틀 씬을 추가한 후, 최초로 재생되는 씬을 타이틀 씬으로 설정했다.

이제 이 다음으로 나올 씬을 만들 차례이다.

class TownScene : Scene
{   
    public override void Render()
    {
        초기 출력 내용;
    }

    public override void SelectChoice()
    {
        선택지1 - 상점에 간다;
        선택지2 - 수상한 사람을 쫓는다;
        선택지3 - 필드로 나간다;
    }

    public override void Result()
    {
        switch(input)
        {
            case ConsoleKey.D1:
                선택지1 내용 - 상점으로 향한다;
                break;
            case ConsoleKey.D2:
                선택지2 내용 - 수상한 사람에게 죽임을 당했다;
                break;
            case ConsoleKey.D3:
                선택지3 내용 - 필드로 나간다;
                break;
            default:
                Console.WriteLine("잘못 입력 하셨습니다. 다시 입력해주세요.");
                break;
        }
    }

    public override void Wait()
    {
        Util.Print("계속하려면 아무키나 눌러주세요...", ConsoleColor.White, 1000);
        Console.ReadKey();
    }
    public override void Next()
    {
        switch (input)
        {
            case ConsoleKey.D1:
                상점으로 씬 전환;
                break;
            case ConsoleKey.D2:
                선택지2에 따른 사망;
                break;
            case ConsoleKey.D2:
                필드로 씬 전환;
                break;
        }
    }
}

첫 씬인 마을 씬이다. 위의 코드 내용을 정리하자면 다음과 같다.

  1. Render로 마을에서 일어나는 상황을 서술한다.
  2. SelectChoice로 마을에서 할 행동을 선택지로 제시한다.
  3. Input은 씬에서 관리하고 있으므로, Input의 결과를 Result로 출력한다.
  4. 플레이어가 결과를 읽을 시간을 주어야 하므로 Wait로 입력을 기다린다.
  5. Next 선택지로 씬 전환, 사망 처리 등의 결과 처리를 한다.

이와 같이 작성했으니 Start에서 딕셔너리에 씬을 추가한 후, 타이틀 씬에서 맵을 연결해주면 된다.

public override void Next()
{
    switch(input)
    {
        case ConsoleKey.D1:
            Game.ChangeScene("Town");
            break;
    }
}

4. 게임오버 만들기

위의 마을 씬에서 선택지2를 눌러 수상한 사람을 쫓으면 죽게 만들어 놓았다. 그렇다면 이 게임오버는 어떻게 구현할까?

씬을 새로 만드는 대신 Game 클래스 내에 함수를 새로 만들었다.

public static void GameOver(string reason)
{
    Console.Clear();
    Console.WriteLine("***************************************");
    Console.WriteLine("*             You Died...             *");
    Console.WriteLine("***************************************");
    Console.WriteLine();
    Console.WriteLine(reason);

    gameOver = true;
}

게임 오버가 되면 게임이 종료해야 하므로, 게임을 계속 진행시키는 gameOver bool 값을 true로 바꿔준다. 또한 string 형태로 사망 이유까지 입력받아 출력할 수 있게 만들었다. 이걸 이제 마을의 Next에 연결시켜주면 된다.

switch (input)
{
    case ConsoleKey.D1:
        // 상점 씬 만들기
        break;
    case ConsoleKey.D2:
         Game.GameOver("수상한 사람은 함부로 쫓지 맙시다...");
        break;
}

앞으로 나올 사망 씬에 대한 사유도 이것을 이용해 출력되게 하면 된다.

5. 플레이어 만들기

지금까지 만든 부분은 겨우 게임의 첫 발을 내딛는, 씬을 전환하는 부분이었다. 그마저도 그저 스토리와 선택지밖에 출력하지 못하는, 아주 단순한 게임이 될 것이다.
우리가 만드는 Text RPG를 만들기 위해서는 플레이어라는 클래스가 하나 필요할 것이다.

플레이어 클래스는 플레이어의 능력치 및 행동을 담아야 한다. 플레이어에게 있는 능력치는 다양하게 있겠지만, 우선은 힘과 속도 능력치만을 넣어보겠다.

public class Player
{
    private int power;
    public int Power { get { return power; } set { power = value; } }

    private int speed;
    public int Speed { get { return speed; } set { speed = value; } }
}

플레이어의 힘과 속도 능력치는 외부에서 변경하지 못하게 Private로 설정하고, 대신 Getter & Setter를 통해 값을 가져 오고 변경하는 식으로 설계했다. 이렇게 만든 후 Player를 Game Class의 Start문에서 가져오면 된다.

...

// 플레이어
private static Player player;
// 플레이어 상태 가져오기
public static Player Player { get { return player; } }

// 게임에 필요한 기능들
public static void Start()
{
    // 게임에 있는 모든 씬들을 보관하고 빠르게 찾아줄 용도로 쓸 자료구조
    sceneDic = new Dictionary<string, Scene>();
    sceneDic.Add("Title", new TitleScene());
    sceneDic.Add("Town", new TownScene());

    // 처음 시작할 씬을 선정
    curScene = sceneDic["Title"];

	// 플레이어의 초기 스탯을 설정
    player = new Player();
    player.Power = 10;
    player.Speed = 8;
}
...

이와 같이 플레이어의 스텟이 생긴 것으로 인해, 게임에서 좀 더 다양한 장면을 만들 수 있게 되었다.

플레이어가 추가되었으므로, 마을 씬에서 수상한 사람에게 죽는 부분의 내용을 수정하였다.

public override void Result()
{
    switch(input)
    {
        ...
        
        case ConsoleKey.D2:
            Console.WriteLine(당신은 수상한 남성을 주시하고 있었습니다.");
            Console.WriteLine("수상한 남성이 당신의 눈빛을 눈치챘습니다.");
            Console.WriteLine("날카로운 단검을 당신에게 던졌고,");                    
            if (Game.Player.Speed >= 10)
            {
                Console.WriteLine("당신은 단검을 재빠르게 피했습니다.", ConsoleColor.Cyan, 1500);
                Console.WriteLine("수상한 남자는 당황하며 도망가기 시작합니다.");
                Console.WriteLine("당신은 수상한 남자를 추격합니다.");                        
            }
            else
            {
                Console.WriteLine("당신은 단검을 피하기에 충분히 빠르지 못했습니다.");
                Console.WriteLine("당신은 그것을 미처 피하지 못했습니다...");
            }
            break;
        ...

    }
}

속도가 10 이상일 경우, 플레이어는 죽지 않고 게임을 계속 진행할 수 있게 만들었다. 이제 플레이어의 능력치에 따라 죽을 수도, 죽지 않을 수도 있는 상황을 만들 수가 있게 되었다. 좀 더 다채롭고 흥미로운 게임을 만들 수 있게 될 것이다.

6. 간단한 UI와 유틸 만들기

6.1 플레이어의 스텟을 출력해보자.

플레이어의 스텟이 실시간으로 보이지 않으니 다소 게임을 진행할 때 불편하게 될 수도 있을 것 같다. Game 클래스에서 아래와 같은 함수를 만들었다.

public static void PrintInfo()
{
    Console.WriteLine("******************************");
    Console.WriteLine("          플레이어          ");
    Console.WriteLine($"   힘 : {player.Power}     속도 : {player.Speed}");
    Console.WriteLine("******************************");
    Console.WriteLine();
}

이와 같이 작성하고서 맨 위에 출력될 수 있도록 씬에서 Render 맨 위에 Game.PrintInfo(); 로 불러오자.

6.2 글씨의 출력 속도 및 색 조절

이렇게 게임을 만들었을 때, 텍스트가 한 번에 출력되는 부분이 게임적으로는 별로라는 느낌이 들었다. 한 번에 텍스트가 다 출력되니 긴장감이 떨어지는 것 같이도 보인다.

그래서 텍스트의 출력속도 및 색을 조절할 수 있는 유틸을 추가하였다.
Util 클래스를 만들어서 출력을 조절해보자.

public class Util
{
    public static void Print(string context, ConsoleColor textColor, int delay = 0)
    {
        Console.ForegroundColor = textColor;
        Console.WriteLine(context);
        Thread.Sleep(delay);
        Console.ResetColor();
    }
}

context에 대사를 넣고, textColor에 색깔을 넣어 조정할 수 있으며, delay에 넣은 속도에 따라 대사의 출력 속도가 달라진다. 이와 같이 텍스트의 출력 속도를 조절하면 아래와 같이 나온다.

7. 아이템, 인벤토리, 장비의 구현

앞서 6까지의 단계는 강의를 들으면서 만든 부분이고, 여기서부터는 순전히 내 부족한 실력으로 만든 구간이라 다소 번잡하고 정석적이지 않을 수 있다는 점 참고 바란다.

아이템과 인벤토리를 구현하려고 하는데 어떻게 구현해야 할까. 막상 시작해 보려 하니 막막했다.

우선 아이템은 상속을 해야 하니까 클래스로 만들어야 겠다. 여기서부터 시작해 보기로 했다.

public abstract class Item
{
    protected string name;
    protected int cost;

    public abstract string Name { get; }
    public abstract int Cost { get; }
}

당장에 어떻게 만들지 틀을 잡기가 어려워서 추상클래스로 만들어 보기로 했다.
이 게임에서 필요한 아이템이 뭐가 있을까. 장비 아이템과 소비 아이템을 기본으로 잡으면, 둘의 공통 요소는 이름과 가격이라고 생각했다. (일단은 상점에서 파는 걸로 만드는 아이템이라서)

또한 이름과 가격을 외부에서 변경할 수 없도록 하면서도, 자식클래스는 사용할 수 있게 Protected로 선언하고 Getter & Setter로 반환하게 했다. Get만 사용한 것은, 일단 게임 중에 Setter로 장비의 이름이나 가격을 변경할 것 같지 않을 것 같아서 생략했다.

이렇게 만들고 우선 당장 필요한 아이템 두 개 정도를 만들었다.

// 소비 아이템 : 포션
public class Potion : Item
{
    public Potion()
    {
        name = "포션";
        cost = 100;
    }
    public override string Name { get{ return name; } }
    public override int Cost { get { return cost; } }
}

public sealed class HPPotion : Potion
{
    public HPPotion()
    {
        name = "HP 포션";
        cost = 100;
    }
}


// 장비 아이템 : 신발
public enum Parts { Head, Body, Feet, Hand, SIZE }

public class Equipment : Item
{
    string[] parts = new string[(int)Parts.SIZE];
    public Equipment()
    {
        name = "장비";
        cost = 400;
    }

    public string this[Parts type]
    {
        get { return parts[(int)type]; }
        set { parts[(int)type] = value; }
    }
    public override string Name { get { return name; } }
    public override int Cost { get { return cost; } }
}

public class GaleShoes : Equipment
{
    public GaleShoes()
    {
        name = "질풍 신발";
        cost = 400;        
    }
}

일단 만들기는 만들었는데, 이제 이 아이템을 사용하는 것이 플레이어에게 영향을 주도록 만들어야 한다. 심지어 지금 플레이어는 HP 능력치도 안 만들어 놨는데 HP 포션부터 만들어놨다.
우선은 질풍 신발부터 이 작업을 시도해 보려 했고, 아래와 같이 생각을 했다.

  1. 장비는 플레이어의 능력치를 상승시켜주는 효과가 있다.
  2. 장비는 부위 당 하나씩 장착할 수 있으며 장비와 탈착이 가능하다.

이와 같은 부분을 반영하기 위해서 Equipment 슬롯을 Player 클레스에 만들어 주었다. 장비창은 플레이어에게 있는 게 맞다는 판단 때문이었다. (덤으로 인벤토리 슬롯도 만들어주었다.)

  • 플레이어 클래스에 선언 ( 인벤토리 6칸, 장비는 머리, 몸통, 신발, 손 4부위 장착부위 추가 )
 // 인벤토리
 public Item[] inventory = new Item[6];

 // 장비창
 public Equipment equipment = new Equipment();

이제 장비를 장착하면 스텟이 오르게 만들어야 할 것이다. 이걸 위해서 Equipment 자식 클래스에 따로 변수를 추가하였다.

public class Equipment : Item
{
...
    protected int PowerStatus;
    protected int SpeedStatus;

    public void Equip()
    {
        Game.Player.Power += PowerStatus;
        Game.Player.Speed += SpeedStatus;
    }
    public void Unequip()
    {
        Game.Player.Power -= PowerStatus;
        Game.Player.Speed -= SpeedStatus;
    }
}

public class GaleShoes : Equipment
{
    public GaleShoes()
    {
        name = "질풍 신발";
        cost = 400;
        PowerStatus = 0;
        SpeedStatus = 3;
    }
}

장비를 장착하고 탈착하는 건 플레이어에 구현해야 하는 기능이 아니라 장비에게 구현해야 하는 것이라 판단했다. 이와 같이 작성하고 질풍 신발을 신으면 속도가 3 올라가는 장비를 만들었다.
이제 상점에서 이 신발을 사면 장착을 하고, 스텟이 올라가도록 구현해야 한다.

사실 이 부분이 제일 어려웠다. 분명 Getter 로 변수를 들고 올 수 있게 설정해놨는데, 왜 자꾸 안 가져와지는 건지. 한참을 고민하고 씨름해본 끝에 문제가 뭔지 알 수 있었다.

지금까지 만든 아이템은 전부 클래스였다. 따라서 클래스가 존재해야지 해당 요소를 가져올 수 있다.

그래서 사실 이게 맞는지는 잘 모르겠긴 하지만... 아이템을 사는 상황에서 해당 아이템의 클래스를 불러와서 변수를 가져오기로 했다.

  • 상점에서 아이템을 살 때
switch (input)
{
	// 포션을 산다 선택지
    case ConsoleKey.D1:
    
    	// 아이템 클래스를 불러온다.        
        HPPotion hPPotion = new HPPotion();
        
        if ( // 소지금이 충분할 경우 )
        {
            for (int i = 0; i < Game.Player.inventory.Length; i++)
            {
                if (Game.Player.inventory[i] == null)
                {
                    Util.Print("당신은 상인에게 HP 포션을 구매했습니다.", ConsoleColor.White, 800);
                    Game.Player.inventory[i] = hPPotion;
                    // 소지금 차감 내용 추가 예정                    
                    break;
                }
                
                // 인벤토리가 꽉 찼을 시
                if(i == Game.Player.inventory.Length-1 && Game.Player.inventory[i] != null)
                {
                    Util.Print("인벤토리가 가득 찼습니다.", ConsoleColor.White, 800);
                    break;
                }
            }
        }
        else
        {
            Util.Print("당신에게 충분한 돈이 없습니다.", ConsoleColor.White, 800);
        }
        break;

	// 질풍 신발을 산다 선택지
    case ConsoleKey.D2:
    	
        // 아이템 클래스를 불러온다.
        GaleShoes galeShoes = new GaleShoes();
        
        // 아이템 중복 착용 방지
        if (Game.Player.equipment[Parts.Feet] == galeShoes.Name)
        {
            Util.Print("이미 착용하고 있는 장비입니다.", ConsoleColor.White, 1500);
        }
        
        else if ( // 소지금이 충분할 경우 )
        {
            Util.Print("질풍 신발을 구매합니다.", ConsoleColor.White, 800);
            Util.Print("착용하니 당신의 다리가 가벼워지는 것을 느낍니다.", ConsoleColor.White, 1200);
            Game.Player.equipment[Parts.Feet] = galeShoes.Name;
            galeShoes.Equip();
            // 소지금 차감 내용 추가 예정
            Util.Print($"플레이어의 스탯 상승! 속도 {Game.Player.Speed}", ConsoleColor.Cyan, 1200);
        }   
        else
        {
            Util.Print("당신에게 충분한 돈이 없습니다.", ConsoleColor.White, 800);
        }
        break;
...

이와 같이 작성을 하여 아이템으로 인한 스텟 증가, 인벤토리에 아이템을 넣는 과정도 구현하는데 성공했다.

8. 플레이어의 소지금

플레이어가 가지고 있는 돈은 플레이어 클래스에다 만들어야 할까? 아니면 다른 클래스에 만들어야 할까?

사실 이것 만으로도 한 20분 넘게 고민한 것 같기도 하다.

이전 수업에서 배운 내용에 따르면, 하나의 클래스에 너무 많은 책임을 넣지 않도록 해야 한다고 신신당부하셨는데, 그래서 계속 플레이어가 가진 소지금을 어디다 넣을 지 고민했다. 플레이어가 처음부터 끝까지 들고 있어야 하니까 Game 클래스의 Static 변수로 선언해야 할까?

결론만 말하자면, 나는 플레이어의 책임이라고 생각했다.

플레이어의 힘 능력치는 플레이어의 책임이다. 플레이어의 속도도 플레이어의 책임이다. 그러면 플레이어가 소지한 돈도 어떻게 보면 능력치? 능력을 표현할 수 있는 수단이 될 수 있지 않을까?

이렇게 생각한 게 정답일지는 모르지만, 우선 이 생각이 맞다는 전제 하에 플레이어 클래스에 소지금 관련 내용을 추가했다.

...

private int goldInHand;
public int GoldInHand { get { return goldInHand; } set { goldInHand = value; } }

// 아이템 살 때의 소지금 감소
public void Buy(Item item)
{
    goldInHand -= item.Cost;
}

// 이벤트 발생으로 인한 소지금 감소
public void decreaseGold(int gold)
{
    GoldInHand -= gold;
    if(GoldInHand < 0)
    {
        GoldInHand = 0;
    }
}

아이템이라는 부모 변수를 이용하여, 앞으로 어떤 아이템이 추가되든지 간에 금액을 플레이어 소지금에서 차감할 수 있도록 만들었다. 또한 이벤트로 인한 소지금 감소를 위한 함수도 만들어서 이후에 만들 상황에서 사용하기로 했다.

이러한 과정을 거쳐서 상점 씬이 완성되었다.

  • 상점 씬 구입 부분 완성본
...

switch (input)
{
    case ConsoleKey.D1:
        HPPotion hPPotion = new HPPotion();
        if (Game.Player.GoldInHand >= hPPotion.Cost)
        {
            for (int i = 0; i < Game.Player.inventory.Length; i++)
            {
                if (Game.Player.inventory[i] == null)
                {
                    Util.Print("당신은 상인에게 HP 포션을 구매했습니다.", ConsoleColor.White, 800);
                    Game.Player.inventory[i] = hPPotion;
                    Game.Player.Buy(hPPotion);
                    Util.Print($"소지 골드 : {Game.Player.GoldInHand} ", ConsoleColor.White, 1500);
                    break;
                }
                if(i == Game.Player.inventory.Length-1 && Game.Player.inventory[i] != null)
                {
                    Util.Print("인벤토리가 가득 찼습니다.", ConsoleColor.White, 800);
                    break;
                }
            }
        }
        else
        {
            Util.Print("당신에게 충분한 돈이 없습니다.", ConsoleColor.White, 800);
        }
        break;

    case ConsoleKey.D2:
        GaleShoes galeShoes = new GaleShoes();
        if (Game.Player.equipment[Parts.Feet] == galeShoes.Name)
        {
            Util.Print("이미 착용하고 있는 장비입니다.", ConsoleColor.White, 1500);
        }
        else if (Game.Player.GoldInHand >= galeShoes.Cost)
        {
            Util.Print("질풍 신발을 구매합니다.", ConsoleColor.White, 800);
            Util.Print("착용하니 당신의 다리가 가벼워지는 것을 느낍니다.", ConsoleColor.White, 1200);
            Game.Player.equipment[Parts.Feet] = galeShoes.Name;
            galeShoes.Equip();
            Game.Player.Buy(galeShoes);
            Util.Print($"플레이어의 스탯 상승! 속도 {Game.Player.Speed}", ConsoleColor.Cyan, 1200);
            Util.Print($"소지 골드 : {Game.Player.GoldInHand} ", ConsoleColor.White, 1500);
        }
        else
        {
            Util.Print("당신에게 충분한 돈이 없습니다.", ConsoleColor.White, 800);
        }
        break;
        
...

9. 아직은 미완성이지만 짧은 시연 자료


아직 많이 조잡한 게임이지만, 만들면서 상당히 배운 점이 많고 재미있었던 것 같다. 이 게임도 틈틈히 만들어서 최종 완성본을 만들어 보고 싶다.

profile
게임 만들러 코딩 공부중

0개의 댓글