본문 바로가기
C#

[C#] 미로 만들기와 길찾기 알고리즘 Part 2 : Player 만들기

by Kangworld 2021. 8. 30.
반응형

인트로

C# 콘솔 프로그래밍으로 미로를 만들고 BFS, A* 알고리즘으로 미로의 출구를 찾는 프로그램을 작성하려 한다.

 

Part2에선 플레이어를 미로에 추가하려 한다.

 

(+ Visual Studio 기준으로 포스팅을 이어나갈 예정입니다.)

 

Player 클래스 추가

Player 클래스 추가

화면에 미로를 Render 하는 것은 Board의 기능이다. 그렇다면 Player 위치를 Board가 어떻게든 알고 있는 상태에서 Render시 플레이어 위치를 다른 색으로 표시하면 된다.

더보기
class Board
{
    ...

    Player _player;
	
    ...
    
    public void InitializeBoard(int size, Player player)
    {
    	...
        
        _player = player;

        ...
    }
}

class Program
{
    static void Main(string[] args)
    {
		...
        
        Board board = new Board();
        Player player = new Player();

        board.InitializeBoard(25, player);
        
        ...
    }
}

 

Render시 위치정보를 알아야 하므로 Player 클래스에 Player의 좌표를 담을 프로퍼티를 정의해야 한다.

더보기
class Player
{
    public int PosY { get; private set; }
    public int PosX { get; private set; }

    public void InitializePlayer(int posY, int posX)
    {
        PosY = posY;
        PosX = posX;
    }
}

 

이제 Main에서 Player를 초기화해주고 Board의 Render 메서드에서 Player의 좌표를 기반으로 Player의 위치를 별도의 색으로 칠해주면 된다.

더보기
static void Main(string[] args)
{
    ...

    Board board = new Board();
    Player player = new Player();

    board.InitializeBoard(25, player);
    player.InitializePlayer(1, 1);
    
    ...
}
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();
    }

    Console.ForegroundColor = prevColor;
}

(1, 1)에 플레이어가 생성되었다.

Player 이동

길을 찾는 로직을 Player에서 해야`할지 Board에서 해야 할지 고민이 된다. 곰곰이 생각해 보면 길을 찾는 "주체"는 Player이기에 Player 내부에 길을 찾는 코드를 추가하면 된다. 그렇게 되면 Player 또한 내부에서 Board를 들고 있어야 Empty Wall을 판별해 다음 위치로 이동할 수 있다. 

더보기
static void Main(string[] args)
{
    ...

    Board board = new Board();
    Player player = new Player();

    board.InitializeBoard(25, player);
    player.InitializePlayer(1, 1, board.Size - 2, board.Size - 2, board);
    
    ...
}
class Player
{
    public int PosY { get; private set; }
    public int PosX { get; private set; }
    
    private Board _board;

    public void InitializePlayer(int posY, int posX, int destY, int destX, Board board)
    {
        PosY = posY;
        PosX = posX;
        
        _board = board;
    }
}

 

이제 Player 클래스에서 Update 메서드를 작성해 Player의 이동을 처리하고 프로그램의 메인 루프에서 Update 메서드를 호출하면 된다.

더보기
public void Update()
{
	...
}
while (true)
{
    #region 프레임 관리
    int currentTick = System.Environment.TickCount;

    //경과 시간이 1/30초보다 작다면?
    if (currentTick - lastTick < WAIT_TICK)
        continue;

    lastTick = currentTick;
    #endregion

    // 1)사용자 입력 대기

    // 2)입력과 기타 로직 처리
    player.Update();

    // 3)렌더링
    Console.SetCursorPosition(0, 0);
    board.Render();
}

 

주의할 사항은 메인 루프에서 프레임을 30 FPS로 설정했다. 즉 위와 같이 코드를 작성하면 Update문이 1/30초마다 실행되는 참사가 일어난다. Update 메서드도 별도의 Tick을 받아서 Update가 실행되는 주기를 늘려줘야 한다.

더보기
const int MOVE_TICK = 100;
private int _sumTick = 0;

public void Update(int deltaTick)
{
    _sumTick += deltaTick;
	
    // 0.1초마다 Player를 이동한다.
    if(_sumTick >= MOVE_TICK)
    {
        _sumTick = 0;
    }
}
while (true)
{
    ...
    
    int deltaTick = currentTick - lastTick;
    
    ...
    
    // 1)사용자 입력 대기

    // 2)입력과 기타 로직 처리
    player.Update(deltaTick);

    // 3)렌더링
    Console.SetCursorPosition(0, 0);
    board.Render();
}

 

이제 Update 메서드 내에 Random으로 Player 위치를 이동하는 코드를 작성하면 된다.

더보기
const int MOVE_TICK = 100;
private int _sumTick = 0;
private Random _rnd = new Random();

public void Update(int deltaTick)
{
    _sumTick += deltaTick;

    if(_sumTick >= MOVE_TICK)
    {
        _sumTick = 0;

        int rndValue = _rnd.Next(0, 5);

        switch (rndValue)
        {
            case 0: //상
                if (_board.Tile[PosY - 1, PosX] == Board.TileType.Empty)
                    PosY = PosY - 1;
                break;
            case 1: //하
                if (_board.Tile[PosY + 1, PosX] == Board.TileType.Empty)
                    PosY = PosY + 1;
                break;
            case 2: //좌
                if (_board.Tile[PosY, PosX - 1] == Board.TileType.Empty)
                    PosX = PosX - 1;
                break;
            case 3: //우
                if (_board.Tile[PosY, PosX + 1] == Board.TileType.Empty)
                    PosX = PosX + 1;
                break;
        }
    }
}

조금 어리버리한 플레이어를 만들었다!

반응형

댓글