A. TextRPG 연습하기
1. 게임 흐름
- 시작
- 로비 입장
- 직업 선택 123
- 필드 입장 12
- 몬스터 스폰
- 전투 12
- 후 결과에 따른 분기문...
a. 게임의 기본 구조
게임의 기본 구조는 while문으로 작성되어있음
📘 문법
void EnterLobby() {
while (true) {
//입력
//로직 ----- 일부 로직이 서버에 분산되어 있다면 온라인 게임 / 싱글게임이면 X
//출력 (아트 리소스)
}
}
2. 코드 작성하기
a. 필드 생성
- 입장 하자마자 로비로 들어가야 하기 때문에 바로 EnterLobby 실행
- 직업 생성
void EnterLobby();
int main()
{
EnterLobby(); //1.
}
void EnterLobby() {
while (true) {
cout << "--------------------" << endl;
cout << "로비에 입장했습니다!" << endl;
cout << "--------------------" << endl;
//플레이어 직업 선택 - 별도의 기능 2.
SelectPlayer();
}
}
b. 직업 생성
- 직업을 골라주세요 출력
- 직업 타입 생성하기
- 직업, hp, attack, defence 선언하기
- 직업 입력받기
- 받은 값 PlayerType으로 변환 및 초기화하기
- 값에 따른 변수 초기화 하기
- 루프 문 종료 후 int a = 3에 break 걸고 오류 확인하기
//2. 직업 타입
enum PlayerType {
PT_None = 0,
PT_Knight = 1,
PT_Archer = 2,
PT_Mage = 3,
};
//스텟을 한번에 관리
struct StatInfo {
int hp;
int attack;
int defence;
};
//C#에서는 int와 enum은 다르지만
//C++에서는 둘이 동일하기 때문에 지금은 아래와 같이 사용
//3.
PlayerType playerType;
StatInfo playerStat;
void SelectPlayer();
int main()
{
EnterLobby();
}
void EnterLobby() {
while (true) { //1.
cout << "--------------------" << endl;
cout << "로비에 입장했습니다!" << endl;
cout << "--------------------" << endl;
//플레이어 직업 선택 - 별도의 기능
SelectPlayer();
int a = 3; //7.
}
}
void SelectPlayer() {
while (true) {
cout << "--------------------" << endl;
cout << "직업을 골라주세요!" << endl;
cout << "(1) 기사 (2) 궁수 (3) 법사" << endl;
cout << ">";
int choice;
cin >> choice;
playerType = (PlayerType)choice;
if (choice == PT_Knight) {
cout << "기사 생성중..." << endl;
playerStat.hp = 150;
playerStat.attack = 10;
playerStat.defence = 5;
playerType = PT_Knight;
break;
}
else if (choice == PT_Archer) {
cout << "궁수 생성중..." << endl;
playerStat.hp = 100;
playerStat.attack = 15;
playerStat.defence = 3;
playerType = PT_Archer;
break;
}
else if (choice == PT_Mage) {
cout << "법사 생성중..." << endl;
playerStat.hp = 80;
playerStat.attack = 25;
playerStat.defence = 0;
playerType = PT_Mage;
break;
}
else {
//없어도 while문에서 반복해서 옳은 값을 입력받을때 까지 루프
}
}
c. 필드 입장하기
- 몬스터가 생성되었다면 필드 입장 유무 받기
- 입장한다면 필드 입장 알림 후 플레이어 정보 알리기
- 몬스터 스폰
- 전투할지 도주할지 선택하기
- 전투하는 도중 플레이어 스텟이 0인경우 리턴하기
void EnterField();
...
void EnterLobby() {
while (true) {
cout << "--------------------" << endl;
cout << "로비에 입장했습니다!" << endl;
cout << "--------------------" << endl;
//플레이어 직업 선택 - 별도의 기능
SelectPlayer();
cout << "--------------------" << endl;
cout << "(1) 필드 입장 (2) 게임 종료" << endl;
cout << "--------------------" << endl;
int input; //입장인지 아닌지 입력받기
cin >> input;
if (input == 1) {
EnterField();
} else {
return;
}
}
}
void EnterField() {
while(true){
cout << "--------------------" << endl;
cout << "필드에 입장했습니다!" << endl;
cout << "--------------------" << endl;
cout << "[PLAYER] HP : " << playerStat.hp << " / ATT : " << playerStat.attack << " / DEF : " << playerStat.defence << endl;
//몬스터 스폰
CreateRandomMonster();
cout << "--------------------" << endl;
cout << "(1) 전투 (2) 도주 " << endl;
cout << "--------------------" << endl;
int input; //전투인지 아닌지 입력받기
cin >> input;
if (input == 1) {
EnterBattle();
if (playerStat.hp == 0) {
return;
}
}
else {
return;
}
}
}
d-1. 몬스터 랜덤 생성
- main에 시드 생성 후 몬스터 랜덤 생성
- 몬스터 타입 생성하기
- 몬스터, hp, attack, defence 선언하기
- 랜덤값에 따른 MonsterType값 변환 및 초기화하기
- 루프 문 종료 후 int a = 3에 break 걸고 오류 확인하기
//2. 몬스터 타입
enum MonsterType {
MT_None = 0,
MT_Slime = 1,
MT_Orc = 2,
MT_Skeleton = 3,
};
MonsterType monsterType;
StatInfo monsterStat;
void CreateRandomMonster();
...
int main()
{
srand((unsigned int)time(0)); //랜덤값의 시드값
EnterLobby();
}
....
void CreateRandomMonster()
{
int randomChoice = 1 + rand() % 3; //3. 1~3사이 숫자를 랜덤으로 가져옴
switch (randomChoice) { //4.
case MT_Slime :
cout << "슬라임 생성중...! (HP:30 / ATT : 2 / DEF : 0)" << endl;
monsterStat.hp = 30;
monsterStat.attack = 2;
monsterStat.defence = 0;
monsterType = MT_Slime;
break;
case MT_Orc:
cout << "오크 생성중...! (HP:80 / ATT : 15 / DEF : 5)" << endl;
monsterStat.hp = 80;
monsterStat.attack = 15;
monsterStat.defence = 5;
monsterType = MT_Orc;
break;
case MT_Skeleton:
cout << "스켈레톤 생성중...! (HP:100 / ATT : 20 / DEF : 10)" << endl;
monsterStat.hp = 100;
monsterStat.attack = 20;
monsterStat.defence = 10;
monsterType = MT_Skeleton;
break;
}
}
d-2. 전투 시작
- 데미지 계산 (0보다 작을시 0으로 예외처리)
- 몬스터 공격 후 몬스터 체력 출력
- 몬스터 처리시 다음 처리
- 아닐시 플레이어 공격 후 플레이어 체력 출력
- 플레이어 사망 시 처리
void EnterField();
...
void EnterBattle()
{
while (true) {
//나의 공격
int damage = playerStat.attack - monsterStat.defence; //1.
if (damage < 0) {
damage = 0;
}
monsterStat.hp -= damage; //2.
if (monsterStat.hp < 0) {
monsterStat.hp = 0;
}
cout << "몬스터 남은 체력 : " << monsterStat.hp << endl;
if (monsterStat.hp == 0) { //3.
cout << "몬스터를 처치했습니다!" << endl;
WaitForNextKey();
return;
}
//몬스터의 공격
int damage2 = monsterStat.attack - playerStat.defence; //4.
if (damage2 < 0) {
damage2 = 0;
}
playerStat.hp -= damage2;
if (playerStat.hp < 0) {
playerStat.hp = 0;
}
cout << "플레이어의 남은 체력 : " << playerStat.hp << endl;
if (playerStat.hp == 0) {
cout << "당신은 사망했습니다... GAME OVER" << endl; //5.
WaitForNextKey();
return;
}
}
}
e. 사망하거나 게임이 끝날 시 처리
void WaitForNextKey();
...
void WaitForNextKey()
{
cout << "계속하려면 1을 눌러주세요" << endl;
cout << ">";
int input;
cin >> input;
system("cls"); //내용을 정리
}
3. 전체 코드
a. 파일
b. 코드
#include <iostream>
using namespace std;
//직업 타입
enum PlayerType {
PT_None = 0,
PT_Knight = 1,
PT_Archer = 2,
PT_Mage = 3,
};
//몬스터 타입
enum MonsterType {
MT_None = 0,
MT_Slime = 1,
MT_Orc = 2,
MT_Skeleton = 3,
};
//스텟을 한번에 관리
struct StatInfo {
int hp;
int attack;
int defence;
};
//C#에서는 int와 enum은 다르지만
//C++에서는 둘이 동일하기 때문에 지금은 아래와 같이 사용
PlayerType playerType;
StatInfo playerStat;
MonsterType monsterType;
StatInfo monsterStat;
void EnterLobby();
void SelectPlayer();
void EnterField();
void CreateRandomMonster();
void EnterBattle();
void WaitForNextKey();
int main()
{
srand((unsigned int)time(0)); //랜덤값의 시드값
EnterLobby();
}
void EnterLobby() {
while (true) {
cout << "--------------------" << endl;
cout << "로비에 입장했습니다!" << endl;
cout << "--------------------" << endl;
//플레이어 직업 선택 - 별도의 기능
SelectPlayer();
cout << "--------------------" << endl;
cout << "(1) 필드 입장 (2) 게임 종료" << endl;
cout << "--------------------" << endl;
int input; //입장인지 아닌지 입력받기
cin >> input;
if (input == 1) {
EnterField();
} else {
return;
}
}
}
void SelectPlayer() {
while (true) {
cout << "--------------------" << endl;
cout << "직업을 골라주세요!" << endl;
cout << "(1) 기사 (2) 궁수 (3) 법사" << endl;
cout << ">";
int choice;
cin >> choice;
playerType = (PlayerType)choice;
if (choice == PT_Knight) {
cout << "기사 생성중..." << endl;
playerStat.hp = 150;
playerStat.attack = 10;
playerStat.defence = 5;
playerType = PT_Knight;
break;
}
else if (choice == PT_Archer) {
cout << "궁수 생성중..." << endl;
playerStat.hp = 100;
playerStat.attack = 15;
playerStat.defence = 3;
playerType = PT_Archer;
break;
}
else if (choice == PT_Mage) {
cout << "법사 생성중..." << endl;
playerStat.hp = 80;
playerStat.attack = 25;
playerStat.defence = 0;
playerType = PT_Mage;
break;
}
else {
//없어도 while문에서 반복해서 옳은 값을 입력받을때 까지 루프
}
}
}
void EnterField() {
while(true){
cout << "--------------------" << endl;
cout << "필드에 입장했습니다!" << endl;
cout << "--------------------" << endl;
cout << "[PLAYER] HP : " << playerStat.hp << " / ATT : " << playerStat.attack << " / DEF : " << playerStat.defence << endl;
//몬스터 스폰
CreateRandomMonster();
cout << "--------------------" << endl;
cout << "(1) 전투 (2) 도주 " << endl;
cout << "--------------------" << endl;
int input; //전투인지 아닌지 입력받기
cin >> input;
if (input == 1) {
EnterBattle();
if (playerStat.hp == 0) {
return;
}
}
else {
return;
}
}
}
void CreateRandomMonster()
{
int randomChoice = 1 + rand() % 3; //1~3사이 숫자를 랜덤으로 가져옴
switch (randomChoice) {
case MT_Slime :
cout << "슬라임 생성중...! (HP:30 / ATT : 2 / DEF : 0)" << endl;
monsterStat.hp = 30;
monsterStat.attack = 2;
monsterStat.defence = 0;
monsterType = MT_Slime;
break;
case MT_Orc:
cout << "오크 생성중...! (HP:80 / ATT : 15 / DEF : 5)" << endl;
monsterStat.hp = 80;
monsterStat.attack = 15;
monsterStat.defence = 5;
monsterType = MT_Orc;
break;
case MT_Skeleton:
cout << "스켈레톤 생성중...! (HP:100 / ATT : 20 / DEF : 10)" << endl;
monsterStat.hp = 100;
monsterStat.attack = 20;
monsterStat.defence = 10;
monsterType = MT_Skeleton;
break;
}
}
void EnterBattle()
{
while (true) {
//나의 공격
int damage = playerStat.attack - monsterStat.defence;
if (damage < 0) {
damage = 0;
}
monsterStat.hp -= damage;
if (monsterStat.hp < 0) {
monsterStat.hp = 0;
}
cout << "몬스터 남은 체력 : " << monsterStat.hp << endl;
if (monsterStat.hp == 0) {
cout << "몬스터를 처치했습니다!" << endl;
WaitForNextKey();
return;
}
//몬스터의 공격
int damage2 = monsterStat.attack - playerStat.defence;
if (damage2 < 0) {
damage2 = 0;
}
playerStat.hp -= damage2;
if (playerStat.hp < 0) {
playerStat.hp = 0;
}
cout << "플레이어의 남은 체력 : " << playerStat.hp << endl;
if (playerStat.hp == 0) {
cout << "당신은 사망했습니다... GAME OVER" << endl;
WaitForNextKey();
return;
}
}
}
void WaitForNextKey()
{
cout << "계속하려면 1을 눌러주세요" << endl;
cout << ">";
int input;
cin >> input;
system("cls"); //내용을 정리
}
[게임 프로그래머 입문 올인원] C++ & 자료구조/알고리즘 & STL & 게임 수학 & Windows API & 게임 서버 -
어디부터 시작할지 막막한 게임 프로그래밍 입문자를 위한 All-In-One 커리큘럼입니다. C++, 자료구조/알고리즘, STL, 게임 수학, Windows API, 게임 서버 입문으로 이어지는 알찬 커리큘럼으로 게임 프
www.inflearn.com
'프로젝트 > [인프런] 게임 프로그래머 입문 올인원' 카테고리의 다른 글
[게임 프로그래머 입문 올인원] 동적할당과 캐스팅 : 아이템 드랍 (36강 + 38강) (0) | 2023.09.14 |
---|---|
[게임 프로그래머 입문 올인원] 포인터와 배열 : 달팽이 문제 (25강) (2) | 2023.09.07 |
[게임 프로그래머 입문 올인원] 포인터와 배열 : 로또 번호 생성기 (24강) (0) | 2023.09.07 |
[게임 프로그래머 입문 올인원] 포인터와 배열 : 배열 실습 (19강) (0) | 2023.09.06 |
[인프런] 게임 프로그래머 입문 올인원 목차 (0) | 2023.09.01 |