Bamboo poop

소코반 게임을 만들어보려고 3~4시간 가량 뼈대를 만들었다. 1주일 동안 이 뼈대를 토대로 이미지나 사운드 등을 입히면서 그나마 그럴싸한 미니 게임을 완성하려고 한다. 제목을 단순히 소코반이라고 지으면 너무 빈약해보여서 푸바오가 똥을 치운다는 컨셉으로 bamboo poop 라고 게임 이름을 지었다. 

 

 


 

게임 로직 코드 

header
// 공간, 벽, 블랙홀, 블랙홀 위에 있는 플레이어, 별, 플레이어
enum Object { SPACE, WALL, HOLE, HOLE_OT_PLAYER, STAR, HOLE_OT_STAR, PLAYER };
// 이동하기 
enum Move { DEFAULT = 0, LEFT = -1, RIGHT = 1, UP = -1, DOWN = 1};

class StarCleaner
{
public:
	StarCleaner(const int _W, const int _H);   // Copy Constructor
	virtual ~StarCleaner();                    // Destructor
	bool     getMapData(const char* _NewData);
	bool     getInput(bool* IsPlay);
	bool     checkGame(bool* IsPlay);
	void     update();
	void     draw();
private:
        int      m_width;
	int      m_height;
	int      m_capacity;
	int      m_stage;
	Move     m_lr;        // 왼쪽 오른쪽 이동
	Move     m_ud;        // 위 아래 이동
	Object*  m_field;
};

 

  • Object*  m_field;
    상태(오브젝트)를 나타내는 구조체를 사용해서 2차원 배열을 나타냈다. 가로폭으로 y값을 나눈 후 x값을 더하는 식의 방법이다.

 

스테이지 입력 받기
{
	if (_NewData == NULL)
		return false;

	// 임시 좌표 tX, tY
	int tX = 0, tY = 0;
	while(tX < m_capacity)
	{
		switch (*_NewData++)
		{
		case '#': m_field[tY * m_width + tX++] = Object::WALL;   break;
		case '.': m_field[tY * m_width + tX++] = Object::HOLE;   break;
		case 's': m_field[tY * m_width + tX++] = Object::STAR;   break;
		case ' ': m_field[tY * m_width + tX++] = Object::SPACE;  break;
		case 'p': m_field[tY * m_width + tX++] = Object::PLAYER; break;
		case '\n':
			tX = 0;
			++tY;
			break;
		case '\0':
			return true;
		}
	}
	return false;
}

미리 만들어진 스테이지를 인수로 넘겨주고 스테이지를 읽고 구조체 배열에 저장하는 방식이다.

 

 

키 입력받기
bool StarCleaner::getInput(bool* IsPlay)
{
	m_lr = DEFAULT;
	m_ud = DEFAULT;
	char   temp;
	cin >> temp;
	switch (temp)
	{
		case 'a': m_lr = Move::LEFT;  return true;
		case 'd': m_lr = Move::RIGHT; return true;
		case 'w': m_ud = Move::UP;    return true;
		case 's': m_ud = Move::DOWN;  return true;
		case 'z': *IsPlay = false;
	}
	return false;
}

 

플레이어 이동시키기 및 똥 움직이기 
	// 플레이어 위치 추적
	int find = 0;
	for (find = 0; find < m_capacity; ++find)
		if (m_field[find] == Object::PLAYER || m_field[find] == Object::HOLE_OT_PLAYER)
			break;

	// 좌표 나누기 행x열
	int x = find % m_width; // x를 폭으로 나눈 나머지 
	int y = find / m_width; // y를 폭으로 나눈 몫

	int tx = x + m_lr;  // x 좌표 예상 이동 경로
	int ty = y + m_ud;  // y 좌표 예상 이동 경로

	// 좌표 최대 최소 검사
	if (tx <= 0 || ty <= 0 || tx >= m_width || ty >= m_height)
		return;

	int p  = y * m_width + x;  // 현재 값이 존재하는 1차원 인덱스 번호
	int tp = ty * m_width + tx; // 앞으로 이동해야할 목표 위치
	// 이동에 따른 사물들의 위치 변화
	if (m_field[tp] == Object::SPACE || m_field[tp] == Object::HOLE )
	{
        // 빈 공간 or 블랙홀 지점일 경우
		(m_field[tp] == Object::HOLE) ? 
			m_field[tp] = Object::HOLE_OT_PLAYER : m_field[tp] = Object::PLAYER;
		// 이전 공간이 블랙홀 위에 지점일 경우 
		(m_field[p] == Object::HOLE_OT_PLAYER) ?
			m_field[p] = Object::HOLE : m_field[p] = Object::SPACE;
	}
	else if (m_field[tp] == Object::STAR || m_field[tp] == Object::HOLE_OT_STAR)
	{
		// 2칸 앞 검사하기 위한 변수
		int tx2 = tx + m_lr;
		int ty2 = ty + m_ud;
		// 2칸 앞 좌표 최대 최소 검사
		if (tx2 <= 0 || ty2 <= 0 || tx2 >= m_width || ty2 >= m_height)
			return;
		int tp2 = ty2 * m_width + tx2;  // 2칸 앞
		if (m_field[tp2] == Object::SPACE || m_field[tp2] == Object::HOLE)
		{
			(m_field[tp2] == Object::SPACE) ?
				m_field[tp2] = Object::STAR : m_field[tp2] = Object::HOLE_OT_STAR;
			(m_field[tp] == Object::STAR) ?
				m_field[tp] = Object::PLAYER : m_field[tp] = Object::HOLE_OT_PLAYER;
			(m_field[p] == Object::PLAYER) ?
				m_field[p] = Object::SPACE : m_field[p] = Object::HOLE;
		}
	}

코드가 굉장히 난잡하다. 오브젝트 구조체 배열에서 플레이어가 되는 p값을 찾고 사전에 벽에 닿는지 체크한 후 그 인덱스를 2차원 배열로 구분해서 블럭을 이동시킬 수 있는 경우의 수를 전부 따졌다. (1칸 앞에 휴지통이 있거나 빈 공간이거나 or 2칸 앞에 빈공간이거나 휴지통이 있거나) 

 

 

 

 

 

 


'프로젝트 > BamBoo Poop' 카테고리의 다른 글

[#3] bamboo poop - 완성 단계  (0) 2022.09.12
[#2] bamboo poop - 이미지 입히기  (0) 2022.09.10