2024. 3. 9. 22:45ㆍC#/구현
다뤄야하는 객체가 2개 이상임으로 작업의 순서를 정할 필요가 있었다.
작업 순서
1. 미로 맵 제작.
2. 플레이어 캐릭터 제작.
3. 출구 지정.
4. 플레이어를 랜덤하게 스폰하고 해당 위치 저장.
5. 플레이어 움직이도록 설정.
6. 플레이어가 출구에 도달하면 루프 정지.
1. 미로 맵 제작.
1-0. 미로를 제작할 class 제작.
1-1. 미로의 크기를 입력받아 맵의 크기를 조절하도록 설정.
1-1-2. 만약 맵의 크기를 짝수로 입력하면 종료되도록 예외 처리.
1-2. 타일의 타입을 구분짓기 (wall, road, player, exit)
[이진 트리 방식]
1-3. 짝수번의 타일 타입은 Wall, 홀수 번의 타일 타입은 road가 되도록 설정.
1-4. 반복문을 사용해서 road의 타일들이 자신의 아래와 오른쪽의 Wall 타일들 중 하나를 랜덤하게 골라
road타일로 바꾸도록 설정.
1-5. 오른쪽 테두리와 인접한 곳은 아래쪽 타일을 Road로 바꾸도록 설정.
1-6. 아래쪽 테두리와 인접한 곳은 오른쪽 타일을 road로 바꾸도록 설정.
1-7. 오른쪽 아래 구석은 아무것도 바꾸지 않도록 설정.
1-8. 타일의 타입에 따라 콘솔의 텍스트 색을 변경하는 함수를 제작
1-9. 해당 함수를 이용하여 Console.ForegroundColor 를 변경하고 화면을 출력하는 함수를 제작.
enum Tile_Type //1-2.
{
Road,
Wall,
Player,
Monster,
Exit
}
internal class Maze // 1-0
{
const char Check = 'ㅁ';
protected Tile_Type[,] tile;
protected int size;
protected Random random;
public int RowIndex { get; set; }
public int ColumnIndex { get; set; }
public Maze()
{
random = new Random();
player = new Player();
}
public void InitMap(int inputSize)
{
if (inputSize %2 == 0) //1-1-2.
{
Console.WriteLine("맵의 크기는 홀수여야만 합니다.");
return;
}
this.size = inputSize; //1-1.
tile = new Tile_Type[size, size];
for (int y = 0; y < size; y++) //1-3.
{
for (int x = 0; x < size; x++)
{
if (x % 2 == 0 || y % 2 == 0)
tile[y, x] = Tile_Type.Wall;
else
tile[y, x] = Tile_Type.Road;
}
}
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
if (x % 2 == 0 || y % 2 == 0)
continue;
if (x == size - 2 && y == size - 2) //1-7.
continue;
if (y == size - 2) //1-6.
{
tile[x + 1, y] = Tile_Type.Road;
continue;
}
if (x == size - 2) //1-5.
{
tile[x, y + 1] = Tile_Type.Road;
continue;
}
if (random.Next(0, 2) == 0) //1-4.
{
tile[y, x + 1] = Tile_Type.Road;
}
else
{
tile[y + 1, x] = Tile_Type.Road;
}
}
}
}
}
public void Render() //1-9.
{
ConsoleColor preColor = Console.ForegroundColor;
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = GetTileColor(tile[i,j]);
Console.Write(Check);
}
Console.WriteLine();
}
Console.ForegroundColor= preColor;
}
ConsoleColor GetTileColor(Tile_Type type) //1-8.
{
switch (type)
{
case Tile_Type.Wall:
return ConsoleColor.White;
case Tile_Type.Road:
return ConsoleColor.Black;
case Tile_Type.Player:
return ConsoleColor.Blue;
case Tile_Type.Exit:
return ConsoleColor.Green;
case Tile_Type.Monster:
return ConsoleColor.Red;
default:
return ConsoleColor.Magenta;
}
}
2. 플레이어 캐릭터 제작.
2-0. 플레이어 class 제작.
2-1. 좌표를 받는 Setter와 좌표를 출력하는 Getter 제작.
internal class Player //2-0.
{
private int PosX { get; set; }
private int PosY { get; set; }
public void SetPlayerPosition(int posX, int posY) // 2-1.
{
this.PosX = posX;
this.PosY = posY;
}
public int GetPlayerPositionX() { return this.PosX;}
public int GetPlayerPositionY() { return this.PosY;}
}
3. 출구 지정.
3-0. 랜덤한 좌표에 출구가 spawn되도록 만들어주는 함수 제작.
3-1. x좌표와 y좌표 랜덤 설정.
3-2. 해당 좌표 타일이 Wall 인지 확인하고 없으면 해당 타일을 Exit으로 지정.
3-3. 해당 좌표를 Exit_X, Exit_Y에 저장하는 함수를 제작.
protected int ExitX;
protected int ExitY;
public void SetExitPosition(int x, int y) //3-3.
{
this.ExitX = x; this.ExitY = y;
}
//출구 랜덤 생성
public void ExitRandomSpawn() //3-0.
{
while (true)
{
int x = random.Next(0, this.size); //3-1.
int y = random.Next(0, this.size);
if (tile[x, y] == Tile_Type.Wall) continue; //3-2.
tile[x, y] = Tile_Type.Exit;
SetExitPosition(x, y);
break;
}
}
4. 플레이어를 랜덤하게 스폰하고 해당 위치 저장.
4-0. 미로 클래스에 플레이어 선언.
4-1. 플레이어에게 좌표를 전달하는 함수 제작.
4-2. 랜덤한 좌표를 지정.
4-3. 해당 좌표를 플레이어 좌표로 지정하고 플레이어 클래스에게 전달.
Player Player; //4-0.
//player = new Player();는 미로 생성자에 삽입
public void PlayerStartPosition() //4-1.
{
while (true)
{
int x = random.Next(0, this.size); //4-2.
int y = random.Next(0, this.size);
if (tile[x, y] == Tile_Type.Wall) continue;
if (tile[x, y] == Tile_Type.Exit) continue;
tile[x, y] = Tile_Type.Player;
Player.SetPlayerPosition(x, y); //4-3.
break;
}
}
5. 플레이어 움직이도록 설정.
5-0. 플레이어를 움직이도록 만드는 함수 제작.
5-1. 플레이어의 위치를 받아오기.
5-2. 입력받은 키가 무엇인지 판별하는 함수 제작.
5-3. 입력받은 키에 따라 좌표 변경.
5-4. 변경된 좌표 타일이 맵의 내부이고 road 타입인지 판별
5-5. 만약 조건을 만족하면 변경된 좌표는 player타입이 되고 기존의 좌표는 road타입으로 변경.
5-6. 플레이어 클래스에게 해당 좌표를 전송.
5-7. 플레이어가 움직였으면 true, 움직이지 않았으면 false를 반환.
enum Direction
{
None,
UP,
DOWN,
LEFT,
RIGHT
}
protected Direction direction;
static Direction GetDirectionKey(ConsoleKey key) //5-2.
{
switch(key)
{
case ConsoleKey.RightArrow:
return Direction.RIGHT;
case ConsoleKey.LeftArrow:
return Direction.LEFT;
case ConsoleKey.UpArrow:
return Direction.UP;
case ConsoleKey.DownArrow:
return Direction.DOWN;
default:
return Direction.None;
}
}
public bool MovePlayer(Direction direction) //5-0.
{
int x = Player.GetPlayerPositionX(); //5-1.
int y = Player.GetPlayerPositionY();
switch(direction) //5-3.
{
case Direction.LEFT:
y--;
break;
case Direction.RIGHT:
y++;
break;
case Direction.UP:
x--;
break;
case Direction.DOWN:
x++;
break;
}
bool insideMap = x>=0 && x<size && y>=0 && y<size; //5-4.
bool notWall = tile[x, y] != Tile_Type.Wall;
if (insideMap&¬Wall)
{
tile[Player.GetPlayerPositionX(), Player.GetPlayerPositionY()] = Tile_Type.Road;
tile[x, y] = Tile_Type.Player; //5-5.
Player.SetPlayerPosition(x, y); //5-6.
return true; //5-7.
}
return false;
}
6. 플레이어가 출구에 도달하면 루프 정지.
6-0. 플레이어가 출구에 도달했는지 판별하는 함수 제작.
6-1. 플레이어의 위치가 출구의 위치와 같은지 판별.
6-2. 만약 조건을 만족했다면 true 를 반환, 아니면 false를 반환
public bool MazeExit() //6-0.
{
bool samePositionX = Player.GetPlayerPositionX() ==ExitX; //6-1.
bool samePositionY = Player.GetPlayerPositionY() ==ExitY;
if (samePositionX && samePositionY)
{
return true; //6-2.
}
else return false;
}
Main 함수
using practice01;
using System;
class Program
{
static void Main(string[] args)
{
Maze maze = new Maze(); //미로 선언
maze.InitMap(25); //미로 맵 제작
maze.PlayerStartPosition(); //플레이어의 위치 설정
while (true)
{
Console.Clear(); //콘솔 창 클리어
maze.Render(); //미로 출력
ConsoleKeyInfo keyInfo = Console.ReadKey();
maze.InputKey(keyInfo); //입력에 따라 플레이어 이동.
bool GameEnd = maze.MazeExit(); //플레이어가 출구에 도달했는지 판별
if (GameEnd) break; //도달했으면 루프 중지
}
}
}
'C# > 구현' 카테고리의 다른 글
[ C# ] 플레이어 인벤토리 구현 (0) | 2024.03.16 |
---|---|
[ C# ] Stack 과 Queue 구현 (0) | 2024.03.13 |