[C#]TIL (29) | 2023.09.01 | 던전 배틀 (Text 게임)

kjg5370·2023년 9월 1일
0

TIL

목록 보기
29/91
post-thumbnail

들어가기 앞서

오늘 팀프로젝트를 마무리하고 모두 모여 자기 팀들의 작품들을 발표하였습니다.
정말 멋진 작품들이 많았고 이건 어떻게 만든거지? 싶은 작품들도 많았습니다.
다들 정말 실력 장난 아니네요. 텍스트로 게임을 만들어서 화면에 보여준다는 것이
다른 팀들의 코드를 봤을 때 그 코드의 양만 봐도 얼마나 힘든 일인지 이번에
많이 깨닫게 되었습니다.

오늘 배운 것

  • 인터페이스 활용
    인터페이스 : 클래스가 따라야 하는 메서드 시그니처(메서드의 이름, 매개 변수, 반환 값 유형) 집합을 정의하는 추상 형태의 템플릿.
    1. 추상 메서드만을 포함
      추상 메서드만을 정의하고 구체적인 메서드 구현을 가질 수 없음.
      이러한 추상 메서드는 인터페이스를 구현하는 클래스에서 반드시 구체적으로 구현되어야 함.
    2. 다중 상속 지원
      클래스는 하나의 클래스만 상속할 수 있는 반면, 인터페이스는 여러 개를 동시에 구현할 수 있으므로 다중 상속을 지원.
    3. 느슨한 결합
      클래스가 특정 인터페이스를 구현하면 해당 인터페이스의 규약을 따르게 되므로, 클래스 간의 상호작용을 간단하게 만들고 코드 재사용을 촉진.

오늘 튜터님의 팀 프로젝트 해설을 들으면서 인터페이스를 어떻게 활용하면 되는지에 대해 알게 되었고
기존에 만들어놨던 기능들을 인터페이스를 활용하면 좋겠다라는 생각을 하게 되었습니다.

  • 기존에 만들었던 코드
    기존 코드는 몬스터와 플레이어의 공격을 실행할 때 스킬 클래스를 만들고 플레이어가 기본적으로 가지고 있는 스킬 "기본 공격"을 통해
     Skills.Add(new Skill
                    {
                        Name = "기본 공격",
                        MPCost = 0,
                        isMunti = false,
                        Description = "기본 공격을 수행합니다.",
                        SingleAction = (player, monster) =>
                        {
                            int playerDamage = player.Damage();
                            int critical = rand.Next(0, 101);
                            string cri = "";
                            if (critical <= 15)
                                {
                                    playerDamage = (int)(playerDamage * 1.6);
                                    cri = " - 치명타 공격!!";
                                }
                                else cri = "";
                           
                            Console.WriteLine($"Lv.{monster.Level} {monster.Name} 을(를) 맞췄습니다. [데미지 : {playerDamage}]{cri}");
                            Console.WriteLine();
                            Console.WriteLine($"Lv.{monster.Level} {monster.Name}");
                            Console.Write($"HP {monster.HP} -> ");
                            player.Mp -= player.Skills[0].MPCost;
                            if (monster.HP - playerDamage > 0)
                            {
                                monster.HP -= playerDamage;
                                Console.WriteLine(monster.HP);
                            }
                            else
                            {
                                monster.HP = 0;
                                Console.WriteLine("Dead");
                            }                       
                        }
                    }); 
    이런 식으로 스킬마다 데미지를 걔산하고 출력까지 하는 아주 기다란 코드를 가지고 있었습니다.
    인터페이스나 추상 클래스를 어떻게 활용해야 될지 모르는 저는 그냥 복잡하더라도 동작은 되니까 하고 넘어갔습니다.
    하지만 인터페이스를 활용하는 것을 보니 "와 저렇게 하나만 만들어두면 복잡하게 코드를 추가할 필요 없이 재사용이 되는구나"
    하고 깨닫게 되었습니다.
    튜터님의 방식은 이랬습니다.
    일단 플레이어와 몬스터가 모두 공격을 하고 기본적으로 플레이어와 몬스터 모두 가지고 있고 공격에 활용되는 변수들을 모아서
    Battle인터페이스를 만들고
    public interface IBattle
    {
        int Health { get; set; }     // 체력
        int AttackPower { get; }     // 공격력
        int DefensePower { get; }    // 방어력
    
        void Attack(IBattle target); // 공격 메서드
    }

플레이어와 문스터가 Battle을 상속 받고 이 Battle 인터페이스를 상속 받은 클래스만이 공격을 할 수 있게 해준다는 것이였습니다.
이렇게 되면 나중에 플레이어와 몬스터 말고도 공격이 가능한 예를들어 NPC 같은 것을 추가 했을 때 제가 만든 방식처럼 코드를 NPC에도 만들어주는
것이 아니라 Battle인터페이스만 상속 받으면 바로 공격을 사용할 수 있게 된다는 것이였습니다.
이런식으로 중복되는 기능을 만들어야 할 때 인터페이스를 활용하면 좋다는 것을 알게 되었습니다.

심지어 이렇게 만들어두면 Attack 이라는 것을 실행 했을 때

public void Attack(Monster target)
    {
        int damage = Math.Max(AttackPower - target.DefensePower, 0);
        target.Health -= damage;
        Console.WriteLine($"플레이어가 몬스터를 공격하여 {damage}의 데미지를 입혔습니다.");
    }

이런식으로 따로 Attack이라는 것을 플레이어나 몬스터에게 만들어서 플레이어가 몬스터를 공격하는 것, 플레이어가 NPC를 공격하는 것 이런 함수들을 계속해서 만들지 않아도

public void Attack(IBattle target)
    {
        int damage = Math.Max(AttackPower - target.DefensePower, 0);
        target.Health -= damage;
    }

Battle 인터페이스를 할당 받은 target 들어오면 자동으로 target에 대한 계산을 해주는 식으로 플레이어가 무엇을 공격하든 타켓만 지정해주면 되는 코드를 작성할 수 있었습니다.

기억 할 것 & 진행 사항

팀 프로젝트 발표를 진행하면서 매니저님이 여러가지 조언들을 말씀해주셨는데 제가 기억력이 안좋아서 몇가지 기억나는 것만 적어놓겠습니다.

  • 게임 파일을 다른 사람들과 공유할 때
    게임 파일을 다른 사람들과 공유할 때 Read Me나 설명서를 첨부하는 것은 매우 중요합니다.
    이를 통해 다른 사람들이 게임을 더 쉽게 이해하고 실행할 수 있으며, 게임에 대한 추가 정보와 지침을 제공할 수 있습니다.

  • Read Me(게임)에 포함하면 좋은 것.

    • 게임 설명 : 게임의 주요 컨셉과 목적을 간단하게 설명 및 게임의 장르, 스토리, 게임 플레이 방식 등을 소개.

    • 시작하기 : 게임을 실행하려면 어떻게 해야 하는지 설명.
      게임 파일을 다운로드하고 실행하는 단계를 상세히 안내.

    • 시스템 요구 사항 : 게임을 실행하기 위한 최소한의 하드웨어 및 소프트웨어 요구 사항을 나열.
      게임을 실행할 수 있는 컴퓨터 환경에 대한 정보를 제공

    • 게임 조작 방법 : 게임을 어떻게 플레이하는지에 대한 지침을 제공.
      키보드, 마우스, 게임패드 등의 입력 장치를 사용하는 방법을 설명.

    • 게임 내의 주요 기능 : 게임에서 사용할 수 있는 주요 기능이나 아이템을 소개하고 어떻게 활용할 수 있는지 설명.

    • 문제 해결 : 게임 실행 중에 자주 발생하는 문제나 오류에 대한 해결 방법을 제공.
      사용자가 문제를 해결하는 데 도움이 될 수 있는 팁을 제공.

    • 업데이트 및 패치 정보 : 게임을 업데이트하거나 패치하는 방법에 대한 정보를 포함하고, 최신 버전의 게임에 대한 변경 사항을 설명.

    • 문의처 : 사용자가 질문이나 문제를 보고할 수 있는 연락처 정보를 제공.
      이메일 주소나 게임 커뮤니티 포럼 링크 등

    • 크레딧 : 게임 개발에 참여한 사람들의 이름이나 조직 정보를 표시하고, 게임에 사용된 리소스나 라이브러리의 출처를 명시.

    • 라이선스 정보 : 게임의 라이선스 정보를 제공.
      게임을 공개 소스로 배포하는 경우 해당 라이선스를 따르는 조건을 설명.

  • 코드를 확장성있게 짜기
    새로운 데이터나 기능을 추가할 때 코드를 크게 수정하지 않고도 기존 코드를 재활용할 수 있어야 합니다.
    예를 들어
    추상화와 인터페이스를 사용하여 코드의 구체적인 구현과 분리 하여 새로운 데이터나 기능을 추가할 때
    인터페이스를 준수하는 새로운 클래스를 작성하고 기존 코드와 연결할 수 있거나
    데이터를 처리할 때 JSON 또는 XML과 같은 형식의 유연한 데이터 구조를 사용하여 데이터를 표현하고 해석할 수 있습니다.

코드를 짜면서 머리가 아팠던 프로젝트 만들기가 끝나고 드디어 2일동안은 쉴 수 있나? 하는 주말이 찾아왔네요.
뭔가 좀더 해보고 싶기도 하고 끝나서 홀가분하기도 하고 오늘 많은 걸 알 수 있고 좋은 작품들을 많이 구경해서
기분이 좋기도 합니다. 앞으로도 많은 것들을 공부하고 성장하여 멋진 작품을 만드는 날 까지 노력하겠습니다.😊

내일 할 일

  • 하루 계획
    • 졸업작품(와이어프레임 제작)
    • 팀프로젝트 발표에서 인상깊었던 작품 보기
profile
학생입니다

0개의 댓글