지난 시간에는 충돌 판정에 관련하여 알아보았습니다.
오늘은 바닥 충돌(또는 블럭 충돌) 및 블럭 랜덤 생성에 대해서 알아보겠습니다.
바닥 충돌 (또는 블럭 충돌)
지난 시간에 이어서 바닥에 충돌하였을 때 감지하는 방법을 알아봅시다.
바닥을 확인하는 CheckBottom 함수
를 작성합니다.
void CheckBottom()
{
if (IsMoveAvailable(0, 1))
return;
// 다음 줄로 움직일 수 없다면 현재 블럭을 포함하여 맵에 저장
memcpy_s(g_nArrMapBackup, sizeof(int) * MAP_WIDTH * MAP_HEIGHT, g_nArrMap, sizeof(int) * MAP_WIDTH * MAP_HEIGHT);
// 플레이어의 위치를 초기 위치로 변경
g_player.SetPosition(START_POS_X, START_POS_Y);
// 플레이어의 블럭 설정
g_player.SetBlock(1);
// 플레이어의 블럭 방향 설정
g_player.SetDirection(CPlayer::eDirection::Dir0);
g_prevPlayerData = g_player;
}
이 CheckBottom 함수
는
int main(void)
{
InitGame();
while (true)
{
InputKey();
CalcPlayer();
CheckBottom(); // <-- Player가 움직인 이후에 바닥 확인
Render(3, 1);
ClearScreen();
BufferFlip();
Sleep(1);
}
DestroyGame();
return 0;
}
CalcPlayer 함수
다음에 수행합니다.
(플레이어가 움직인 이후에 바닥을 확인하는 매커니즘입니다.)
이렇게 수정하고 실행하게 되면
이렇게 바닥 또는 더 이상 내려가지 못하는 곳으로 가게 되면 다음 블럭으로 넘어가게 됩니다.
랜덤 블럭 생성
이제 블럭을 랜덤으로 생성할 수 있도록 코드를 작성하여 봅시다.
그 전에 C++에서 사용하는 랜덤 함수에 대해서 알아봅시다.
크게 2가지가 있습니다.
// C언어 기반 rand 함수 사용
#include <stdlib.h> // 랜덤 함수(srand, rand)가 있는 헤더 파일
#include <time.h> // 시간 함수(time)가 있는 헤더 파일
srand(time(NULL)); // 랜덤 시드 설정 (time(NULL)은 1970.1.1의 시간 값을 반환)
int nRand = rand() % 10; // 0 ~ 9까지 랜덤 값을 반환
C언어 기반의 랜덤 함수와
// C++11 기반의 랜덤 함수 (MT19937 사용)
#include <random> // 랜덤 함수가 들어있는 헤더파일
std::random_device rdDevice; // 랜덤 시드용 디바이스
std::mt19937 gen(rdDevice()); // 난수 생성 엔진(메르센 트위스터) 초기화
std::uniform_int_distribution<int> dist(0, 9); // 0 ~ 9 랜덤 값 생성
int nRandom = dist(gen); // 랜덤 값 생성
C++11에서 제공하는 랜덤 함수가 있습니다.
이 방법들 중 후자의 방법(C++11 기반)을 사용하도록 하겠습니다.
먼저 stConsole 구조체
에 랜덤 관련 변수를 추가합니다.
// Console Structure
struct stConsole
{
// 생략 ....
// Random Seed
random_device rdDevice;
// Random Generation
mt19937 rdGen;
// Random Distribution (블럭)
uniform_int_distribution<int> rdBlockDist;
// Random Distribution (블럭의 방향)
uniform_int_distribution<int> rdDirDist;
stConsole()
: hConsole(nullptr), hBuffer{ nullptr, }, nCurBuffer(0)
, rdGen(rdDevice()), rdBlockDist(0, 6), rdDirDist(CPlayer::eDirection::Dir0, CPlayer::eDirection::Dir270)
{}
};
그리고 랜덤으로 블럭을 생성하는 RandomBlock 함수
와 랜덤으로 블럭의 방향을 생성하는 RandomDirection 함수
를 작성합니다.
/**
블럭 랜덤 생성
*/
int RandomBlock()
{
return g_console.rdBlockDist(g_console.rdGen);
}
/**
블럭의 방향 랜덤 생성
*/
int RamdomDirection()
{
return g_console.rdDirDist(g_console.rdGen);
}
이제 모든 상황에서 블럭을 랜덤한 방향으로 생성하도록 해봅시다.
// InitGame 함수 변경
void InitGame(bool bInitConsole = true)
{
// Initialize Player Data
{
g_player.SetPosition(START_POS_X, START_POS_Y);
g_player.SetXPositionRange(-1, MAP_WIDTH);
g_player.SetYPositionRange(0, MAP_HEIGHT);
// 블럭 랜덤 생성
g_player.SetBlock(RandomBlock());
// 블럭 방향 랜덤 생성
g_player.SetDirection((CPlayer::eDirection)RamdomDirection());
g_player.SetGameScore(0);
g_player.SetGameOver(false);
g_prevPlayerData = g_player;
}
// 생략 ....
}
InitGame 함수
에서 블럭을 랜덤으로 생성하도록 변경 합니다.
// CheckBottom 함수 변경
void CheckBottom()
{
if (IsMoveAvailable(0, 1))
return;
memcpy_s(g_nArrMapBackup, sizeof(int) * MAP_WIDTH * MAP_HEIGHT, g_nArrMap, sizeof(int) * MAP_WIDTH * MAP_HEIGHT);
g_player.SetPosition(START_POS_X, START_POS_Y);
// 블럭 랜덤 생성
g_player.SetBlock(RandomBlock());
// 블럭 방향 랜덤 생성
g_player.SetDirection((CPlayer::eDirection)RamdomDirection());
g_prevPlayerData = g_player;
}
CheckBottom 함수
에서 블럭을 랜덤으로 생성하도록 변경 합니다.
이제 실행하여 봅시다.
이렇게 바닥 또는 블럭에 충돌했을 때 다음 블럭으로(랜덤하게) 나오도록 하였습니다.
다음 시간에는 자동으로 블럭이 내려오도록 하고 라인을 형성하였을 때 지워지면서 점수가 올라가도록 해보겠습니다.
현재 까지의 진행 프로젝트 다운로드
'Study > C++' 카테고리의 다른 글
[C++/Console] 테트리스 만들어 보기 - 7 (자동 하강, 블럭 회전, 라인 클리어) (1) | 2023.04.17 |
---|---|
[C++11] unordered_map (0) | 2023.03.20 |
[C++/Console] 테트리스 만들어 보기 - 5 (충돌 판정 - 벽, 블럭) (0) | 2023.02.20 |
[C++/Console] 테트리스 만들어 보기 - 4 (플레이어(블럭) 움직임) (0) | 2023.02.09 |
[C++/Console] 테트리스 만들어 보기 - 3 (화면 출력에 대한 고찰) (0) | 2023.02.02 |