1. 오른손 법칙
미로를 탈출할 때 오른쪽 벽에 손을 대고 벽을 따라가면 언젠가는 탈출한다는 법칙이다.
player의 진행방향을 기준으로 오른쪽으로 갈 수 있는지, 바라보고 있는 방향으로 갈 수 있는지 체크한다.
(1) player.h
#pragma once
class Board;
class Player
{
enum
{
MOVE_TICK = 100 // 100ms 당 한 번 이동하게 설정
};
public:
void Init(Board* board);
void Update(uint64 deltaTick); // 프레임마다 이동
void SetPos(Pos pos) { _pos = pos; } // 위치 변경
Pos GetPos() { return _pos; } // 위치 반환
bool CanGo(Pos pos); // 갈 수 있는지 판단
private:
Pos _pos = {};
int32 _dir = DIR_UP; // 바라보고 있는 방향
Board* _board = nullptr; // 보드의 포인터를 받기 위한 변수
vector<Pos> _path; // 경로를 배열로 받음
int32 _pathIndex = 0;
uint32 _sumTick = 0; // 업데이트 틱을 계산
};
MOVE_TICK이라는 enum을 하나 만들고 플레이어의 진행여부를 판단하는 CanGo boolean를 만든다.
그리고 플레이어가 너무 빠르게 이동하지 않도록 속도를 조절할 수 있게 하는 _sumTick 멤버변수를 만든다.
(2) Player.cpp
(2-1) 플레이어 초기화
먼저 보드 멤버변수에 보드 클래스의 포인터를 저장한다.
또 _pos에 보드 클래스의 위치를 받는 함수를 이용하여 위치를 받는다.
동적배열 _path를 사용하여 플레이어의 움직임을 계측한다.
front 배열을 통해 플레이어의 위치를 지정할 수 있게 한다.
void Player::Init(Board* board)
{
_pos = board->GetEnterPos();
_board = board;
Pos pos = _pos;
_path.clear();
_path.push_back(pos);
// 목적지 도달 전까지 계속 실행
Pos dest = board->GetExitPos();
Pos front[4] =
{ // { y, x }
// UP
Pos { -1 , 0},
// LEFT
Pos { 0 , -1},
// DOWN
Pos { 1 , 0},
// RIGHT
Pos { 0 , 1},
};
여기에서 y 좌표는 아래로 갈수록 +, x 좌표는 오른쪽으로 갈수록 + 이다.
(2-2) 갈 수 있는지 판단
bool Player::CanGo(Pos pos)
{ // 타일이 EMPTY일 때만 진행 가능
TileType tileType = _board->GetTileType(pos);
return tileType == TileType::EMPTY;
}
(2-3) 회전 후 전진
플레이어가 바라보는 방향에 따라 회전하게 하는 방법이다.
// 오른쪽 방향으로 90도 회전
switch (_dir)
{
case DIR_UP: // 0
_dir = DIR_RIGHT;
case DIR_LEFT: // 1
_dir = DIR_UP;
case DIR_DOWN: // 2
_dir = DIR_LEFT;
case DIR_RIGHT: // 3
_dir = DIR_DOWN;
}
이 코드를 사용하여 구현할 수 있지만, 코드를 더 간편하게 할 수 있다.
int32 newDir = (_dir - 1 + DIR_COUNT) % DIR_COUNT;
newDir을 사용하면
while (pos != dest)
{
// 1. 바라보는 방향 기준으로 오른쪽으로 갈 수 있는지 확인
int32 newDir = (_dir - 1 + DIR_COUNT) % DIR_COUNT;
if (CanGo(pos + front[newDir]))
{
// 오른쪽 방향으로 90도 회전
_dir = newDir;
// 앞으로 한 보 전진
pos += front[_dir];
// 변화한 좌표 기록
_path.push_back(pos);
}
// 2. 바라보는 방향 기준으로 전진할 수 있는지 확인
else if (CanGo(pos + front[_dir]))
{
// 앞으로 한 보 전진
pos += front[_dir];
// 변화한 좌표 기록
_path.push_back(pos);
}
else
{
// 왼쪽 방향으로 90도 회전
_dir = (_dir + 1) % DIR_COUNT;
}
}
(2-4) 매 틱마다 업데이트
void Player::Update(uint64 deltaTick)
{ // 0.1초 지연
if (_pathIndex >= _path.size())
return;
_sumTick += deltaTick;
if (_sumTick >= MOVE_TICK)
{
_sumTick = 0;
_pos = _path[_pathIndex];
_pathIndex++;
}
}
'자료구조와 알고리즘 > 예제' 카테고리의 다른 글
3-4. A*(A-Star) 알고리즘 (0) | 2023.07.11 |
---|---|
3-3. 우선순위 큐 구현 연습 (0) | 2023.07.10 |
2-4. BFS를 이용한 길 찾기 구현 (0) | 2023.07.07 |
1-2. 미로 만들기(1) - Binary Maze Algorithm (0) | 2023.06.27 |
1-1. Maze 구현을 위한 환경설정 (0) | 2023.06.27 |