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++;
	}
}