0. 코드 정리
맵을 랜더링하는 코드를 maze가 아닌 board로 관리한다.
1. 맵 만들기
(1-1) Board.cpp - 벽 생성
Binary Tree Maze Algorithm을 따라 size에 해당하는 맵을 만든다.
// Binary Tree 미로 생성 알고리즘
// - Mazes For Programmers
void Board::GenerateMap()
{
for (int32 y = 0; y < _size; y++)
{
for (int32 x = 0; x < _size; x++)
{
if (x % 2 == 0 || y % 2 == 0) // 첫번째 가로줄과 세로줄은 벽으로 설정
_tile[y][x] = TileType::WALL;
else
_tile[y][x] = TileType::EMPTY;
}
}
- x의 위치가 0이거나 y의 위치가 0이면 벽으로 만든다.
- 그리고 x가 짝수이거나 y가 짝수인 곳을 벽으로 만든다.
(1-2) 길 뚫기
// 랜덤으로 우측 혹은 아래로 길을 뚫는 작업
for (int32 y = 0; y < _size; y++)
{
for (int32 x = 0; x < _size; x++)
{
if (x % 2 == 0 || y % 2 == 0)
continue;
if (y == _size - 2 && x == _size - 2) // 오른쪽 아래 모서리(끝)에 도달
continue;
if (y == _size - 2) // 아래 한계
{
_tile[y][x + 1] = TileType::EMPTY; // 오른쪽으로 길 뚫기
continue;
}
if (x == _size - 2) // 우측 한계
{
_tile[y + 1][x] = TileType::EMPTY; // 아래로 길 뚫기
continue;
}
x축 상에서 타일은 0 ~ 24의 좌표를 가지고, y축 또한 0 ~ 24의 좌표를 가진다.
즉 x축에서 24번째 타일은 벽이다. 따라서 x축에서 이동가능한 우측 한계는 _size = 25 에서 2를 뺀 값이다.
y축도 동일하다.
x축 또는 y축이 한계에 도달할 때마다 아래로 혹은 오른쪽으로 길을 뚫게 지정한다.
위의 조건인 벽에 해당하지 않으면 랜덤값을 사용하여 길을 생성한다.
const int32 randValue = ::rand() % 2; // 0 or 1
if (randValue == 0) // 랜덤으로 길 생성
{
_tile[y][x + 1] = TileType::EMPTY;
}
else
{
_tile[y + 1][x] = TileType::EMPTY;
}
}
}
}
0 또는 1의 값을 받아서 기댓값이 1/2인 확률로 오른쪽 또는 아래로 길을 생성하게 해준다.
(1-3) 벽 외부, 플레이어 색, 출구 색 설정
TileType Board::GetTileType(Pos pos)
{
if (pos.x < 0 || pos.x >= _size)
return TileType::NONE;
if (pos.y < 0 || pos.y >= _size)
return TileType::NONE;
return _tile[pos.y][pos.x];
}
ConsoleColor Board::GetTileColor(Pos pos)
{
if (_player && _player->GetPos() == pos)
return ConsoleColor::YELLOW;
if (GetExitPos() == pos)
return ConsoleColor::BLUE;
TileType tileType = GetTileType(pos);
switch (tileType)
{
case TileType::EMPTY:
return ConsoleColor::GREEN;
case TileType::WALL:
return ConsoleColor::RED;
}
return ConsoleColor::WHITE;
}
(2) 플레이어 생성
(2-1) Player.h
#pragma once
class Board;
class Player
{
public:
void Init(Board* board);
void Update(uint64 deltaTick);
void SetPos(Pos pos) { _pos = pos; }
Pos GetPos() { return _pos; }
private:
Pos _pos = {};
int32 _dir = DIR_UP;
Board* _board = nullptr;
};
보드의 포인터를 받는 Init 함수와 프레임 당 업데이트를 수행하는 Update 멤버 함수를 선언한다.
SetPos 함수는 플레이어의 위치를 설정한다.
_dir은 pch.h에 정의된 enum DIR의 값을 사용한다.
(2-2) Player.cpp
#include "pch.h"
#include "Player.h"
#include "Board.h"
void Player::Init(Board* board)
{
_pos = board->GetEnterPos();
_board = board;
}
void Player::Update(uint64 deltaTick)
{
}
플레이어의 시작 위치는 보드의 GetEnterPos 함수를 사용하여 받는다.
그리고 nullptr로 초기화된 _board 멤버 변수의 값을 Board 클래스의 포인터로 설정한다.
(3) Maze.cpp
#include "pch.h"
#include <iostream>
#include "ConsoleHelper.h"
#include "Board.h"
#include "Player.h"
Board board;
Player player;
int main()
{
::srand(static_cast<unsigned>(time(nullptr)));
board.Init(25, &player);
player.Init(&board);
srand를 사용하여 시드를 시간에 따른 변수로 받는다.
Board.Init(int32 size, Player* player)
이 때 Board 클래스의 Init 함수를 사용하여 크기와 player의 포인터로 초기화한다.
player도 board의 포인터를 받도록 초기화한다.
이후는 무한 루프를 통해서 프레임마다 플레이어(의 위치)를 업데이트 해주고, 보드를 렌더링하는 코드를 작성한다.
uint64 lastTick = 0;
while (true)
{
#pragma region 프레임 관리
const uint64 currentTick = ::GetTickCount64();
const uint64 deltaTick = currentTick - lastTick;
lastTick = currentTick;
#pragma endregion
// 입력
// 로직
player.Update(deltaTick);
// 렌더링
board.Render();
}
}
'자료구조와 알고리즘 > 예제' 카테고리의 다른 글
3-4. A*(A-Star) 알고리즘 (0) | 2023.07.11 |
---|---|
3-3. 우선순위 큐 구현 연습 (0) | 2023.07.10 |
2-4. BFS를 이용한 길 찾기 구현 (0) | 2023.07.07 |
1-2. 미로 만들기(2) - 오른손 법칙(우수법) (0) | 2023.06.27 |
1-1. Maze 구현을 위한 환경설정 (0) | 2023.06.27 |