유니티 부트캠프 8기/Ch02. 프로그래밍 기초(C#)

3주차 과제1. 스네이크 게임3. 먹이 추가, 게임 종료 조건

Imperor 2025. 2. 16. 18:57

먹이 추가(먹이를 먹으면 길이+1), 종료조건을 추가하면 완성된다

 

6. 먹이 추가

        static int food_x, food_y;	//food의 좌표값을 저장 
        const string sign_Food = "☆";   // 먹이        
        static int length;  // 길이

길이는 먹을 때마다 1씩 올라간다

 

먹이 배치

        // 랜덤위치에 음식 추가
        static void Food()
        {
            bool food_crush_on = false; // food가 뱀 몸통 좌표에 생길 경우 true
            Console.WriteLine($"  Score : {score}  Last Score : {last_score}  Best Score : {best_score}");

            Random rand = new Random();

            while (true)
            {
                food_crush_on = false;
                food_x = rand.Next(1, MAP_XSIZE - 1); // 난수를 좌표값에 넣음
                food_y = rand.Next(1, MAP_YSIZE - 1);

                for (int i = 0; i < length; i++) // food가 뱀 몸통과 겹치는지 확인
                {
                    if (food_x == x[i] && food_y == y[i])
                    {
                        food_crush_on = true; // 겹치면 food_crush_on을 true로 설정
                        break;
                    }
                }

                if (food_crush_on)
                {
                    continue; // 겹쳤을 경우 while문을 다시 시작
                }

                PrintTo(MAP_X + food_x, MAP_Y + food_y, sign_Food); // 안 겹쳤을 경우 좌표값에 food를 찍고
                speed = Math.Max(50, speed - 3); // 속도 증가 (최소 50 이하로 내려가지 않도록)
                break;
            }
        }

 

점수 추가

        static int score;          //점수 저장: reset함수에 의해 초기화됨
        static int best_score = 0; //최고 점수 저장: reset함수에 의해 초기화 되지 않음 
        static int last_score = 0; //마지막 점수 저장: reset함수에 의해 초기화 되지 않음

 

 

7. 게임 종료조건(벽과 충돌, 몸통과 충돌)

게임종료

        static void GameOver()
        {
            PrintTo(MAP_X + (MAP_XSIZE / 2) - 6, MAP_Y + 5, "+----------------------+");
            PrintTo(MAP_X + (MAP_XSIZE / 2) - 6, MAP_Y + 6, "       GAME OVER        ");
            PrintTo(MAP_X + (MAP_XSIZE / 2) - 6, MAP_Y + 7, "+----------------------+");
            PrintTo(MAP_X + (MAP_XSIZE / 2) - 6, MAP_Y + 8, $" YOUR SCORE : {score}");

            if (score > best_score)
            {
                best_score = score;
                PrintTo(MAP_X + (MAP_XSIZE / 2) - 4, MAP_Y + 10, " BEST SCORE ");
            }

            Thread.Sleep(500);
            Console.ReadKey(true);
            Title();
        }

 

 

Move에 종료조건을 추가

몸통과 머리를 1칸씩 옮긴다

        // 이동
        static void Move(int dir)
        {
            // 먹이
            if (x[0] == food_x && y[0] == food_y)
            {
                score += 10;
                Food();
                length++;
                x[length - 1] = x[length - 2];
                y[length - 1] = y[length - 2];
            }
            // 벽과 충돌
            if (x[0] == 0 || x[0] == MAP_XSIZE - 1 || y[0] == 0 || y[0] == MAP_YSIZE - 1)
            {
                GameOver();
                return;
            }
            // 몸통과 충돌
            for (int i = 1; i < length; i++)
            {
                if (x[0] == x[i] && y[0] == y[i])
                {
                    GameOver();
                    return;
                }
            }
            // 충돌하지 않았다면 
            // 몸통부터 1칸씩 옮긴다
            PrintTo(MAP_X + x[length - 1], MAP_Y + y[length - 1], "  "); // 몸통 마지막을 지움
            for (int i = length - 1; i > 0; i--) /// 몸통 좌표를 한칸씩 옮김
            {
                x[i] = x[i - 1];
                y[i] = y[i - 1];
            }
            PrintTo(MAP_X + x[0], MAP_Y + y[0], sign_Body); /// 머리가 있던 곳을 몸통으로 고침
            // 머리를 1칸 옮긴다
            /// 기본 방향은 왼쪽으로 설정되어있다
            if (dir == (int)ConsoleKey.LeftArrow) --x[0]; // 방향에 따라 새로운 머리좌표(x[0], y[0])값을 변경
            if (dir == (int)ConsoleKey.RightArrow) ++x[0];
            if (dir == (int)ConsoleKey.UpArrow) --y[0];
            if (dir == (int)ConsoleKey.DownArrow) ++y[0];
            PrintTo(MAP_X + x[0], MAP_Y + y[0], sign_Head); // 새로운 머리좌표값에 머리를 그림
        }

 

 

이 상태로 실행하면, 점수메세지가 Food에서 생성되는 문제가 있다

화면 아래쪽 벽의 아래에 점수가 표시되면 좋겠다

 

        static void Food()
        {
            bool food_crush_on = false; // food가 뱀 몸통 좌표에 생길 경우 true
            PrintTo(MAP_X, MAP_Y + MAP_YSIZE, " ");		//점수표시 
            Console.WriteLine($"  Score : {score}  Last Score : {last_score}  Best Score : {best_score}");

이젠 화면 아래에 생긴다

 

일시정지 기능 추가하고 끝내면 될 듯

 

 

일시정지 추가

        static void Pause()
        {
            while (true)
            {
                if (key == (int)ConsoleKey.P)
                {
                    PrintTo(MAP_X + (MAP_XSIZE / 2) - 9, MAP_Y, "< PAUSE : PRESS ANY KEY TO RESUME > ");
                    Thread.Sleep(400);
                    PrintTo(MAP_X + (MAP_XSIZE / 2) - 9, MAP_Y, "                                    ");
                    Thread.Sleep(400);
                }
                else
                {
                    // 아무 키나 누르면 다시 게임이 재개된다
                    DrawMap();
                    return;
                }
                if (Console.KeyAvailable)
                {
                    key = (int)Console.ReadKey(true).Key;
                }
            }
        }

 

 

메인메서드에 일시정지 추가하면 끝

        static void Main(string[] args)
        {
            Title();

            while (true)
            {
                if (Console.KeyAvailable)   // 키 입력 버퍼에 키 입력을 받으면 true, 아무 입력이 없으면 false
                {
                    ConsoleKeyInfo keyInfo = Console.ReadKey(true);    // true: 입력된 키를 화면에 표시하지 않음,
                                                                       // .Key: 어떤 키가 눌렸는지 반환된다(왼쪽 화살표 누르면 ConsoleKey.LeftArrow 반환)
                    key = (int)keyInfo.Key;
                }
                Thread.Sleep(speed);

                switch (key)
                {
                    case (int)ConsoleKey.LeftArrow:
                        if (dir != (int)ConsoleKey.RightArrow) dir = (int)ConsoleKey.LeftArrow;
                        break;
                    case (int)ConsoleKey.RightArrow:
                        if (dir != (int)ConsoleKey.LeftArrow) dir = (int)ConsoleKey.RightArrow;
                        break;
                    case (int)ConsoleKey.UpArrow:
                        if (dir != (int)ConsoleKey.DownArrow) dir = (int)ConsoleKey.UpArrow;
                        break;
                    case (int)ConsoleKey.DownArrow:
                        if (dir != (int)ConsoleKey.UpArrow) dir = (int)ConsoleKey.DownArrow;
                        break;
                    case (int)ConsoleKey.Escape:
                        Environment.Exit(0);
                        break;
                    case (int)ConsoleKey.P:  // 'P' 키를 눌렀을 때 (일시정지)
                        Pause();
                        break;
                }
                key = 0;    // 입력된 키 값을 초기화

                Move(dir);
            }
        }

 

 

확인해보자