본문 바로가기

IT/유니티

5. 유니티 교육 (C++로 구현한 간단한 게임)

1. C++로 구현한 간단한 게임 


c++를 이용해서 아주 간단한 게임을 만들어 보았습니다.

system의 cls를 이용해서 프레임을 구현해 보았구요.

SetConsoleTextAttribute를이용해서 색깔을 입혀 보았습니다.


우선 코드는 다음과 같습니다.


#include<stdio.h>

#include<string.h>

#include<cstdlib>

#include<ctime>

#include<windows.h>

#include<conio.h>


#define LEFT 75

#define RIGHT 77

#define UP 72

#define DOWN 80


struct Monster

{

//이름은 10자리 이하로

char name[10];

//hp에 마이너스는 없으므로 언사인드를 사용한다.

unsigned int health;

//몬스터의 무기. 메모리 절약을 위해 1바이트만 사용한다

char weapon;

//생성위치

int pos[2];

};


struct Hero

{

//이름은 10자리 이하로

char name[10];

//hp에 마이너스는 없으므로 언사인드를 사용한다.

unsigned int health;

//몬스터의 무기. 메모리 절약을 위해 1바이트만 사용한다

char weapon;

//생성위치

int pos[2];

};



int getRandNum(int num) {

int returnValue;

returnValue = rand() % num;


return returnValue;

}


void spawnMonster(Monster* mArray, int maxNum, char mName[][20], int mapX, int mapY) {

for (int i = 0; i < maxNum; i++) {

strcpy(mArray[i].name, mName[getRandNum(10)]);

mArray[i].health = getRandNum(50000) + 10000;

mArray[i].weapon = getRandNum(4);

mArray[i].pos[0] = getRandNum(mapX);

mArray[i].pos[1] = getRandNum(mapY);

}

}


void main(void) {

//랜덤함수를 위한 설정

srand((unsigned)time(NULL));


//몬스터 최대 생성수

int maxMonsterNum = getRandNum(20) + 1;


//지도의 범위 지정

int mapX = 40;

int mapY = 15;


Hero myHero;

strcpy(myHero.name, "MyHero");

myHero.pos[0] = mapX*0.5;

myHero.pos[1] = mapY-1;


//몬스터 정보가 들어가 배열

Monster *mArray = new Monster[maxMonsterNum];


//무기 이름 배열

char weaponName[4][10] =

{ "axe", "sword" ,"gun" ,"rocket" };


//몬스터 이름 배열

char monsterName[10][20] =

{ "orc", "troll" ,"orge" ,"imp", "hell hound"

, "vampire", "imp", "warewolf", "slime", "dark elf" };



//몬스터를 생성한다.

spawnMonster(mArray, maxMonsterNum, monsterName, mapX, mapY);



//현재 괴물이 가지고 있는 무기의 종류를 화면에 출력해주는 코드를 추가하자

//switch나 if else를 사용하자

//무기의 종류는 아래와 같다

//1.도끼 2.칼 3.총 4.로켓포

//괴물의 정보를 출력할때 이름 무기 2가지만 출력해줌


/*

for (int i = 0; i < maxMonsterNum; i++) {

Monster tempMonster = mArray[i];

printf("name:%s\nweapon:%s hp:%d location:%d/%d\n",

tempMonster.name, weaponName[tempMonster.weapon], tempMonster.health

, tempMonster.pos[0], tempMonster.pos[1]);

}

*/


int turn = 0;

int maxTrun = 2;


while (true)

{

for (int y = 0; y < mapY; y++) {

for (int x = 0; x < mapX; x++) {

int isMonsterOnMap = 0;

char monstNameHead;

//몬스터 위치를 검색해서 표시해준다.

for (int i = 0; i < maxMonsterNum; i++) {

Monster tempMonster = mArray[i];

if (tempMonster.pos[0] == x && tempMonster.pos[1] == y && tempMonster.health > 0) {

monstNameHead = tempMonster.name[0];

isMonsterOnMap = i;

}

}




if (isMonsterOnMap == 0) {

if (myHero.pos[0] == x && myHero.pos[1] == y) {

SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);

printf("H");

mArray[isMonsterOnMap].health = 0;

}

else {

SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);

printf("*");

}


}

else {

if (myHero.pos[0] == x && myHero.pos[1] == y) {

SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);

printf("H");

mArray[isMonsterOnMap].health = 0;

}

else {

SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY);

printf("%c", monstNameHead);

}


}

}

printf("\n");

}


if (turn == maxTrun) {

turn = 0;

for (int i = 0; i < maxMonsterNum; i++) {

Monster *tempMonster = &mArray[i];

int randX = getRandNum(3);

if (randX == 0) {

tempMonster->pos[0] = tempMonster->pos[0] + 1;

}

else if (randX == 1) {

tempMonster->pos[0] = tempMonster->pos[0] - 1;

}


int randY = getRandNum(3);

if (randY == 0) {

tempMonster->pos[1] = tempMonster->pos[1] + 1;

}

else if (randY == 1) {

tempMonster->pos[1] = tempMonster->pos[1] - 1;

}


if (tempMonster->pos[0] >= mapX) {

tempMonster->pos[0] = mapX - 1;

}

else if (tempMonster->pos[0] < 0) {

tempMonster->pos[0] = 0;

}


if (tempMonster->pos[1] >= mapY) {

tempMonster->pos[1] = mapY - 1;

}

else if (tempMonster->pos[1] < 0) {

tempMonster->pos[1] = 0;

}


}

}

else {

++turn;

}


char c = getch();

switch (c)

{

case LEFT: myHero.pos[0] = myHero.pos[0] - 1; break;

case RIGHT: myHero.pos[0] = myHero.pos[0] + 1;  break;

case UP: myHero.pos[1] = myHero.pos[1] - 1; break;

case DOWN: myHero.pos[1] = myHero.pos[1] + 1; break;

default: break;

}


if (myHero.pos[0] >= mapX) {

myHero.pos[0] = mapX - 1;

}

else if (myHero.pos[0] < 0) {

myHero.pos[0] = 0;

}


if (myHero.pos[1] >= mapY) {

myHero.pos[1] = mapY - 1;

}

else if (myHero.pos[1] < 0) {

myHero.pos[1] = 0;

}


system("cls");

}


}





코드는 유니티교육 두번째 코드와 비슷합니다.

구조체나 함수등은 그저 그전에 쓰던걸 가져 왔구요.

이번에 구현한건 디스플레이 부분입니다.


몬스터의 포지션에 따라 화면에 표시해주시고, 영웅 구조체를 만들어서

영웅도 화면에 표시해주었습니다.


몬스터는 빨강으로 영웅은 노랑으로 표시했습니다.


방향키로 영웅을 조정할수 있고, 영웅이 빨강 몬스터를 다 잡아먹으면 게임이 클리어됩니다.


몬스터는 영웅이 3번움직이고 난후 한번 움직일수 있습니다.




2. 간단한 메뉴 만들기


간단하지만 게임을 만들었다면, 이제는 메뉴가 필요합니다.

메뉴는 단순한 반복문을 이용해서 다음과같이 만들었습니다.


#include<stdio.h>

#include<string.h>

#include<cstdlib>

#include<ctime>

#include<windows.h>

#include<conio.h>


#define LEFT 75

#define RIGHT 77

#define UP 72

#define DOWN 80


int showMenu() {

int input;

while (1) {

system("cls");


printf("1.게임시작\n");

printf("2.옵션\n");

printf("3.나가기\n");

printf("원하시는 메뉴를 입력해주세요.");

scanf("%d", &input);

fflush(stdin);


switch (input)

{

case 1:

printf("game start");

break;

case 2:

return input;

break;

case 3:

printf("bye");

return input;

break;


default:

printf("wrong input! retry plz.");

break;

}


getch();

}

}


int showOption() {

int input;


while (1) {

system("cls");


printf("1.sound\n");

printf("2.graphic\n");

printf("3.controller\n");

printf("4.back to menu\n");

printf("원하시는 메뉴를 입력해주세요.");

scanf("%d", &input);


switch (input)

{

case 1:

printf("sound");

break;

case 2:

printf("graphic");

break;

case 3:

printf("controller");

break;

case 4:

printf("enter anykey to menu");

getch();

return input;

break;


default:

printf("wrong input! retry plz.");

break;

}


getch();

}



return input;

}



void main(void) {



//랜덤함수를 위한 설정

srand((unsigned)time(NULL));


int menuInput;

int optionInput;

int isMenu = 1;


while (1) {

menuInput = showMenu();

if (menuInput == 2) {

optionInput = showOption();

if (optionInput == 4) {

menuInput == 0;

}

}

else if (menuInput == 3) {

return;

}

}


}


기본메뉴화면과 옵션메뉴화면을 따로 함수로 만들어서 유지보수 관리가 잘되게 만들어 보았습니다.

간단한 코딩에서는 함수를 사용하지 않고 단순히 코딩해도 문제가 없겠지만, 

나중을 생각하면 함수로 쪼개서 구성해놓는것이 디버깅이나 관리에 편할거 같습니다.

 




3. 간단한 커맨드입력 게임


자 이제 메뉴를 구성하는 법을 배웠으니,

이 메뉴를 이용해서 간단한 게임을 만들어 보자.

우선 소스는 다음과  같다.


#include<stdio.h>

#include<string.h>

#include<cstdlib>

#include<ctime>

#include<windows.h>

#include<conio.h>


#define LEFT 75

#define RIGHT 77

#define UP 72

#define DOWN 80



struct Character

{

char name[20];

int hp;

};


int getRandNum(int num) {

int returnValue;

returnValue = rand() % num;


return returnValue;

}


void characterInit(Character *hero, char *name, int hp) {

strcpy(hero->name, name);

hero->hp = hp;

}


void showCharater(Character *hero) {

printf("\nName: %s", hero->name);

printf("\nHP: %d", hero->hp);

printf("\n\nEnter anykey to menu");

}


void heal(Character *hero) {

hero->hp = hero->hp + getRandNum(10);

if (hero->hp > 100) {

hero->hp = 100;

}

}


void dead(Character *hero) {

printf("\n%s is dead.\nGameOver", hero->name);

}


int checkCharacter(Character *hero) {

int returnValue = 1;

if (hero->hp <= 0) {

hero->hp = 0;

dead(hero);

returnValue = 0;

}

else if (hero->hp >= 1 && hero->hp <= 40) {

printf("\n%s needs heal.", hero->name);

returnValue = 1;

}

else if (hero->hp >= 41 && hero->hp <= 100) {

printf("\n%s is ok.", hero->name);

returnValue = 2;

}

return returnValue;

}


int hit(Character *hero) {

int returnValue = 1;


hero->hp = hero->hp - (getRandNum(10)+1);


returnValue = checkCharacter(hero);

return returnValue;

}







void main(void) {



//랜덤함수를 위한 설정

srand((unsigned)time(NULL));


Character hero;


characterInit(&hero, "MyHero", 100);


int input;


while (1) {

system("cls");


printf("1.hit\n");

printf("2.heal\n");

printf("3.info\n");

printf("4.quit\n");

printf("Enter:");

scanf("%d", &input);


switch (input)

{

case 1:

if (hit(&hero) == 0) {

return;

}

else {

showCharater(&hero);

}

break;

case 2:

heal(&hero);

break;

case 3:

showCharater(&hero);

break;

case 4:

printf("bye~");

return;

break;


default:

printf("wrong input! retry plz.");

break;

}


getch();

}


}



지금까지 배웠듯이, 가능한 모든 커맨드들을 함수로 따로 만들었습니다.

기본 커맨드는 공격, 회복, 상태보기, 나가기 입니다.

공격해서 캐릭터의 체력이 0이되면 게임 오버가됩니다.


체력에따라서 회복해야한다는 메세지등을 표시합니다.


간단하지만, 결국 이런 식으로 머드게임들이 생겨나지 않았을까요?






*********************************************

죽음도 함수로 따로 만들면 좋을거 같다.

어쩌면 죽음은 그냥 데미지 받는 함수에서 간단하게 처리 할수도 있지만,

의외로 처리할것이 많을수 있는 함수라고 할수있다.


일반적인 rpg게임을 생각해보아도, 내가 죽거나 몹이 죽었을대 경험치습득이나 하락, 

아이템을 떨구거나, 어떤 무기에 죽었는지에 따라서 보여지는 효과도다를수 있고, 

이것저것 생각해야할것이 많이 있을것이다.