명품 c++ human eat food 하면서, 약간 가상함수의 개념을 살짝 익힌것 같아요 ㅠㅠ
그래도 아직 가상함수를 잘 사용할러면 좀더 이해가 필요할 것 같아요 ㅠㅠ
5개의 파일로 분리해서 만들었어요.
Game.hpp, GameController.hpp, Game.cpp, GameController.cpp, main.cpp
// Game.hpp
#ifndef __GAME_HPP__
#define __GAME_HPP__
class GameObject
{
protected:
int distance; // 한번 이동 거리
int x,y; // 현재 위치 x: 왼쪽, 오른쪽 y: 위,아래
public:
// 초기 위치와 이동거리 설정
GameObject(int startX,int startY, int distance)
: x(startX),y(startY) { this->distance=distance; }
~GameObject() {};
// 이동한 후 새로윈 위치로, x,y 변경
virtual void move()=0;
// 벽에 충돌 여부를 판단하는 메소드
virtual bool move_check(int input)=0;
// 객체의 모양을 아타내는 문자 리턴
virtual char getShape()=0;
// x,y값을 리턴하는 함수
inline int getX() { return x; }
inline int getY() { return y; }
// 이 객체가 객체 p와 충돌했으면 true 리턴
bool collide(GameObject *p);
};
// GameObject 클래스를 상속 받은 Human 클래스
class Human : public GameObject
{
public:
// Human 객체는 한번 이동 거리가 1 이므로
// 다음과 같이 생성자를 만들어줌.
Human(int startX, int startY)
: GameObject(startX,startY,1) {}
~Human() {};
virtual void move();
virtual bool move_check(int input);
virtual char getShape();
};
// GameObject 클래스를 상속 받은 Monster 클래스
class Monster : public GameObject
{
public:
// Monster 객체는 한번 이동 거리가 2이므로
// 다음과 같이 생성자를 만들어줌.
Monster(int startX, int startY)
: GameObject(startX,startY,2) {}
~Monster() {};
virtual void move();
virtual bool move_check(int input);
virtual char getShape();
};
// GameObject 클래스를 상속 받은 Food 클래스
class Food : public GameObject
{
private:
int count1; // 5번중 3번 제자리
int count2; // 5번중 2번 움직이기
public:
// Food 객체는 한번 이동거리가 1이므로
// 다음과 같이 생성자를 만들어줌.
Food(int startX, int startY)
: GameObject(startX,startY,1), count1(0),count2(0) {}
~Food() {};
virtual void move();
virtual bool move_check(int input);
virtual char getShape();
};
#endif
// GameController.hpp
#ifndef __Game_Controller_HPP__
#define __Game_Controller_HPP__
#include "Game.hpp"
// 게임의 맵과 Gameobject를 관리하는 handler 클래스
class GameController
{
private:
char map[10][20];
public:
// main함수에서 GameObject에 직접적인 접근을 하기 위해서
// public으로 선언을 해줌.
Human& h;
Monster& m;
Food& f;
public:
// Human + Monster + Food 객체
// 맵을 초기화를 시켜줌.
GameController(Human& hh,Monster& mm, Food& ff)
: h(hh), m(mm), f(ff)
{
for(int i=0;i<10;i++)
for(int j=0;j<20;j+=4)
{
map[i][j]='-'; map[i][j+1]='-';
map[i][j+2]='-'; map[i][j+3]='-';
}
}
bool Check(); // 게임 시작시 각각의 객체들의 위치 확인
void Start(); // 게임 시작 알림
void ChangeMap(); // 맵을 바꿔줌.
void DrawMap(); // 맵을 그려줌.
};
#endif
// Game.cpp
#include <iostream>
#include "Game.hpp"
using namespace std;
// 맵의 크기를 고려해서
// 벽에 부딪쳤는지 안 부딪쳤는지 확인을 함.
bool Human::move_check(int input)
{
// tmp 변수를 통해 충돌 유무를 판단후
// 값을 변조를 시킴.
int tmp;
switch (input)
{
// 왼쪽
case 1:
tmp=this->x-this->distance;
if (tmp < 0)
{
cout << "벽에 부딪쳤습니다. 다시 입력해주세요" << endl;
return false;
}
this->x-=this->distance;
break;
// 아래
case 2:
tmp=this->y+this->distance;
if (tmp > 9)
{
cout << "벽에 부딪쳤습니다. 다시 입력해주세요" << endl;
return false;
}
this->y += this->distance;
break;
// 위
case 3:
tmp=this->y-this->distance;
if (tmp < 0)
{
cout << "벽에 부딪쳤습니다. 다시 입력해주세요" << endl;
return false;
}
this->y -= this->distance;
break;
// 오른쪽
case 4:
tmp=this->x+this->distance;
if (tmp > 19)
{
cout << "벽에 부딪쳤습니다. 다시 입력해주세요" << endl;
return false;
}
this->x +=this->distance;
break;
default:
cout<<"이상한 값을 입력했씁니다. 다시 입력해주세요"<<endl;
return false;
break;
}
return true;
}
// 맵의 크기를 고려해서
// 벽에 부딪쳤는지 안 부딪쳤는지 확인을 함.
bool Monster::move_check(int input)
{
// tmp 변수를 통해 충돌 유무를 판단후
// 값을 변조를 시킴.
int tmp;
switch (input)
{
// 왼쪽
case 1:
tmp=this->x-this->distance;
if (tmp < 0)
{
// debug 용 프린트
cout << "몬스터 벽에 부딪침" << endl;
return false;
}
this->x -= this->distance;
break;
// 아래
case 2:
tmp=this->y+this->distance;
if (tmp > 9)
{
// debug 용 프린트
cout << "몬스터 벽에 부딪침" << endl;
return false;
}
this->y += this->distance;
break;
// 위
case 3:
tmp=this->y-this->distance;
if (tmp < 0)
{
// debug 용 프린트
cout << "몬스터 벽에 부딪침" << endl;
return false;
}
this->y -= this->distance;
break;
// 오른쪽
case 4:
tmp=this->x+this->distance;
if (tmp > 19)
{
// debug 용 프린트
cout << "몬스터 벽에 부딪침" << endl;
return false;
}
this->x +=this->distance;
break;
default:
break;
}
return true;
}
// 맵의 크기를 고려해서
// 벽에 부딪쳤는지 안 부딪쳤는지 확인을 함.
bool Food::move_check(int input)
{
// tmp 변수를 통해 충돌 유무를 판단후
// 값을 변조를 시킴.
int tmp;
switch (input)
{
// 왼쪽
case 1:
tmp=this->x-this->distance;
if (tmp < 0)
{
// debug용 프린트
cout << "음식이 벽에 부딪침" << endl;
return false;
}
this->x -= this->distance;
break;
// 아래
case 2:
tmp=this->y+this->distance;
if (tmp > 9)
{
// debug용 프린트
cout << "음식이 벽에 부딪침" << endl;
return false;
}
this->y += this->distance;
break;
// 위
case 3:
tmp=this->y-this->distance;
if (tmp < 0)
{
// debug용 프린트
cout << "음식이 벽에 부딪침" << endl;
return false;
}
this->y -= this->distance;
break;
// 오른쪽
case 4:
tmp=this->x+this->distance;
if (x > 19)
{
// debug용 프린트
cout << "음식이 벽에 부딪침" << endl;
return false;
}
this->x +=this->distance;
break;
default:
break;
}
return true;
}
// 다른 객체와 부딪쳤는지 확인하는 함수.
bool GameObject::collide(GameObject *p)
{
if (this->x == p->x && this->y == p->y)
return true;
else
return false;
}
// Human 움직임을 구현
void Human::move()
{
char input;
int out=0;
do
{
cout << "왼쪽(a), 아래(s), 위(d), 오른쪽(f) >> ";
cin >> input;
if(input=='a')
out=1;
else if(input=='s')
out=2;
else if(input=='d')
out=3;
else if(input=='f')
out=4;
cin.ignore();
} while (!move_check(out));
}
// Human의 형태를 리턴함.
char Human::getShape()
{
return 'H';
}
// Monster 움직임을 구현
void Monster::move()
{
int ran;
do {
ran=rand()%4+1;
} while(!move_check(ran));
}
// Monster의 형태를 리턴함
char Monster::getShape()
{
return 'M';
}
// Food 움직임을 구현
void Food::move()
{
int ran;
ran=rand()%2;
// 5번중 3번 제자리 체크
if(ran==0 && count1<3){
count1++;
return ;
}
// 5번중 2번 움직임 체크
else{
count2++;
do{
ran=rand()%4+1;
} while(!move_check(ran));
}
if(count1+count2==5){
count1=0; count2=0;
}
}
// Food 형태를 리턴함.
char Food::getShape()
{
return '@';
}
// GameController.cpp
#include <iostream>
#include "GameController.hpp"
using namespace std;
// 게임 시작시 각각의 객체들이 동일한 위치에 생성이 된다면
// 게임을 종료시키는 메소드
bool GameController::Check()
{
if(h.getX()==m.getX() && h.getY()==m.getY()){
cout<<"휴먼과 몬스터의 위치가 동일합니다."<<endl;
cout<<"게임종료"<<endl;
return false;
}
else if(h.getX()==f.getX() && h.getY()==f.getY()){
cout<<"휴먼과 음식의 위치가 동일합니다."<<endl;
cout<<"게임종료"<<endl;
return false;
}
else if(m.getX()==f.getX() && m.getY()==f.getY()){
cout<<"몬스터와 음식의 위치가 동일합니다."<<endl;
cout<<"게임종료"<<endl;
return false;
}
return true;
}
// 게임 시작을 알리는 메소드
void GameController::Start()
{
cout<<"명품 c++ 프로그래밍 책에 있는 Open Challenge 문제입니다"<<endl;
cout<<"코드 오류 및 수정 사항이 있다면, 777bareman777@gmail.com으로 문의 해주시기 바랍니다."<<endl<<endl;
cout<<"** Human의 Food 먹기 게임을 시작합니다. **"<<endl;
}
// 각각의 객체들의 위치 정보를 받아서,
// 맵을 바꿔주고 있다.
// loop unrooling을 통해 맵의 정보를 바꾸는 속도를 향상시킴.
void GameController::ChangeMap()
{
for(int i=0;i<10;i++)
for(int j=0;j<20;j+=4)
{
map[i][j]='-'; map[i][j+1]='-';
map[i][j+2]='-'; map[i][j+3]='-';
}
int x,y; // 행 과 열을 표현할 변수
// food 위치 설정
x=f.getX();y=f.getY();
map[y][x]=f.getShape();
// human 위치 설정
x=h.getX(); y=h.getY();
map[y][x]=h.getShape();
// monster 위치 설정
x=m.getX(); y=m.getY();
map[y][x]=m.getShape();
}
// loop unrooling을 통해 맵을 그리는 속도를 향상시킴.
void GameController::DrawMap()
{
for(int i=0;i<10;i++)
{
for(int j=0;j<20;j+=4)
{
cout<<map[i][j]<<map[i][j+1]
<<map[i][j+2]<<map[i][j+3];
}
cout<<endl;
}
}
// main.cpp
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include "Game.hpp"
#include "GameController.hpp"
using namespace std;
int main()
{
int randX, randY;
// Human, Monster, Food의 위치를 항상 랜덤하게 나타나게 만듬.
srand(time(NULL));
// human 위치 초기화
randX=rand()%20;randY=rand()%10;
Human h1(randX,randY);
// monster 위치 초기화
randX=rand()%20;randY=rand()%10;
Monster m1(randX,randY);
// food 위치 초기화
randX=rand()%20;randY=rand()%10;
Food f1(randX,randY);
// GameController 생성
GameController gc(h1,m1,f1);
// 게임 시작 부분
if(!gc.Check())
return 0;
gc.Start();
while(1){
// 맵의 정보를 바구고 맵을 그림.
gc.ChangeMap();
gc.DrawMap();
// 게임 오버
if(gc.h.collide(&gc.m) || gc.m.collide(&gc.f))
{
cout<<"Monster is winner!!"<<endl;
return 0;
}
// 게임 승리
else if (gc.h.collide(&gc.f))
{
cout<<"Human is winnder!!"<<endl;
return 0;
}
// 각각 객체들이 human, monster, food 순으로 움직임.
gc.h.move();
gc.m.move();
gc.f.move();
}
}