Chapter 3-3. 플레이어 이동
카테고리: Algorithm Lesson 2
인프런에 있는 Rookiss님의 [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part2: 자료구조와 알고리즘 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click
Chapter 3. 미로 준비
📜Player.cs
플레이어의 위치 결정 및 업데이트
using System;
using System.Collections.Generic;
using System.Text;
namespace Algorithm
{
class Player
{
public int PosY { get; private set; }
public int PosX { get; private set; }
Random _random = new Random();
Board _board;
public void Initialize(int posY, int posX, Board board)
{
PosX = posX;
PosY = posY;
_board = board;
}
const int MOVE_TICK = 100; // 0.1 초 마다 움직이게
int _sumTick = 0;
public void Update(int deltaTick)
{
_sumTick += deltaTick;
if (_sumTick >= MOVE_TICK)
{
_sumTick = 0;
// 여기에다가 0.1초마다 실행될 로직을 넣어 준다.
int randValue = _random.Next(0, 4); // 4 가지의 랜덤한 방향
switch (randValue)
{
case 0: // 상
if (PosY - 1 >= 0 && _board.Tile[PosY - 1, PosX] == Board.TileType.Empty)
PosY = PosY - 1;
break;
case 1: // 하
if (PosY + 1 < _board.Size && _board.Tile[PosY + 1, PosX] == Board.TileType.Empty)
PosY = PosY + 1;
break;
case 2: // 좌
if (PosX - 1 >= 0 && _board.Tile[PosY, PosX - 1] == Board.TileType.Empty)
PosX = PosX - 1;
break;
case 3: // 우
if (PosX + 1 < _board.Size && _board.Tile[PosY, PosX + 1] == Board.TileType.Empty)
PosX = PosX + 1;
break;
}
}
}
}
}
- 플레이어의 위치에 관한 기능을 담당한다. 👉
PosX
,PosY
- 플레이어의 위치를 결정할 땐 벽이면 갈 수 없고 벽이 아닐 때만 갈 수 있어서 미로 타일에 대한 정보가 필요하다. 👉
_board
- 플레이어의 위치를 결정할 땐 벽이면 갈 수 없고 벽이 아닐 때만 갈 수 있어서 미로 타일에 대한 정보가 필요하다. 👉
- Initialize
- 인수로 들어온 값으로
PosX
,PosY
,_board
초기화
- 인수로 들어온 값으로
- Update(int deltaTick)
-
플레이어의 위치
PosX
,PosY
를 업데이트 한다. 단,MOVE_TICK
시간이 경과될 때 마다만 실행- 메인 함수에서 매 프레임마다 📜Player의 이 Update(int deltaTick) 함수를 호출할 것이고 그때마다 매개 변수인
deltaTick
에 프레임 간 간격 시간을 인수로 보낼 것이다. 매 프레임 때 실행될 때마다_sumTick
에 프레임 경과 시간이 더해지고 이게MOVE_TICK
시간을 넘기면 그 때서야 실행할 것이다!- 예를 들어, 30 프레임마다 이 Update(int deltaTick) 함수가 실행 되고(1/30 = 0.033초 = 33 밀리세컨즈)마다 실행됨),
MOVE_TICK
값이 100 이라면 (100 밀리세컨즈 = 0.1초)- 대략 3 ~ 4 프레임 간격으로 Update(int deltaTick) 함수가 실행될 것이다. 33 * 4 > 100
MOVE_TICK
을 경과할 때면, 다시_sumTick
을 0 으로 초기화
- 예를 들어, 30 프레임마다 이 Update(int deltaTick) 함수가 실행 되고(1/30 = 0.033초 = 33 밀리세컨즈)마다 실행됨),
- 메인 함수에서 매 프레임마다 📜Player의 이 Update(int deltaTick) 함수를 호출할 것이고 그때마다 매개 변수인
- 4 개의 방향 중 랜덤하게 선택하여 그 방향으로 갈 수 있다면 플레이어를 이동시킨다.
- 그 방향이 갈수 있는 곳인지(벽이 아닌 곳인지), 타일 인덱스를 초과하는 곳은 아닌지 먼저 체크하고
- 갈 수 있다면 해당 방향으로 이동.
- 그 방향이 갈수 있는 곳인지(벽이 아닌 곳인지), 타일 인덱스를 초과하는 곳은 아닌지 먼저 체크하고
-
📜Board.cs
미로에 관한 정보, 미로 렌더링
using System;
using System.Collections.Generic;
using System.Text;
namespace Algorithm
{
class Board
{
const char CIRCLE = '\u25cf';
public TileType[,] Tile { get; private set; } // 맵의 타일들을 담을 배열
public int Size { get; private set; }
Player _player;
public enum TileType
{
Empty, // 갈 수 있는 타일
Wall, // 갈 수 없는 타일
}
public void Initialize(int size, Player player)
{
if (size % 2 == 0)
return;
_player = player;
Tile = new TileType[size, size];
Size = size;
// GenerateByBinaryTree();
GenerateBySideWinder();
}
public void Render()
{
ConsoleColor prevColor = Console.ForegroundColor;
for (int y = 0; y < Size; y++)
{
for (int x = 0; x < Size; x++)
{
// 플레이어 좌표 갖고 와서, 그 좌표랑 현재 y, x 가 일치하면 플레이어 전용 색상인 파란색으로 표시
if (y == _player.PosY && x == _player.PosX)
Console.ForegroundColor = ConsoleColor.Blue;
else
Console.ForegroundColor = GetTileColor(Tile[y, x]);
Console.Write(CIRCLE);
}
Console.WriteLine();
}
}
void GenerateBySideWinder()
{
// ...
}
void GenerateByBinaryTree()
{
// ...
}
ConsoleColor GetTileColor(TileType type)
{
// ...
}
}
}
- 미로 렌더링시 플레이어의 위치를 알아야 하므로
Player _player
📜Player 멤버 선언이 필요하다. - 미로 렌더링시 미로의 모든 타일을 검사할 때, 해당 타일이 플레이어의 현재 위치와 일치하다면 파란색으로 그려준다.
📜Prdogram.cs
메인 함수. 본격 플레이. 무한 루프로 1️⃣ 입력 2️⃣ 로직 3️⃣ 렌더링 한다.
using System;
namespace Algorithm
{
class Program
{
static void Main(string[] args)
{
Board board = new Board();
Player player = new Player();
board.Initialize(25, player); // 플레이어보다 먼저 이니셜라이징이 이루어져야 함
player.Initialize(1, 1, board);
Console.CursorVisible = false;
const int WAIT_TICK = 1000 / 30; // 1000밀리세컨즈/30 = 1초/30 = 1/30초 = 33밀리세컨즈 쯤 = 30 프레임 환경에서 1 프레임당 걸리는 시간
int lastTick = 0;
while (true)
{
#region 프레임 관리
int currentTick = System.Environment.TickCount; // 밀리 세컨즈로 나타낸 현재시간. 1초 = 1000 밀리세컨즈
if (currentTick - lastTick < WAIT_TICK) // 만약 경과한 시간이 1/30초보다 작다면 아래 모든 부분을 실행하지 않고 다시 위로
continue;
int deltaTick = currentTick - lastTick; // 1프레임 지날 때마다 업데이트
lastTick = currentTick; // 마지막 측정 시간 업뎃
#endregion
// 1.입력
// 2.로직
player.Update(deltaTick);
// 3.렌더링
Console.SetCursorPosition(0, 0);
board.Render();
}
}
}
}
board.Initialize(25, player);
player.Initialize(1, 1, board);
📢 미로의 초기화가 플레이어 초기화보다 먼저 이루어져야 한다!! 📜Player 에서 플레이어의 위치를 업뎃 할 때 📜Board 의 미로 배열의 타일를 가져와 벽인지 벽이 아닌지 따져야 하기 때문이다. 이 순서를 뒤바꾼 바람에 계속 런타임 에러가 났는데 이유를 찾느라 애먹었다. 😡
4 개의 방향 중 랜덤하게 한 방향을 선택해서 갈 수 있다면 가기 때문에 굉장히.. 바보 같이.. 갔던 길 다시 되돌아가고.. 그러는 모습을 볼 수 있다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글남기기