Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Archives
Today
Total
관리 메뉴

시작은 0부터

11. Console.SetCursorPosition으로 Console.Clear 대체하기, List.Add, List.Contain(), Console.KeyAvailable + 레이싱 게임 수정 중 본문

C# 학습일지

11. Console.SetCursorPosition으로 Console.Clear 대체하기, List.Add, List.Contain(), Console.KeyAvailable + 레이싱 게임 수정 중

0base 2022. 7. 16. 02:18

  while문을 돌리고 그 안에 SetCursorPosition로 적의 위치, 플레이어 위치를 찍으면서 출력하고 Clear로 콘솔창을 계속 지우면서 그리는 방법을 사용했었다. 그러나 while문 안에 DateTime.Now.Ticks 함수를 이용하여 딜레이를 주더라도 Clear를 사용하면 화면이 깜빡거리는 문제가 불가피했고, 그 깜빡거리는 정도를 개선하기 위해서는 Clear를 사용하지 않는 방법을 찾았다. (혼자 찾기 보다는 동기의 조언을 통해서 알게 되었다.)

 

Console.SetCursorPosition(0,0) 으로 Console.Clear 를 대체하기

: while문 안에 SetCursorPosition(0, 0)을 한번만 넣으면 Clear를 사용하지 않더라도 반복문이 돌 때 동안 화면이 포인트 지점인 0,0(맨위 맨왼쪽)부터 계속 그리기 시작하는 것이다. 이 방법을 사용하면 화면을 지우지 않더라도 계속 새로 그리기 때문에 화면을 덧씌움으로써 거슬리는 깜빡임문제를 해결할 수 있었다. 

 

int enemyY = 0;
Random rd = new Random();
enemyCount = 0; //적 생성 값
List<int> enemyX = new List<int>(); //적의 x값 리스트

while(true)
{
	for(curtime - oldtime < fps)
    {
    	continue;
    }
    else
    {
    	oldtime = curtime;
        Console.SetCursorPosition(0,0);
        enemyY++;
        
        if(enemyY == 0)
        {
        	enemyCount = rd.Next(1,xSize); //적의 생성 개수 설정
        	for(int i = 0; i < enemyCount; i++) 
            {
        		enemyX.Add(rd.Next(0,xSize)); // 리스트에 랜덤한 x값을 추가
            }
        }
        
        if(enemyY == ySize) // 적이 내려오는 위치가 최대로 내려오면 0을 넣어서 초기화
        {
        	enemyY = 0;
        }
        
        
        
        for(int y = 0; y < ySize; y++)
        {
        	for(int x = 0; x < xSize; x++)
            {
            	if(playerX == x && playerY == y)
                {
                	Console.Write("●");
                }
                
                else if(enemyX.Contain(x) == true && enemyY == y) //리스트에 x값이 포함되어있을 경우
                {
                	Console.Write("■");
                }
            }
        }
        
        if(enemyY == playerY)
        {
        	if(enemyX == playerX)
            {
            	break;
            }
        }
        
    }
}

 List<int> listname = new List<int>();

: 리스트 선언 형식. 리스트를 생성할 때는 리스트가 어떤 형식인지를 < > 안에 작성해야한다. 메모리에 대해 간단히 배운것을 응용해 생각해보자면 이 선언을 통해 리스트도 new를 선언하여 새로운 메모리를 할당받고 힙 영역으로 들어간다는 것을 알 수 있다.

 

listname.Add();

: 리스트에 ()안에 들어가는 값을 추가한다. listname.Add(1), listname.Add(2)를 하면 리스트 안에는 1, 2가 있는 것이다. 

 

listname.Contain();

: 리스트 안에 ()안의 값이 포함되어있는지를 참/거짓으로 구분한다. 괄호 안에 a 를 넣고 == true 를 사용하여 조건문을 만들면 리스트 안에 a가 포함되어있을 때만 실행한다는 코드를 만들 수 있다.

 

처음에 만든 코드에서는 적이 늘어날 때마다 적의 X값을 포함하는 변수와 조건문을 추가하여 코드가 불필요하게 길어졌다. 이를 개선할 수 있는 방법으로 적들의 x값을 리스트로 만들어서 리스트 중 하나라도 포함이 될 경우 해당 x값에 적을 찍어내는 방법을 사용하니 이전 코드보다는 확실히 나아졌다. 그러나 여전히 한줄로 균일하게 나온다는 문제와 적이 끝까지 떨어져야 새로 생성하는 단조로움을 극복하지 못했다.

 

  이 문제는 적의 y값을 하나의 정수(int)로 설정하고 반복문이 돌 때 마다 y값을 증가시키다가 y값이 화면의 최대 높이Y값에 도달하면 y값을 0으로 초기화하는 방법을 썼기 때문인데, 기존에 x값에 생성된 적들은 그대로 내려오면서 동시에 새로운 x값이 설정된 적들이 같은 y값을 사용하기 때문에 새로 생성된 x값(적)들마다 각기 다른 y값을 설정해줘야한다는 대안을 생각하고는 있지만 그 방법을 아직 구현하지 못했다. 위의 식을 작성하면서 List 안에 있는 기능들을 찾아보다보니 List의 기능들을 찾아보게 되었고 그 중 일부는 직접 응용해보면서 사용법을 알게 되었다.

 

 

 

입력값에 따라 반복문 안에서 플레이어 이동시키기

	if (Console.KeyAvailable == true) //키가 눌렸는지 안눌렸는지 체크
                {
                    pressB = Console.ReadKey(true);

                    switch (pressB.Key)
                    {
                        case ConsoleKey.LeftArrow:
                            if (playerX > 0)
                                playerX--;
                            break;
                        case ConsoleKey.RightArrow:
                            if (playerX < 19)
                                playerX++;
                            break;
                    }
                }

처음에 반복문안에 조건문 없이 Console.ReadKey(true);를 넣어 게임이 진행이 안된 상황을 만들기도 했다. 원인은 ReadKey() 함수 때문에 반복문 안에서 입력처리를 받을 때까지 대기하는 문제가 생겼기 때문이었다. 실시간으로 움직이되, 키를 입력받았을 때만 플레이어의 좌표를 움직이기 위해서 넣은 조건문이 위와 같다.

 

Console.KeyAvailable == true/false;

: 콘솔창에서 키입력 여부를 구분하는 함수다. 콘솔창에서 무언가 키를 눌렀다면 참, 아무키도 누르지 않았다면 거짓. 이 식을 반복문 안에 넣어주면 입력값을 받지 않더라도 반복문 안에서 입력을 기다리는 문제를 방지할 수 있다.

 

a = Console.ReadKey(true);

: 콘솔창에 입력값이 있다면 그 값을 변수 a에 넣는다. 

 

switch ( a.Key )

: 입력값인 a의 값에 따라 조건문을 형성하는 식이다. case 0 에 a 를 넣고 case 1에 d 를 넣으면, 키보드 a를 눌렀을 때 조건0이 실행되고, 키보드 b 를 눌렀을 때 조건1이 실행되는 방식이다.

 

여전히 갈 길은 멀고, 진전은 체감되지 않지만 제작 과정에서 새로운 함수들과 여러 기능들을 알게 되는 것 같다. 교수님의 말씀처럼 계속 실습해보는 것이 가장 좋은 학습방법인 것 같다.