1. 오늘의 할 일
던전!
여관!
레벨링!!
직업선택!!!
TextRPG를 더 RPG 처럼 만들어주는 것!
어디까지 만들 수 있는지 한 번 해보자.
렛츠고

2. 작업 개시🛠️
1. 던전
던전! RPG의 꽃이지만, 처음 만들 것은 아주 간단한 형태로 만들 것이다.
그리고 나중에 심화버전으로 던전 진입>선택지 몇 가지> 종료 의 형태로 만들고 싶다.
만약 어릴 때 '동물농장'-'탐험하기'를 해본 사람이라면, 내가 말한 방식이 어떤 느낌인지 더 잘 알 수 있을 것이다.
(방을 열면 출구로 향하는 길이 있거나, 몬스터가 있거나.)
하지만 일단! 지금 만들 것은 방어력을 비교하고 성공/실패를 나누는 것이다.
일단 메서드 생성

아주 간단한 구조로 짜볼 예정이다.
일단 방어력을 비교한다.
>총 방어력이 권장 방어력보다 낮으면 실패할 확률이 발생한다. (40%+부족한 방어력만큼)
>방어력이 높으면 성공-권장 방어력+-에 따라 종료시 체력 소모에 반영됨
공격력을 비교한다.
>공력력에 따라 +추가보상을 획득한다. (공격력 10이면, 공격력 10~20% 골드 획득 보너스)
경험치 획득
>감소한 hp*10만큼 획득한다. (너무 쉬우면, 그만큼 경험치가 올라가지 않는다)
임의로 가장 첫번째 던전인 '평원 던전'을 메서드로 제작해본다.
//일단 실패 확률을 40%로 고정해본다.
static void PlainDungeon()
{
Console.WriteLine("평원 던전의 권장 방어력은 5입니다.");
Console.WriteLine("입장하시겠습니까?(Y/N)");
string answer = Console.ReadLine();
switch (answer)
{
case "Y":
Console.WriteLine("던전 공략을 시작합니다.");
if (player.defense + player.itemDefense >= 5)
{
Console.WriteLine("던전 공략에 성공했습니다.");
//체력 소모 값=20~35에 방어력에 따른 보정치 발생
int minusHP = new Random().Next(20, 36);
player.hp -= (int)(minusHP - ((player.defense + player.itemDefense) - 5));
//보상은 공격력~공격력*2 %까지 보정됨 (공격력 10이면 10%~20%까지 보정됨)
float rewardPercent = player.attack + player.itemAttack;
int reward = new Random().Next((int)rewardPercent, (int)rewardPercent * 2 + 1);
int rewardGold = (int)(1000 + 1000 * (reward * 0.01f));
player.gold += rewardGold;
player.exp += (int)(minusHP * 10); //경험치 획득
Console.WriteLine("==던전 결과==");
Console.WriteLine($"획득 Gold:{rewardGold}");
Console.WriteLine($"획득 경험치:{(int)(minusHP * 10)}");
player.LevelUp(); //레벨업 체크
Dungeon();
}
else
{
int clear = new Random().Next(1, 101);
if (clear <= 40)
{
Console.WriteLine("던전 공략에 실패했습니다.");
Console.WriteLine($"체력이 {50 + 5 - (player.defense + player.itemDefense)}감소합니다.");
player.hp -= (int)(50 + 5 - (player.defense + player.itemDefense));
Console.WriteLine($"현재 체력: {player.hp}");
}
else
{
Console.WriteLine("던전 공략에 성공했습니다.");
//체력 소모 값=20~35에 방어력에 따른 보정치 발생
int minusHP = new Random().Next(20, 36);
player.hp -= (int)(minusHP - ((player.defense + player.itemDefense) - 5));
//보상은 공격력~공격력*2 %까지 보정됨 (공격력 10이면 10%~20%까지 보정됨)
float rewardPercent = player.attack + player.itemAttack;
int reward = new Random().Next((int)rewardPercent, (int)rewardPercent * 2 + 1);
int rewardGold = (int)(1000 + 1000 * (reward * 0.01f));
player.gold += rewardGold;
player.exp += (int)(minusHP * 10); //경험치 획득
Console.WriteLine("==던전 결과==");
Console.WriteLine($"획득 Gold:{rewardGold}");
Console.WriteLine($"획득 경험치:{(int)(minusHP * 10)}");
player.LevelUp(); //레벨업 체크
Dungeon();
}
}
break;
case "N":
Console.WriteLine("던전 공략을 그만둡니다.");
Dungeon();
break;
}
}
그리고 제작한 후의 나:

일단 기능은 잘 작동했다.(놀랍게도)
그런데 이거...던전도 클래스로 만들어서, 클래스-메서드로 돌리면 되는 거 아냐?
클리어하면 클리어 메서드/실패하면 실패 메서드 출력하면 되는 거 아냐?
이거 세 개나 만들면 이상하진 않은데 중복코드 X 3(이상) 될 거 같은데?
그리고 클리어 처리랑 hp = 0일 때의 처리를 같이 두면 될 것 같은데?

Let's go
일단 던전에 사용할 클래스를 짠다.

한 번 짜두면 온갖 던전을 만들 수 있어서 슬슬 애용하는 중.

리스트도 만들었다.
그렇게 최종.의 최종.의 최종
//던전 진행 메서드 (권장 방어력보다 낮으면 일정 확률로 실패함)
public void DungeonClear()
{
Console.WriteLine($"{name}의 권장 방어력은 {recommendDefense}입니다.");
Console.WriteLine("입장하시겠습니까?(Y/N)");
Console.Write("입력: ");
string answer = Console.ReadLine();
Console.WriteLine("============================================");
switch (answer)
{
case "Y":
Console.WriteLine("던전 공략을 시작합니다.");
Console.WriteLine("============================================");
//실패는 방어력이 권장 방어력보다 낮을 때만 확률적으로 발생
if (player.defense + player.itemDefense <= recommendDefense)
{
int clear = new Random().Next(1, 101); //던전 공략 실패 확률 1~100
if (clear <= 40) //40% 확률로 실패
{
Console.WriteLine("던전 공략에 실패했습니다.");
Console.WriteLine($"체력이 {50 + recommendDefense - (player.defense + player.itemDefense)}감소합니다.");
player.hp -= (int)(50 + recommendDefense - (player.defense + player.itemDefense)); //체력 감소
if (player.hp <= 0)
{
player.hp = 0; //마이너스가 되더라도 체력 0으로 설정
Console.WriteLine("============================================");
Console.WriteLine("공략은 실패했다. 하지만….");
Console.WriteLine($"{player.name}님의 남은 체력: 0");
player.GameOver(); //게임 오버 메서드 호출
break;
}
Console.WriteLine($"{player.name}님의 체력: {player.hp}");
Console.WriteLine("============================================");
DungeonStart(); //던전입구로 이동
}
}
//나머지는 성공
//체력 소모 값=20~35에 방어력에 따른 보정치 발생
int minusHP = new Random().Next(20, 36);
player.hp -= (int)(minusHP - ((player.defense + player.itemDefense) - 5));
//공략에 성공해도 체력이 0이 되면 행동불능->실패
if (player.hp <= 0)
{
player.hp = 0; //마이너스가 되더라도 체력 0으로 설정
Console.WriteLine("============================================");
Console.WriteLine("공략은 성공했다. 하지만….");
Console.WriteLine($"{player.name}님의 남은 체력: 0");
player.GameOver(); //게임 오버 메서드 호출
break;
}
Console.WriteLine("던전 공략에 성공했습니다.");
Console.WriteLine("============================================");
Console.WriteLine($"{player.name}님의 체력이 {minusHP} 감소했습니다.");
Console.WriteLine($"{player.name}님의 체력: {player.hp}");
//보상은 공격력~공격력*2 %까지 보정됨 (공격력 10이면 10%~20%까지 보정됨)
int rewardPercent = (int)(player.attack + player.itemAttack);
int reward = new Random().Next(rewardPercent, rewardPercent * 2 + 1);
player.gold += (int)(rewardGold * (1 + reward * 0.01f));
//던전 보상 골드 지급 (기본 보상+보정치) 즉, 리워드가 20%로 결정되면 1.2배 지급
player.exp += (int)(minusHP * 10); //감소한 체력의 10배 만큼 경험치 지급
Console.WriteLine("==던전 결과==");
Console.WriteLine($"획득 Gold:{(int)(rewardGold * (1 + reward * 0.01f))}");
Console.WriteLine($"획득 경험치:{(int)(minusHP * 10)}");
player.LevelUp(); //레벨업 체크
DungeonStart(); //던전 공략 후 던전입구로 이동
break;
case "N":
Console.WriteLine("던전에 들어가지 않고, 다시 발길을 돌렸다.");
Console.WriteLine("============================================");
DungeonStart(); //던전입구로 이동
break;
default:
Console.WriteLine("잘못된 입력입니다.");
DungeonClear();
break;
}
}
최대한 같은 문장은 줄이고, 통합하고, 지웠다. (처음 쓸 때는 공략 성공 메세지 저 긴게 x2배로 있었다는 게 믿겨지는지?)
아직 보충할 부분이나 정돈해야할 것은 있을 것 같지만(아직 씬 구분/정리를 제대로 하지 않아 어지럽다)
내가 필요로 하던 기능 구현은 전부 완료되었다.
그럼, 수정한 코드도 제대로 작동하는지 한 번 살펴보자.


클리어하고 경험치를 받자 신명나게 올라가는 레벨.
(필요 경험치 초기 수치를 500으로 잡아야 할 것 같다.)

다른 던전을 선택해도 정상적으로 작동하는 것을 볼 수 있다.
던전 클리어!
2. 여관
여관, 기본적으로 '휴식공간'으로 생각하는 곳이고, 나 역시 그렇게 만들 생각이다.
만약 저장시스템을 넣는다면 여관에 넣고 싶다고 생각하고 있다.
하지만, 일단 필요한 것은 '휴식'시스템!
식사 주문 시스템도 곧 넣을 것이지만, 일단 휴식 기능만 정상적으로 작동하는지 확인해보도록 하자.

여관의 구성은 간단하게 짜보았다.
휴식/숙박 로직
//휴식/숙박
static void Rest()
{
Console.WriteLine("여관 주인: 숙박? 마침 방이 비어있네.");
Console.WriteLine("여관 주인: 방은 500G야.");
Console.WriteLine("=======================================");
Console.WriteLine($"{player.name}님의 골드: {player.gold}G");
Console.WriteLine("=======================================");
Console.WriteLine("여관 주인: 방 하나 내어줄까?(Y/N)");
string answer = Console.ReadLine();
switch (answer)
{
case "Y":
if (player.gold >= 500)
{
Console.WriteLine("여관 주인: 방은 2층에 있어.");
Console.WriteLine("여관 주인: 편히 쉬어.");
player.gold -= 500; //골드 차감
player.hp = 100; //체력 회복
Console.WriteLine($"{player.name}의 체력이 회복되었습니다.");
Console.WriteLine("=======================================");
Console.WriteLine($"{player.name}님의 골드: {player.gold}G");
Console.WriteLine("=======================================");
Tarvern();
}
else
{
Console.WriteLine("여관 주인: 방을 빌리기엔 돈이 부족한 것 같은데?");
Console.WriteLine("여관 주인: 상점에 가서 물건을 팔거나, 던전에 가서 돈을 벌어보는 건 어때?");
Tarvern();
}
break;
case "N":
Console.WriteLine("여관 주인: 뭐야, 그만 둘 거야?");
Tarvern();
break;
default:
Console.WriteLine("잘못된 입력입니다.");
Rest();
break;
}
}
자, 구성을 짰으니, 기능을 테스트 해봐야한다.

마침, 방금 테스터가 던전을 다녀오느라 체력이 많이 깎인 상태이다.
여관에 바로 보내서, 숙박을 요청하자.

500G가 차감되고, 체력이 회복되었다는 알림도 나타났다.
그럼 정말 회복되었는지 스탯창을 열어보자.

굿.
정상적으로 모든 HP가 회복되었다. (^^)b
하지만 공격력과 방어력이 레벨업 할 때마다 기하급수적으로 늘어나는 것이 보인다.
굳이 늘린다면 1.1배~1.2배 정도가 좋을 것 같다. (데이터를 수정해주도록 하자)
3. 레벨업
레벨업! 던전이 있다면 레벨업도 있어야한다.
언제까지 lv1의 초보자로 살 수는 없으며, RPG의 묘미 중 하나는 싸우면서 점점 강해지는 내 캐릭터도 있다.
경험치를 모으기 위해서는 열심히 던전을 돌아야한다. 이것이 RPG의 묘미(이자 노가다)
사실 던전 로직을 보면, 이미 레벨업 로직이 짜여져 있다는 걸 확인할 수 있다. ( ^^)9
player 클래스에 들어간 LevelUP 메서드
public void LevelUp()
{
if (exp >= needExp)
{
//필요 경험치보다 경험치가 적어질 때까지 반복
while (exp >= needExp)
{
attack += attack * 0.5f;
defense += defense * 0.5f;
level++;
exp -= needExp; //레벨업 후 남은 경험치 유지
needExp = 125 + (level * level * level); //다음 레벨업에 필요한 경험치 계산
Console.WriteLine("============================================");
Console.WriteLine($"{name}의 레벨이 올랐습니다! \n 현재 레벨: {level}");
Console.WriteLine($"공격력: {attack + itemAttack} (+{itemAttack})");
Console.WriteLine($"방어력: {defense + itemAttack} (+{itemDefense})");
Console.WriteLine("============================================");
}
}
}
이 방법의 문제가 하나 있다.(그리고 쉽게 해결할 수도 있다.)
attack과 defense(기본 공/방)를 보면 *0.5f 씩 더하고 있다. 즉, 기존 공격력의 1.5배가 되고 있다는 뜻.
(추후, 1.1배로 수정 예정)
하지만 0.5는 곱하면 곱할 수록 계속 뒤로 숫자가 늘어난다.
방어력 10을 기준으로 보자면 이런 상황이다.

방법은?: 가장 쉬운 방법은 int값으로 만드는 것이다.

얼마나 편하고, 또 얼마나 쉬운가?
이러면 앞으로도 계속 깔끔한 스탯창을 볼 수있다. (여관-스테이터스 창 참고)
LevelUP 은 매 던전을 공략 성공하고 경험치 정산이 끝난 다음에 적용되어, 필요 경험치보다 현재 경험치가 낮으면 아무 기능을 하지 않도록 만들어두었다.
반대로, 필요경험치보다 경험치가 높다면, 필요 경험치보다 낮아질 때까지 반복해서 레벨업을 시킨다.
4. 직업 선택
메X플이라던가, 엘X드라던가, 많은 RPG 게임에 공통으로 등장하는 '직업군'이 있다.
전사, 마법사, 궁수
RPG 직업 3대장이다. (이제 여기서 보통 단검을 쓰는 도적까지 추가되기도 한다.)
일반적으로 전사는 체력과 방어력이 높다. RPG게임 내에서 '탱커'역할을 맡게 되면 공격력이 떨어진다.
반대로 마법사는 체력이 낮고 공격력이 높다. 쉽게 죽는 대신 순간 화력이 강하다.
궁수는 민첩함/기동성이 장점이고, 공격력과 방어력은 중간정도가 보통이다.
하지만 내가 기본으로 설정한 능력치는 체력/공격력/방어력 정도. (민첩은 커녕 마공/물공으로 나누지도 않았다.)
그러므로 이번에는 체력을 건들지 않고, 공격력과 방어력을 이용해 직업군을 나눌 것이다.
초기 캐릭터가 설정된 값은 공 10 방 5이었으므로, 공+방의 합을 15로 기준삼아 올려줄 것이다.
1. 캐릭터 객체 생성

캐릭터 객체에 부여되는 공격력, 방어력을 0으로 만들어 캐릭터 객체를 생성한다.
그럼 공격력과 방어력을 언제 부여하는 게 좋을까?
가장 처음, 이름과 직업을 정할 때다.
2. 캐릭터 객체-스탯 조정위치 변경

가장 초기 창, 직업 선택을 하고나면, 해당 '직업'에 따라 수치가 조정되도록 만들었다.
이 조정된 스탯은 플레이를 진행하는 동안 계속 유지되므로, 딱 원하던 대로의 구현이다.
(만들고나니 숨겨진 직업을 만들고 싶은 욕망이 스멀스멀 올라온다.)



모든 직업이 내가 원한 공격력과 방어력을 갖춘 것을 확인할 수 있다.
5. 상점 업데이트
상점! 직업이 3개나 되는데 아이템이 검, 창, 도끼...밖에 없으면 이거 마법사랑 궁수 차별이다.
그렇기 때문에, 각자의 디자인에 맞춰 비슷한 성능의 아이템들을 추가시켜주기로 했다.
상점에서는 각 직업별로 다른 아이템 리스트가 출력될 것이다.
전사를 선택했을 때, 아이템 리스트

마법사로 선택했을 때, 아이템 리스트

궁수를 선택했을 때, 아이템 리스트

직업따라 다른 아이템리스트! 다른 능력치!
정상적으로 잘 출력되는 걸 확인했다!
👏👏👏👏👏👏👏
이걸로 오늘 하고 싶었던 기능들 구현은 끝났다.
4. 내일 할 일
사실 이것으로 처음 목표한 것은 거의 다 되었다.
원하는 걸 더 덧붙이고 더하다보니 오래 걸렸을 뿐.
내일 가능하다면 저장/불러오기도 만들고 싶지만, 우선순위는 코드를 보기 좋게 정리하는 것이다.
(그리고, 혹시 모를 오류가 있는지도 확인해봐야 한다.)
'Unity_본캠프' 카테고리의 다른 글
[내일배움캠프 2주차] TextRPG 정리 (0) | 2025.04.20 |
---|---|
[내일배움캠프 10일차]TextRPG 제작기 5 (1) | 2025.04.18 |
[내일배움캠프 8일차] TextRPG 제작기 3 (5) | 2025.04.16 |
[내일배움캠프 7일차] TextRPG 제작기 2 (4) | 2025.04.15 |
[내일배움캠프 6일차] TextRPG 제작기 1 (1) | 2025.04.14 |