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부터

10. DateTime.Now.Ticks로 딜레이 만들기, 레이싱 게임 만들기 본문

C# 학습일지

10. DateTime.Now.Ticks로 딜레이 만들기, 레이싱 게임 만들기

0base 2022. 7. 15. 00:38

DateTime.Now.Ticks

: 현재 시간의 틱을 가져오는 함수다. 틱은 천만분의 1초인데 이 틱을 가져와서 원하는 딜레이(코드 안에서는 1000이 1초로 작용해서 60프레임을 설정하고 싶다면 1000/60으로 코드를 작성한다)값을 설정하고, 설정한 딜레이값보다 작으면 continue 함수를 통해 딜레이값을 충족할 때 까지 for문을 돌려 딜레이를 만든다. 그러다 원하는 딜레이값을 충족하면 동일한 딜레이를 계속 반복해서 주어야하기 때문에 설정값을 충족한 틱값을 이전틱값에 부여한다. 그리고 틱값에 이전틱값을 뺀 값과 딜레이값을 비교하면, 딜레이값을 충족할 때 마다 틱값 - 이전틱값(=틱값) = 0 이 되어 틱값이 동일한 간격으로 초기화되는 방식이다. 

 

System.Environment.TickCounts & Int32.MaxValue;

: 틱을 가져오는 또다른 함수다. 뒤에 & Int32를 붙인 이유는 해당 함수가 음수값을 불러오는 경우도 있기 때문에 해당 문제를 막기 위한 조치다.

 

int oldTime = 0; //초기화
int fps = 1000/60; //60프레임

while(true)
{
	int curTime = DateTime.Now.Ticks; // 현재시간의 틱을 계속 대입하여 증가시킨다.
    if(curTime - oldTime < fps)
    {
    	continue; //현재시간에서 이전시간을 뺀 값이 프레임값보다 낮다면 다시 돌려보낸다.(딜레이)
    }
    else
    {
    	oldTime = curTime; //프레임값을 충족하면 현재시간을 이전시간에 대입해 다시 간격 초기화.
    }
    
    //명령문 < == 해당 명령문은 현재시간이 프레임값을 충족할 때까지 지연된다.
}

 

 

업다운 형식의 레이싱 게임을 만들어보는 과제가 주어졌다. 변수, 함수, 조건문, 반복문의 개념만 어느정도 익히고 바로 실전으로 들어가 배운것들을 최대한 활용하여 만든 조잡한 초기 완성 코드.

게임의 완성 조건은 다음과 같다.

 

1) 적(장애물) / 코인(점수)이 2개 이상 랜덤한 X값에서부터 위에서부터 내려온다.(초기 X값이 주어지면 X값은 고정)

2) 하단에 플레이어가 있고, Y값은 고정되어 있으며 키를 입력받으면 X축으로만 움직일 수 있다.

3) 코인을 먹으면 점수를 획득하고, 적과 부딪히면 게임 오버된다.

			Console.BufferHeight = Console.WindowHeight = 30;
            Console.BufferWidth = Console.WindowWidth = 20;
            int playerX = 5;
            const int playerY = 29;
            int Y = 0;
            int X = 0;
            int X2 = 0;
            int X3 = 0;
            int X4 = 0;


            Console.CursorVisible = false;
            ConsoleKeyInfo pressB;

            Random rd = new Random();


            long oldTime = 0;
            long curTime = DateTime.Now.Ticks;
            bool exist = false;
            int score = 0;
            List<int> list = new List<int>();
            while (true)
            {
                Console.Clear(); // 화면 초기화
                Console.SetCursorPosition(0, 0);
                Console.WriteLine("score : {0}", score);
                curTime = DateTime.Now.Ticks;

                if (exist == false)
                {
                    while (true) //적
                    {
                        X = rd.Next(0, 20);
                        X2 = rd.Next(0, 20);
                        X3 = rd.Next(0, 20);
                        X4 = rd.Next(0, 20);
                        if (X == X2 || X == X3 || X2 == X3
                            || X == X4 || X2 == X4 || X3 == X4)
                        {
                            continue;
                        }
                        break;
                    }
                    exist = true;
                }

                if (curTime - oldTime < 500000)
                {
                	continue;
                }
                    Y++;
                    if (Y == 30)
                    {
                        Y = 0;
                        exist = false;
                        
                    }
                    oldTime = curTime;
                }
                Console.SetCursorPosition(X, Y);
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("■");
                Console.SetCursorPosition(X2, Y);
                Console.WriteLine("■");
                Console.SetCursorPosition(X3, Y);
                Console.WriteLine("■");

                Console.SetCursorPosition(X4, Y);
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("★");



                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.SetCursorPosition(playerX, playerY);
                Console.ForegroundColor = ConsoleColor.White;
                Console.WriteLine("#");
                if (Y == playerY)
                {
                    if (playerX == X || playerX == X2 || playerX == X3)
                    {
                        break;
                    }

                    else if (playerX == X4)
                    {
                        score += 1;
                        X4 = 0;

                    }

                }
            }
            Console.Clear();
            Console.SetCursorPosition(6, 14);
            Console.WriteLine("게임오버");
            Console.ReadLine();

while문으로 끊임없이 계속 돌리면서 그 안에 SetCursorPosition 함수를 이용해 커서 위치를 불러오고 해당 위치에 적과 코인, 플레이어를 각각 이동하면서 찍는다. 그리고 while문 한바퀴가 돌 때마다 Clear 함수를 이용해 갱신하는 방법을 썼다.

그러나 이렇게 되면 while문의 반복속도가 너무 빨라서 화면 깜빡임의 정도가 매우 심하고, 오브젝트들의 위치가 육안으로 보기 힘들 정도다. 이를 개선하기 위해 반복문 안에 시간을 딜레이할 수 있는 요소를 넣어야하는데 딜레이 함수나 쓰레드 슬립 함수도 있지만, 그렇게 하면 쓰레드 전체가 딜레이가 걸리는 문제가 있을 수 있어 멀티 쓰레드를 쓰지 않으면 안되는데 그 부분은 아직 배울 단계가 아니기에 DateTime.Now.Ticks 함수를 이용해 시간차를 두는 방법을 배웠다.

(위의 코드에서는 배운 방법을 제대로 활용하지 못했다.)