24.01.07 TIL - [C#] Text RPG 만들기 (3)

JJwoo·2024년 1월 7일

TEXT 게임 해설 요약


1. 설계

간단하게 도식화해서 화면 구성 정리

ex)
오프닝 화면 에서 그 다음 씬 생각

  1. 상태 확인
  2. 인벤토리 -> 장착 관리
  3. 상점 -> 구매 관리

2. 각 기능의 필수적인 공통점 생각하기

  • 각 페이지에서 0,1,2 등을 입력해서 input을 받는 과정이 공통적으로 들어가기 때문에 이 부분을 모듈화, 함수화 시킬 필요가 있겠다.

  • 인벤토리-장착관리에서 보여주는 아이템 목록을 보여주는 기능 같은 경우도 함수로 만들어서 편리하게 활용 할 수 있겠다.

3. 이번 과제의 활용 범위

  • 변수
  • 자료형
  • 조건문 - if
  • 반복문 - for , while
  • 배열과 컬렉션
  • 클래스
  • 메서드와 구조체

4. 설계 (2)

  • 구현하기 힘들어하는 초보 입장에서 진행

  • 샘플 코드 기반으로 시작

  • 하나의 Item을 각각의 개별 변수로 저장하는 것보다 클래스로 저장 -> 훨씬 편리, 실수를 방지


과정

다시 만들면서 최대한 코드를 해석하는 방식으로 작성
본인에게는 아직 복잡한 부분이 많아서 과정과 그 이유, 모르는 개념도 최대한 찾아서 다 주석으로 처리 함.
최종 완성 후 코드의 순서 정리 예정.. 쉽지 않다.


namespace TextRPG2
{

    //구성
    // 0. 데이터 초기화
    // 1. 스타팅 로고를 보여줌 (게임 처음 킬 때만)
    // 2. 선택 화면을 보여줌 (기본 구현사항 - 상태 / 인벤토리)
    // 3. 상태 화면을 구현함 ( 필요 구현 요소 : 캐릭터, 아이템)
    // 4. 인벤토리 화면 구현함
    // 4-1. 장비장착 화면 구현
    // 5. 선택화면 확장


    //  P.s ->  숫자. 은 코드 작업 순서를 표시 한 것.



    // 3. 플레이어를 생성하기 위해 클래스가 필요함, 캐릭터와 아이템 클래스를 구현할 예정
    public class Character // 3-1. 캐릭터 클래스 정의, 캐릭터의 구성도
    {
        public string Name { get; } // 한 번 정의되면 바꿀 수 없도록 함
        public string Job { get; } // Enum은 아직 배우지 않았으므로 pass
        public int Level { get; }
        public int Atk { get; }
        public int Def { get; }
        public int Hp { get; }
        public int Gold { get; }

        public Character(string name, string job, int level, int atk, int def, int hp, int gold)
        // 3-2. 캐릭터 클래스의 생성자, 기본적으로 클래스의 이름과 같은 함수, 캐릭터를 실제로 생성하는 과정 = 인스턴스를 만든다
        {
            Name = name;
            Job = job;
            Level = level;
            Atk = atk;
            Def = def;
            Hp = hp;
            Gold = gold;
            // 조금 이따가 GameDataSetting()에 new 캐릭터를 생성 할 때(인스턴스를 만들 때)
            // 클래스 - 생성자에서 설정한 기본 세팅 조건들이 자동으로 대입 됨.
        }
    }

    public class Item // 4. 아이템 클래스 정의
    {
        public string Name { get; }
        // get 접근자 : 속성 값을 읽는 데 사용, 클래스의 외부에서 속성의 값을 요청할 때 get 접근자의 코드가 실행
        // set 접근자 : 속성 값을 할당 하는데 사용, 클래스의 외부에서 속성에 특정 값을 할당. (현재는 사용 x)
        // get; 만 있다 = 읽기 전용, 객체가 생성될 때 설정 되고 이후에는 변경 할 수 없음. 
        // 둘 다 있다   = 읽기/쓰기 전용, 클래스 외부에서 값을 변경할 수 있음, 속성이 동적으로 변경될 필요가 있는 경우 사용.
        // ∴ 플레이어의 레벨이나 체력이 게임 도중 변경될 수 있다면(사냥을 한다거나) set 접근자가 필요할 수 있다.

        // public void LevelUp()   => 레벨업 메서드 예시 
        // {
        //     Level += 1;
        //     (기타 구현 코드 생략)
        // }     
        //   이런 경우 캐릭터 클래스의 public int Level {get;}의 get 옆에, set 도 추가해줘야 한다.

        public string Description { get; } // 템 설명

        public int Type { get; } // 무기 or 방어구 타입

        public int Atk { get; } // 

        public int Def { get; }

        public int Gold { get; }

        public bool IsEquipped { get; set; } // 4-1. 장착 유무, 장착이 실제로 되었는지 확인하기 위함

        public static int ItemCnt = 0;   // 5-2.  static int -> 클래스에 공유가 되는 int형 변수
        // 각각의 인스턴스가 아닌 아이템 클래스에 귀속 되어 게임에 전반적으로 공유 되는 변수, additem 함수에 활용 될 예정
        // 아이템이 만들어 질 때마다 변수를 1만큼 올리고 싶을 때, 일일히 인스턴스에서 만들기 보단 전체에 공유 되는 값을 위함.
        public Item(string name, string description, int type, int atk, int def, int gold, bool isEquipped = false)
        // 4-2. 아이템 클래스의 생성자, 장착 유무는 false로 설정(처음에 안 끼고 있으니)
        {
            Name = name;
            Description = description;
            Type = type;
            Atk = atk;
            Def = def;
            IsEquipped = isEquipped;
        }

        public void PrintItemStatDescription(bool withNumber = false, int idx = 0) 
            // 7-1. 아이템 설명 출력
        {
            Console.Write("- ");

            if (withNumber) // 7-4 아이템 장착관리 번호 컬러
            {
                Console.ForegroundColor = ConsoleColor.DarkMagenta;
                Console.Write("{0} ", idx);
                Console.ResetColor();
            }


            if (IsEquipped) // 아이템 착용 시
            {
                Console.Write("[");
                Console.ForegroundColor = ConsoleColor.Cyan; //   [ 의 뒤의 색 변경
                Console.Write("E"); // cyan 컬러
                Console.ResetColor(); // 색 리셋
                Console.Write("]");
                Console.Write(PadRightForMixedText(Name, 9)); // 장착 중인 경우는 9글자 출력
            }
            else
                Console.Write(PadRightForMixedText(Name, 12)); // 장착 중이 아닌 경우 12글자 출력
                Console.Write(" | ");
            
            // 수치가 0이 아니라면 작동,  [ 삼항 연산자 활용 => 조건 ? 조건이 참이라면 : 조것이 거짓이라면 ]
            if (Atk != 0) Console.Write($"Atk {(Atk >= 0 ? " + " : "")}{Atk}");  // 공격력이 0보다 크거나 같으면 "+" 를 붙이고 아니면 " "해라(붙이지 마라).
            if (Def != 0) Console.Write($"Def {(Def >= 0 ? " + " : "")}{Def}");

            Console.Write(" | ");
            Console.WriteLine(Description); // 설명 String 출력
        }

        public static int GetPrintableLength(string str) // 아이템 텍스트 정렬을 위해 Length의 길이를 구함
        {
            int length = 0;
            foreach (char c in str)
            {
                if (char.GetUnicodeCategory(c) == System.Globalization.UnicodeCategory.OtherLetter)
                {
                    length += 2; // 한글과 같은 넓은 문자는 길이를 2로 취급
                }
                else
                {
                    length += 1; // 나머지 문자는 길이를 1로 취급
                }
            }
            return length;
        }
        public static string PadRightForMixedText(string str, int totalLength)
        {
            int currentLength = GetPrintableLength(str); // 텍스트의 실제 길이
            int padding = totalLength - currentLength; //  총길이 - 실제길이 = int padding 추가해야 할 길이
            return str.PadRight(str.Length + padding); // padding 만큼 PadRight(문자열의 오른쪽)에 공백을 추가
        }


    }
    internal class Program
    {
        static Character _player; // 5. 실제 플레이에서 쓸 캐릭터와 아이템 추가,  class Program 내에서 플레이어 관련에 주구장창 사용 예정
        static Item[] _items;     // 아이템은 여러 개 이므로 배열[] 사용, class Program내에서 아이템 관련 사용 예정

        static void Main(string[] args) // 메인 함수
        {

            GameDataSetting(); // 1. 게임 데이터 세팅
                                                                           // new 라는 키워드를 통해 새로운 캐릭터를 메모리에 할당 지시, Character 생성자 발동

            PrintStartLogo(); // 5-4. 게임 스타트 화면 함수
             
            StartMenu(); // 5-5. 스타트 메뉴
        }
        private static void GameDataSetting() // 2. 게임 데이터 메서드 생성, Private(비공개)
        {
            _player = new Character("정진", "백수", 1, 10, 5, 100, 1500); // 5-1. new 플레이어 변수 선언(실제로 사용할 캐릭터의 데이터)
            // 아까 3-2 에서 만든 캐릭터 클래스 생성자의 세팅 값들을 받아 옴.
            // () 괄호 안에 각각 순서대로 Name, Job, Level, Atk, Def, HP, Gold 순서이며, 입력 값이 세팅 됨.
            // _ (언더스코어) 사용 이유? = Private(비공개) 필드 구분을 위한 것.
            // 클래스 내부에서만 사용되는 변수임을 쉽게 식별할 수 있고, 외부에서 접근되는 공개 속성이나 메서드와의 혼동을 방지.
            // 복습 : 클래스의 필드(field)란 클래스에 포함된 변수(Variable)를 말한다. ( 결국 같은 뜻? )
            // 변수에는 특정 값을 할당할 수 있고, 이를 통해 객체의 특성을 만들어줄 수 있다.

            _items = new Item[8]; // 이번에는 List 대신 배열을 사용, 추후 5-3. additem 메서드를 정의 할 예정, (위의 5-2 로 이동)

            // 5-4. 아이템 추가
            AddItem(new Item("무쇠 갑옷", "무쇠로 만들어진 튼튼한 갑옷입니다.", 0, 0, 5, 1000)); // 맨 앞의 숫자가 0이면 방어구, 1이면 무기
            AddItem(new Item("수련자 갑옷", "수련에 도움을 주는 갑옷입니다.", 0, 0, 9, 2000));
            AddItem(new Item("스파르타의 갑옷", "스파르타의 전사들이 사용했다는 전설의 갑옷입니다.", 0, 0, 15, 3500));
            AddItem(new Item("전신 방탄복", "총탄 및 파편 등으로부터 보호하기 위해 특수제작된 보호구", 0, 0, 30, 5500)); // 추가 아이템 1
            AddItem(new Item("낡은 검", "쉽게 볼 수 있는 낡은 검입니다.", 1, 2, 0, 600));
            AddItem(new Item("청동 도끼", "쉽게 볼 수 있는 낡은 검입니다.", 1, 5, 0, 1500));
            AddItem(new Item("스파르타의 창", "스파르타의 전사들이 사용했다는 전설의 창입니다.", 1, 7, 0, 3000));
            AddItem(new Item("AK - 47", "왜 갑자기 총기가 튀어나왔는지는 모르겠지만, 너도 나도 사이 좋게 한 방입니다.", 1, 15, 0, 6000)); // 추가 아이템 2
        }

        static void StartMenu() // 5-5. 스타트 메뉴
        {
            Console.Clear(); // 게임 스타트 화면 정리
            Console.WriteLine("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■");
            Console.WriteLine("스파르타 마을에 오신 여러분 환영합니다.");
            Console.WriteLine("이곳에서 던전으로 들어가기전 활동을 할 수 있습니다.");
            Console.WriteLine("■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■");
            Console.WriteLine();  // Console.WriteLine(); 단축키 -> C + W + Tab
            Console.WriteLine("");
            Console.WriteLine("1. 상태 보기");
            Console.WriteLine("2. 인벤토리");
            Console.WriteLine("3. 상점");
            Console.WriteLine("4. 던전 입장");
            Console.WriteLine("5. 휴식");
            Console.WriteLine("6. 게임 저장 및 불러오기");
            Console.WriteLine("7. 게임 종료");
            Console.WriteLine("");


            // int keyInput = int.TryParse(Console.ReadLine(), out keyInput);  는 안 쓰고 아래 따로 함수 생성
            // CheckValidInput(1, 7);   // 5-6.  1에서 7까지 유효성 확인, 일단 관련 함수들을 만들고 switch 문의 매개변수로 사용될 예정
            
            switch (CheckValidInput(1, 7)) 
            // 5-8. switch문, CheckValidInput함수로 유효 값(1~7)을 입력 받으면 그에 맞는 함수 호출 후 break;로 벗어남.

            {
                case 1:
                    StatusMenu(); // 플레이어 상태
                    break;
                case 2:
                    InventoryMenu(); // 인벤토리
                    break;
                case 3:
                    //StoreMenu(); // 상점
                    break;
                case 4:
                    //DungeonMenu(); // 던전 입장
                    break;
                case 5:
                    //RestMenu(); // 휴식
                    break;
                case 6:
                    //SaveGameMenu(); // 게임 저장 및 불러오기
                    break;
                case 7:
                    //GameOverMenu(); // 게임 종료
                    break;
            }
        }

        private static void StatusMenu() // 6. 플레이어 상태
        {
            // 6-3. 상태창 꾸미기 작업 시작
            Console.Clear(); 
            ShowHighlightText("■ 상태 보기 ■"); // 제목에 첫 줄 색 변경 6-2 함수 활용
            Console.WriteLine("캐릭터의 정보가 표기됩니다.");

            PrintTextWithHighlights("Lv ", _player.Level.ToString("00")); // 문자열 하이라이트 6-2 함수 활용, "00" 은 01,02,03 이런 식으로 두 자릿수로 표현
            Console.WriteLine("");
            Console.WriteLine("{0} ({1})", _player.Name, _player.Job);

            // 7-8. 합산 공격력, 방어력 구현 추가
            int bonusAtk = getSumBonusAtk(); // 밑에 넣어줄 예정
            int bonusDef = getSumBonusDef();
            PrintTextWithHighlights("공격력 : ", (_player.Atk + bonusAtk).ToString(), bonusAtk > 0 ? string.Format(" (+{0})", bonusAtk) : "");
            // 플레이어 공격력 + 보너스 공격력을 문자열로, (삼항연산자) 보너스 공격력이 0보다 크면 +(보너스 어택)을 출력해주고, 아니면은 빈칸을 추가
            PrintTextWithHighlights("방어력 : ", (_player.Def + bonusDef).ToString(), bonusDef > 0 ? string.Format(" (+{0})", bonusDef) : "");
            
            // 각각 PrintTextWithHighlights 함수의 s1 , s2, s3인데 Atk(공격력) 의 자료형은 Int이므로 s2의 노란색 컬러를 적용 시키기 위해 Tostring 해줌
            PrintTextWithHighlights("체력 : ", _player.Hp.ToString());
            PrintTextWithHighlights("골드 : ", _player.Gold.ToString());
            Console.WriteLine("");
            Console.WriteLine("0. 뒤로가기");
            Console.WriteLine("");

            switch (CheckValidInput(0, 0)) // 0번 나가기
            {
                case 0:
                    StartMenu();
                        break;
            }
        }

        private static int getSumBonusAtk() // 7-7. 공격력 합산 표시
        {    
            int sum = 0; // 능력치를 다 더 할 것 
            for (int i = 0; i < Item.ItemCnt; i++)   // 아이템을 전부 확인
            {
                if (_items[i].IsEquipped) sum += _items[i].Atk;  
                // 아이템 목록의 아이템이 장착되어 있다면, 아이템의 Atk를 다 더해라.
            }
            return sum; // 그 다음에 리턴해라.
        }
        private static int getSumBonusDef()  // 방어력 합산
        {
            int sum = 0;
            for (int i = 0; i < Item.ItemCnt; i++)   // 아이템을 전부 확인
            {
                if (_items[i].IsEquipped) sum += _items[i].Def;
            }
            return sum;
        }


        private static void InventoryMenu() // 7. 인벤토리 
        {
            Console.Clear();
            ShowHighlightText("■ 인벤토리 ■");
            Console.WriteLine("보유중인 아이템을 관리 할 수 있습니다.");
            Console.WriteLine("");
            Console.WriteLine("[아이템 목록]");
            Console.WriteLine("");

            // 위쪽 Item 클래스로 이동해서 작업 7-1로.

            // 7-2 아이템 설명 출력 반복문
            for(int i = 0; i<Item.ItemCnt; i++) // 아이템의 Itemcnt 반복문, 아이템의 가짓 수 만큼 출력되어 보임
            {
                _items[i].PrintItemStatDescription(true, i+1); // true면, _items의 i번째에서 7-1의 PrintItemStatDescription();(아이템 설명) ++ 출력
            }
            Console.WriteLine("");
            Console.WriteLine("0. 나가기");
            Console.WriteLine("1. 장착관리");
            Console.WriteLine("");

            switch (CheckValidInput(0, 1)) // 0 or 1
            {
                case 0:
                    StartMenu();
                    break;
                case 1:
                    EquipMenu(); // 장착 관리
                    break;
            }
        }

        private static void EquipMenu() // 7-3. 장착관리 메뉴
        {
            Console.Clear();

            ShowHighlightText("■ 인벤토리 - 장착 관리 ■");
            Console.WriteLine("보유중인 아이템을 장착/해제 할 수 있습니다.");
            Console.WriteLine("");
            Console.WriteLine("[아이템 목록]");
            Console.WriteLine("");
            // 잠시 PrintItemStatDescription함수로 이동, withNumber 변수를 활용 예정
            for (int i = 0; i < Item.ItemCnt; i++)
            {
                _items[i].PrintItemStatDescription(true, i+1);
            }
           
            Console.WriteLine("");
            Console.WriteLine("0. 나가기");

            // 7-5.  default를 활용한 switch문 ->  모든 케이스가 아니면, 마지막에 케이스 default가 실행
            int keyInput = CheckValidInput(0, Item.ItemCnt); // 아까 만든 입력 유효성 확인 함수(0에서 아이템 숫자만큼) 인풋값에 활용
            switch (keyInput)
            {
                case 0:
                    InventoryMenu();
                    break;
                default:
                    ToggleEquipStatus(keyInput - 1); // ToggleEquipStatus는 곧 만들고(아이템 장착 상태 변경),
                                                     // 유저 입력값은 123이며 실제 배열에는 012 이므로 -1해서 맞춰줌
                    EquipMenu();
                    break;

            }
        }

        private static void ToggleEquipStatus(int idx) // 7-6. 아이템 장착 상태 변경  , IsEquipped;가 true면 [E]가 나온다.
        {
            _items[idx].IsEquipped = !_items[idx].IsEquipped; // _items의 목록[idx]에 들어가서 IsEquipped이면, !(bool값을 반대로)로 장착 상태 변경
        }

        private static void ShowHighlightText(string text) // 6-1. 첫 줄 색 변경 함수, 마젠타 색
        {
            Console.ForegroundColor = ConsoleColor.Magenta; 
            Console.WriteLine(text);
            Console.ResetColor();
        }

        private static void PrintTextWithHighlights(string s1, string s2, string s3 = "") // 6-2. 문자열 하이라이트 효과 함수 
        {
            Console.Write(s1);
            Console.ForegroundColor = ConsoleColor.Yellow; // 노란색 발동 -> s2에 적용
            Console.Write(s2);
            Console.ResetColor (); // 색 리셋
            Console.WriteLine(s3);
        }





        private static int CheckValidInput(int min, int max) // 5-6. 입력 값 유효성 확인 함수 (int 반환)
        {
            // 아래 두 가지 상황은 비정상, 재입력 수행
            // 1. 숫자가 아닌 입력을 받은 경우,    2. 숫자가 최솟값 에서 최댓값의 범위를 벗어난 경우
            int keyInput; // tryParse(정수화)에 필요
            bool result;  // while 반복문에 필요
            do // 일단 한 번 실행
            {
                Console.WriteLine("원하시는 행동을 입력 해주세요.");
                result = int.TryParse(Console.ReadLine(), out keyInput);
                // 입력을 정수로 변환하여 int KeyInput에 저장하고, 결과 값을 result로 설정.
                // 결과 값이 숫자(정수)면 가져오고, 그 외면 안 가져옴(실행 안한다는 뜻)
            }
            while (result == false || CheckIfVaild(keyInput, min, max) == false); // result가 false거나 CheckIfVaild함수가 false면 반복 

            //여기에 도착했다는 것은 (아래 유효성 확인 bool 함수를 통해) 제대로 입력을 받았다는 것.
            return keyInput;
        }

        private static bool CheckIfVaild(int keyInput, int min, int max) // 5-7. 유효성 확인 함수2 (bool 반환)
        {
            if (min <= keyInput && keyInput <= max) return true; // 키 입력값이 min ~ mix 사이면 return이 참 = 실행
            return false; // 그 외면 false
        }

        static void AddItem(Item item) // 5-3. 아이템 추가 함수
        {                               // ( ) 안에 Item item ? -> AddItem 메서드의 매개 변수 = 외부에서 Item 객체의 item 매개 변수를 받아 온 것.
                                        // Item 객체의 속성과 메서드에 접근 할 수 있음(데이터 읽기, 수정, 필요 기능 수행)
                                        // 타입 유연성, 재사용성, 안정성을 보장하고 잘못된 타입의 객체 전달 방지.

            if (Item.ItemCnt == 8) return; // Item클래스 객체의 ItemCnt 변수가 10이면 아무 것도 안 만든다.
            _items[Item.ItemCnt] = item;  // 0개 -> 0번 인덱스, 1개 -> 1번 인덱스
            Item.ItemCnt++;
        }

        private static void PrintStartLogo() // 5-4. 게임 스타트 화면
        {

            Console.WriteLine("==================================================================");
            Console.WriteLine("     ___________________   _____  __________ ___________ _____");
            Console.WriteLine("     \\_____  \\  |     ___//  /_\\  \\ |       _/  |    |  /  /_\\  \\ ");
            Console.WriteLine("     /        \\ |    |   /    |    \\|    |   \\  |    | /    |    \\");
            Console.WriteLine("    /_______  / |____|   \\____|__  /|____|_  /  |____| \\____|__  /");
            Console.WriteLine("            \\/                   \\/        \\/                  \\/");
            Console.WriteLine("________    ____ ___ _______     ________ ___________________    _______ ");
            Console.WriteLine("\\______ \\  |    |   \\\\      \\   /  _____/ \\_   _____/\\_____  \\   \\      \\");
            Console.WriteLine(" |    |  \\ |    |   //   |   \\ /   \\  ___  |    __)_  /   |   \\  /   |   \\");
            Console.WriteLine(" |    `   \\|    |  //    |    \\\\    \\_\\  \\ |        \\/    |    \\/    |    \\");
            Console.WriteLine("/_______  /|______/ \\____|__  / \\______  //_______  /\\_______  /\\____|__  /");
            Console.WriteLine("        \\/                  \\/         \\/         \\/         \\/         \\/");
            Console.WriteLine("==============================================================================");
            Console.WriteLine("                            PRESS ANYWAY TO START                             ");
            Console.WriteLine("==============================================================================");
            Console.ReadKey(); // 아무 키나 입력 받음
        }
    }
}


추가로 배운 기능 및 사용한 함수

Console.ForegroundColor / ResetColor
글자색 변경 및 리셋(ResetColor)
string.Right(totalWidth) / LeftPad  
글자 정렬 기능
아이템 텍스트 정렬용 메서드 2개 

        public static int GetPrintableLength(string str) // 아이템 텍스트 정렬을 위해 Length의 길이를 구함
        {
            int length = 0;
            foreach (char c in str)
            {
                if (char.GetUnicodeCategory(c) == System.Globalization.UnicodeCategory.OtherLetter)
                {
                    length += 2; // 한글과 같은 넓은 문자는 길이를 2로 취급
                }
                else
                {
                    length += 1; // 나머지 문자는 길이를 1로 취급
                }
            }
            return length;
        }


        public static string PadRightForMixedText(string str, int totalLength)
        {
            int currentLength = GetPrintableLength(str); // 텍스트의 실제 길이
            int padding = totalLength - currentLength; //  총길이 - 실제길이 = int padding 추가해야 할 길이
            return str.PadRight(str.Length + padding); // padding 만큼 PadRight(문자열의 오른쪽)에 공백을 추가
        }

하루 종일 다시 만들어보며 분석을 했는데, 이리저리 클래스를 넘나들며 만드는 것 자체가 쉽지 않다.

모르는 부분이 있거나, 이해하지 않으면 찜찜해서 왜 저렇게 입력 했는지 일일히 주석을 달다보니 하루가 가버렸다.

이제 추가 기능 차례인데, 내일 저녁까지 완성 할 수 있을지..

추후에는 텍스트 RPG를 혼자서 처음부터 끝까지 구현 할 수 있는게 최종 목표.


이제 AM 1:30에 시작하는 축구를 보러 갈 것이다.


어? 30분 뒤다.

오후 3시부터 새벽1시까지 오늘의 공부 끝!


이건 ASCII art 라고 텍스트를 텍스트형 아트 문자로 바꿔주는 곳, 게임 스타트 화면에 활용 됨.
https://textkool.com/en/test-ascii-art-generator?text=

profile
개발 모코코

0개의 댓글