지난 시간에는 플레이어(블럭)의 움직임에 관련하여 알아보았습니다.
오늘은 플레이어(블럭) 충돌 판정에 대해서 알아보겠습니다.
충돌 판정
지난 시간에 했던 프로젝트를 실행해서 움직여보면 좌, 우, 하단 끝에 도달하여도 계속 가는 것을 볼 수 있습니다.
이것을 방지하기 위해서는 충돌 판정을 통해서 움직이지 못하도록 해야합니다.
그럼 어떻게 하면 충돌 판정을 시킬 수 있을 까요?
void InputKey()
{
int nKey = 0;
if (_kbhit() > 0)
{
nKey = _getch();
switch (nKey)
{
case eKeyCode::KEY_UP:
{
break;
}
case eKeyCode::KEY_DOWN:
{
g_player.AddPosition(0, 1); // <-- 움직이기
break;
}
case eKeyCode::KEY_LEFT:
{
g_player.AddPosition(-1, 0); // <-- 움직이기
break;
}
case eKeyCode::KEY_RIGHT:
{
g_player.AddPosition(1, 0); // <-- 움직이기
break;
}
case eKeyCode::KEY_SPACE:
{
break;
}
case eKeyCode::KEY_R:
{
break;
}
}
}
}
현재 우리는 InputKey 함수
에서 키를 누름과 동시에 플레이어(블럭)의 좌표를 증가하도록 하였습니다.
그래서 누름과 동시에 이동을 하게 됩니다.
그럼 좌표를 증가시키기 전에 그 위치로 이동해도 되는지 확인하는 과정(충돌을 하는지 안하는지)을 거치게 되면 벽을 넘어서지 못하도록 할 수 있습니다.
먼저 이전 맵의 데이터를 기록하는 배열을 전역으로 하나 만듭니다.
// Map Data (Backup Data)
int g_nArrMapBackup[MAP_HEIGHT][MAP_WIDTH] = { 0, };
이제부터 이 배열은 이전의 테트리스 맵을 백업
하도록 할겁니다.
(이전이라고 함은 현재 블럭이 ㄴ 이고 이전 블럭이 ㅡ 일 때 ㄴ 블럭 이전의 맵 데이터)
그리고 충돌을 확인하는 IsCollision 함수
를 작성합니다.
// pBlock : 블럭 데이터
// coordPlayer : 블럭의 위치
bool IsCollision(int* pBlock, const COORD& coordPlayer)
{
int nColision = 0;
for (int nY = 0; nY < BLOCK_HEIGHT; ++nY)
{
for (int nX = 0; nX < BLOCK_WIDTH; ++nX)
{
// 벽 충돌 유무
nColision = pBlock[(nY * BLOCK_HEIGHT) + nX] & (g_nArrMapBackup[coordPlayer.Y + nY][coordPlayer.X + nX] << 1);
// 다른 블럭과 충돌 유무
nColision += pBlock[(nY * BLOCK_HEIGHT) + nX] & g_nArrMapBackup[coordPlayer.Y + nY][coordPlayer.X + nX];
// 벽 또는 블럭과 충돌 했다면 충돌로 판정
if (nColision > 0)
return true;
}
}
return false;
}
그리고 IsCollision 함수
를 이용하여 키가 눌렸을 때 그 위치로 이동할 수 있는지 유무를 판단하는 함수인 IsMoveAvailable 함수
를 작성합니다.
// nXAdder : 플레이어(블럭)이 이동할 X 위치(증가)
// nYAdder : 플레이어(블럭)이 이동할 Y 위치(증가)
bool IsMoveAvailable(int nXAdder, int nYAdder)
{
// 현재 플레이어의 위치
COORD coorNext = g_player.GetCursor();
// 다음 위치를 미리 시뮬레이션
coorNext.X += nXAdder;
coorNext.Y += nYAdder;
// 다음 위치로 이동한 블럭의 데이터
int* pBlock = GetRotateBlock(g_player.GetBlock(), g_player.GetDirection());
// 다음 위치로 이동 했을 때 충돌을 했는지 유무
return !IsCollision(pBlock, coorNext);
}
이제 IsMoveAvailable 함수를
이용하여 충돌 감지하여 벽을 벗어나지 못하도록 해봅시다.
void InputKey()
{
int nKey = 0;
if (_kbhit() > 0)
{
nKey = _getch();
switch (nKey)
{
case eKeyCode::KEY_UP:
{
break;
}
case eKeyCode::KEY_DOWN:
{
if (IsMoveAvailable(0, 1))
g_player.AddPosition(0, 1);
break;
}
case eKeyCode::KEY_LEFT:
{
if (IsMoveAvailable(-1, 0))
g_player.AddPosition(-1, 0);
break;
}
case eKeyCode::KEY_RIGHT:
{
if (IsMoveAvailable(1, 0))
g_player.AddPosition(1, 0);
break;
}
case eKeyCode::KEY_SPACE:
{
break;
}
case eKeyCode::KEY_R:
{
break;
}
}
}
}
그리고 이전의 테트리스 맵을 기억하는 백업용 배열
을 초기화 합시다.
void InitGame(bool bInitConsole = true)
{
// Initialize Player Data
{
// 생략 ......
}
if (bInitConsole)
{
// 생략 ......
}
// Map Backup
{
int nMapSize = sizeof(int) * MAP_WIDTH * MAP_HEIGHT;
memcpy_s(g_nArrMap, nMapSize, ORIGIN_MAP, nMapSize);
memcpy_s(g_nArrMapBackup, nMapSize, g_nArrMap, nMapSize); // <-- 백업맵 초기화
}
}
이제 실행하여 봅시다.
이렇게 벽에 닿으면 더이상 움직이지 않게 되었습니다.
다음 시간에는 블럭이 바닥에 닿았을 때 해당 블럭은 바닥에 남고 다음 블럭이 랜덤으로 생성되는 것에 대해서 알아보도록 하겠습니다.
현재 까지의 진행 프로젝트 다운로드
'Study > C++' 카테고리의 다른 글
[C++11] unordered_map (0) | 2023.03.20 |
---|---|
[C++/Console] 테트리스 만들어 보기 - 6 (바닥 충돌, 블럭 랜덤 생성) (0) | 2023.03.06 |
[C++/Console] 테트리스 만들어 보기 - 4 (플레이어(블럭) 움직임) (0) | 2023.02.09 |
[C++/Console] 테트리스 만들어 보기 - 3 (화면 출력에 대한 고찰) (0) | 2023.02.02 |
[C++/Console] 테트리스 만들어 보기 - 2 (키보드 입력 및 블럭) (0) | 2023.01.29 |