게임 개발/[AssortRock] 콘솔 게임(CUI) 설계 및 분석
[PUSH PUSH] 게임 로직 구현 - AssortRock 16일차 오프라인 수업_220928
헛둘이
2022. 9. 29. 16:17
게임 로직 변경
- C스타일의 2차원 배열을 std::vector로 변경
- 기존의 경우 메모리 할당하는 것을 Stage 사이즈에 맞게 하드코딩(8, 8)해서 넣었는데
- 이런 방식으로 갈 경우, 다른 맵을 넣었을 때 애매해지는 문제가 있음
- 그래서 메모장 맵 파일 맨 위에 맵의 x , y 크기를 넣어줌으로써 그 좌표로 맵을 할당하고,
- 그 크기로 반복문을 돌며 맵을 로드함
Stage::Load 로직 변경
Map* Stage::Load()
{
FILE* fp = nullptr;
errno_t error = fopen_s(&fp, "..\\Stages\\Stage02.txt", "rt,ccs=UTF-8");
if (error != 0)
{
std::wcout << L"스테이지 파일이 없습니다.\n";
std::wcout << L"파일 경로를 확인해주세요.\n";
exit(0);
}
wchar_t buff[64] = L"";
std::wstring x = fgetws(buff, 63, fp);
std::wstring y = fgetws(buff, 63, fp);
int mapX = std::stoi(x);
int mapY = std::stoi(y);
mMap = new Map(mapX, mapY);
for (size_t y = 0; y < mapY; y++)
{
fgetws(buff, 63, fp);
for (size_t x = 0; x < mapX; x++)
{
if (buff[x] == L'ㅤ' || buff[x] == L'▩')
mMap->SetGameObjectInMap(x, y, buff[x]);
else
CreateGameObject(buff[x], x, y);
}
}
fclose(fp);
return mMap;
}
- int mapX, int mapY 부분이 메모장 맨 위에서 값을 긁어오는 부분
- CreateGameObject는 메모장에 있는 Ball과 Player를 객체로 매핑하는 함수
- 벽과 공백이 아니라면 GameObject이므로 map에 있는 GameObject 배열에 할당한다.
void Stage::CreateGameObject(wchar_t type, int x, int y)
{
switch (type)
{
case L'★':
{
Player* player = new Player(Pos(x,y));
mMap->AddGameObject(dynamic_cast<GameObject*>(player));
}
break;
case L'●':
{
Ball* ball = new Ball(Pos(x, y));
mMap->AddGameObject(dynamic_cast<GameObject*>(ball));
}
break;
case L'◇':
{
House* house = new House(Pos(x, y));
mMap->AddGameObject(dynamic_cast<GameObject*>(house));
}
break;
default:
break;
}
}
- switch-case 문을 통해 문자에 따라 객체, 좌표를 부여하는 부분
돌을 미는 로직 추가
- 기존 구조에서 돌을 미는 로직을 추가하는 부분
- 내가 처음 했던 방식은 어차피 플레이어와 맵이 상호작용하므로 맵에서 Ball의 좌표를 추출해서 상호작용했었음
- 그런데 어제 쌤이 하신 방식은 플레이어가 list<Ball*> 의 참조를 갖고 각각의 참조에 접근해서 Ball을 움직이는 것
- Ball이 static 멤버로 list<Ball*>를 갖고 생성자에서 자신의 주소를 이 list에 추가해준 뒤에
- 이 리스트를 반환하는 함수도 static list<Ball*> GetBalls()와 같이 만들었는데 너무 좋은 방법인 듯 하다.
- 객체간 상호작용을 가볍게 처리하는 방법에 대해 좀 더 생각해 볼 필요성을 느꼈다.
enum class DIRECTION
{
LEFT,
RIGHT,
UP,
DOWN,
NONE
};
#pragma once
#include "GameObject.h"
class Player : public GameObject
{
public:
Player();
Player(Pos pos);
~Player();
virtual void Update(Map* map) override;
virtual void Render() override;
private:
DIRECTION InputProcess();
private:
};
- InputProcess의 로직을 변경해서 반환값으로 방향을 반환해주는 것
- 방향을 알아야 돌맹이를 어디로 보낼지 알 수 있다.
DIRECTION Player::InputProcess()
{
DIRECTION dir = DIRECTION::NONE;
if (_kbhit())
{ //키보드 입력 확인 (true / false)
char input = _getch();
switch (input)
{
case 'W':
{
mPos.y -= 1;
dir = DIRECTION::UP;
}
break;
case 'A':
{
mPos.x -= 1;
dir = DIRECTION::LEFT;
}
break;
case 'S':
{
mPos.y += 1;
dir = DIRECTION::DOWN;
}
break;
case 'D':
{
mPos.x += 1;
dir = DIRECTION::RIGHT;
}
break;
default:
break;
}
}
return dir;
}
- 움직인 방향에 따라 dir에 방향을 넣어주고 반환함
void Player::Update(Map* map)
{
Pos prevPos = mPos;
DIRECTION dir = InputProcess();
std::list<Ball*>& balls = Ball::GetBalls();
for (std::list<Ball*>::iterator iter = balls.begin()
; iter != balls.end()
; iter++)
{
Pos ballPos = (*iter)->GetPos();
Pos prevBallPos = ballPos;
//내 위치가 볼과 같다면
if (mPos == ballPos)
{
//민 방향에 따라 임시 볼의 위치를 변경한다
switch (dir)
{
case DIRECTION::LEFT: { ballPos.x -= 1; }
break;
case DIRECTION::RIGHT:{ ballPos.x += 1; }
break;
case DIRECTION::UP: { ballPos.y -= 1; }
break;
case DIRECTION::DOWN: { ballPos.y += 1; }
break;
case DIRECTION::NONE: {}
break;
default:
break;
}
// 숙제
if (map->IsBarrier(ballPos) || map->IsBall(ballPos))
{
mPos = prevPos;
break;
}
else
{
(*iter)->SetPos(ballPos);
map->SetGameObjectInMap((*iter)->GetWChar_t(), ballPos, prevBallPos);
}
}
}
if (map->IsBarrier(mPos))
{
mPos = prevPos;
}
map->SetGameObjectInMap(mCh, mPos, prevPos);
}
- 숙제라고 주석 달아놓은 부분은 실제 돌을 움직이고, 벽을 뚫는지 등 비정상적인 동작을 체크해주는 곳
- map에 IsBarrier라는 함수가 있는데, pos를 넘겨주면 그 pos가 벽인지 확인해주는 함수
- ball이 움직일 예정인 pos가 벽이거나 볼이라면? 캐릭터도 움직이기 전으로 변경하고 break 해준다.
- 벽이 아니라면 볼을 해당 좌표로 움직여줌
- 그러면 그 밑 로직에서 캐릭터의 위치가 벽인지 확인하고 원래 로직대로 진행된다.
#pragma once
#include "Common.h"
#include "GameObject.h"
class Ball : public GameObject
{
public:
static std::list<Ball*>& GetBalls() { return mBalls; }
Ball();
Ball(Pos pos);
~Ball();
void Initialize(Pos pos = Pos(-1, -1));
virtual void Update(Map* map) override;
virtual void Render() override;
private:
static int mBallCount;
static std::list<Ball*> mBalls;
};
- static 변수(mBalls)와 함수(GetBalls)를 넣어주어 다른 오브젝트에게 Ball의 원본을 넘길 수 있도록 처리해줌