ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C# 콘솔로 스네이크 게임 찍어내기
    Misc/이상한거 2023. 8. 13. 23:00

     

    숙제라서 만들었다

    만들고 보니까 껌뻑껌뻑 거리는데 예전에 WINAPI 할때 더블 버퍼링 생각이 났다

    어렵진 않았는데 시간 박치기 구현 노가다라서 피곤했다..

    저녁까지 밖에 나갔다 왔는데 집에 와서 하는거라곤 구현 노가다라니

     

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace SnakeGame
    {
        public enum GameObjectType
        {
            BLANK,
            WALL,
            FOOD,
            SNAKE_BODY,
            SNAKE_HEAD
        }
    
        class Vector2
        {
            public int x, y;
    
            public Vector2(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        }
    
        class NormalizedVector2
        {
            private int _x, _y;
    
            public int x
            {
                get
                {
                    return _x;
                }
                set
                {
                    if (value > 1)
                    {
                        _x = 1;
                    }
                    else if (value < -1)
                    {
                        _x = -1;
                    }
                    else
                    {
                        _x = value;
                    }
                }
            }
    
            public int y
            {
                get
                {
                    return _y;
                }
                set
                {
                    if (value > 1)
                    {
                        _y = 1;
                    }
                    else if (value < -1)
                    {
                        _y = -1;
                    }
                    else
                    {
                        _y = value;
                    }
                }
            }
    
            public NormalizedVector2(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        }
    
        class Transform
        {
            public Vector2           position = new Vector2(0, 0);
            public NormalizedVector2 rotation = new NormalizedVector2(0, 0);
        }
    
        class GameObject
        {
            public Transform transform = new Transform();
            public GameObjectType type;
    
            public GameObject(Vector2 position, NormalizedVector2 rotation, GameObjectType type)
            {
                transform.position = position;
                transform.rotation = rotation;
    
                this.type = type;
            }
        }
    
        class Map
        {
            public int x { get; private set; }
            public int y { get; private set; }
    
            public GameObject[][] tiles { get; private set; }
    
            public Map(int x, int y)
            {
                this.x = x;
                this.y = y;
    
                tiles = new GameObject[y][];
    
                for(int i = 0; i < y; i++)
                {
                    tiles[i] = new GameObject[x];
                }
    
                for(int i = 0; i < y; i++)
                {
                    for(int j = 0; j < x; j++)
                    {
                        Vector2 position = new Vector2(x, y);
                        NormalizedVector2 rotation;
                        GameObject tile;
                        if (i == 0 || i+1 == y || j == 0 || j+1 == x)
                        {
                            if(i == 0 && j == 0)
                            {
                                rotation = new NormalizedVector2(-1, 1);
                            }
                            else if(i == 0 && j + 1 == x)
                            {
                                rotation = new NormalizedVector2(1, 1);
                            }
                            else if(i + 1 == y && j == 0)
                            {
                                rotation = new NormalizedVector2(-1, -1);
                            }
                            else if (i + 1 == y && j + 1 == x)
                            {
                                rotation = new NormalizedVector2(1, -1);
                            }
                            else if(j == 0)
                            {
                                rotation = new NormalizedVector2(-1, 0);
                            }
                            else if (j+1 == x)
                            {
                                rotation = new NormalizedVector2(1, 0);
                            }
                            else if (i == 0)
                            {
                                rotation = new NormalizedVector2(0, 1);
                            }
                            else
                            {
                                rotation = new NormalizedVector2(0, -1);
                            }
    
                            tile = new GameObject(position, rotation, GameObjectType.WALL);
                        }
                        else
                        {
                            rotation = new NormalizedVector2(0, 0);
                            tile = new GameObject(position, rotation, GameObjectType.BLANK);
                        }
    
                        tiles[i][j] = tile;
                    }
                }
            }
    
            public void RenderMap()
            {
                for(int i = 0; i < y; i++)
                {
                    for(int j = 0; j < x; j++)
                    {
                        if(tiles[i][j].type == GameObjectType.BLANK)
                        {
                            Console.Write(' ');
                        }
                        else if(tiles[i][j].type == GameObjectType.FOOD)
                        {
                            Console.Write('*');
                        }
                        else if(tiles[i][j].type == GameObjectType.SNAKE_HEAD)
                        {
                            Console.Write('@');
                        }
                        else if (tiles[i][j].type == GameObjectType.SNAKE_BODY)
                        {
                            Console.Write('#');
                        }
                        else if(tiles[i][j].type == GameObjectType.WALL)
                        {
                            if((tiles[i][j].transform.rotation.x == -1
                               &&
                                tiles[i][j].transform.rotation.y == 0)
                               ||
                               (tiles[i][j].transform.rotation.x == 1
                               &&
                                tiles[i][j].transform.rotation.y == 0))
                            {
                                Console.Write('|');
                            }
                            else if ((tiles[i][j].transform.rotation.x == 0
                                     &&
                                      tiles[i][j].transform.rotation.y == 1)
                                     ||
                                     (tiles[i][j].transform.rotation.x == 0
                                     &&
                                      tiles[i][j].transform.rotation.y == -1))
                            {
                                Console.Write('~');
                            }
                            else if (tiles[i][j].transform.rotation.x == -1
                               &&
                               tiles[i][j].transform.rotation.y == 1)
                            {
                                Console.Write('+');
                            }
                            else if (tiles[i][j].transform.rotation.x == 1
                               &&
                               tiles[i][j].transform.rotation.y == 1)
                            {
                                Console.Write('+');
                            }
                            else if (tiles[i][j].transform.rotation.x == 1
                               &&
                               tiles[i][j].transform.rotation.y == -1)
                            {
                                Console.Write('+');
                            }
                            else if (tiles[i][j].transform.rotation.x == -1
                               &&
                               tiles[i][j].transform.rotation.y == -1)
                            {
                                Console.Write('+');
                            }
                        }
                    }
                    Console.Write('\n');
                }
            }
    
            public void SpawnRandomFood()
            {
                Random rand = new Random();
    
                while(true)
                {
                    int ranX = rand.Next(0, x);
                    int ranY = rand.Next(0, y);
    
    
                    if(tiles[ranY][ranX].type == GameObjectType.BLANK)
                    {
                        tiles[ranY][ranX].type = GameObjectType.FOOD;
                        break;
                    }
                }
            }
    
            public bool IsFoodAlive()
            {
                for(int i = 0; i < y; i++)
                {
                    for(int j = 0; j < x; j++)
                    {
                        if(tiles[i][j].type == GameObjectType.FOOD)
                        {
                            return true;
                        }
                    }
                }
    
                return false;
            }
        }
        
        class SnakeHead : GameObject
        {
            List<GameObject> body = new List<GameObject>();
    
            public SnakeHead(Vector2 startPosition) : base(startPosition, new NormalizedVector2(1, 0), GameObjectType.SNAKE_HEAD)
            {
                body.Add(this);
                for (int i = 1; i < 4; i++)
                {
                    body.Add(new GameObject(new Vector2(transform.position.x - i, transform.position.y), transform.rotation, GameObjectType.SNAKE_BODY));
                }
            }
    
            public bool Move(Map map, NormalizedVector2 direction)
            {
                bool isCrashed = false;
    
                Vector2 lastTilePosition = body[body.Count - 1].transform.position;
    
                for (int i = body.Count - 1; i > 1; i--)
                {
                    body[i].transform.rotation = body[i - 1].transform.rotation;
    
                    body[i].transform.position = new Vector2
                        (body[i].transform.position.x + body[i].transform.rotation.x,
                         body[i].transform.position.y + body[i].transform.rotation.y);
    
                    map.tiles[body[i].transform.position.y][body[i].transform.position.x].type = body[i].type;
                }
    
                body[1].transform.rotation = transform.rotation;
                body[1].transform.position = new Vector2
                    (body[1].transform.position.x + body[1].transform.rotation.x,
                    body[1].transform.position.y + body[1].transform.rotation.y);
                map.tiles[body[1].transform.position.y][body[1].transform.position.x].type = body[1].type;
    
                transform.rotation = direction;
                transform.position.x += transform.rotation.x;
                transform.position.y += transform.rotation.y;
    
                if (map.tiles[transform.position.y + direction.y][transform.position.x + direction.x].type == GameObjectType.WALL)
                {
                    isCrashed = true;
                }
                else if(map.tiles[transform.position.y + direction.y][transform.position.x + direction.x].type == GameObjectType.SNAKE_BODY)
                {
                    isCrashed = true;
                }
                else if(map.tiles[transform.position.y + direction.y][transform.position.x + direction.x].type == GameObjectType.FOOD)
                {
                    GameObject tp = body[body.Count - 1];
                    body.Add(new GameObject(new Vector2(tp.transform.position.x - tp.transform.rotation.x, tp.transform.position.y - tp.transform.rotation.y), body[body.Count - 1].transform.rotation, GameObjectType.SNAKE_BODY));
                    lastTilePosition = body[body.Count - 1].transform.position;
                    isCrashed = false;
                }
                else
                {
                    isCrashed = false;
                }
    
                map.tiles[transform.position.y][transform.position.x].type = type;
    
                map.tiles[lastTilePosition.y][lastTilePosition.x].type = GameObjectType.BLANK;
    
                return isCrashed;
            }
        }
    
        class Program
        {
            static int gameScore = 0;
            static int highestScore = 0;
            static int foodCollected = -1;
    
            static Map map;
            static SnakeHead player;
            static ConsoleKeyInfo ipt;
            static NormalizedVector2 direction = new NormalizedVector2(1, 0);
    
            static bool applicationQuit = false;
            static bool isEnterPressed  = false;
    
            static void Main(string[] args)
            {
                Init();
                LifeCycle();
                while(applicationQuit == false);
            }
    
            static void Init()
            {
                int mapX = 50, mapY = 25;
                map = new Map(mapX, mapY);
                player = new SnakeHead(new Vector2(mapX / 2, mapY / 2));
            }
    
            static bool Update()
            {
                Console.Clear();
                if(map.IsFoodAlive() == false)
                {
                    foodCollected++;
                    map.SpawnRandomFood();
                }
                bool isCrashed = player.Move(map, direction);
                map.RenderMap();
                Console.WriteLine("=====================================================");
                Console.WriteLine("점수 : {0}        최고 점수 : {1}        먹은 수 : {2}", gameScore, highestScore, foodCollected);
                Console.WriteLine("=====================================================");
                Console.WriteLine("ESC를 누르면 종료");
                gameScore++;
                if(gameScore >= highestScore)
                {
                    highestScore = gameScore;
                }
                isEnterPressed = false;
                return isCrashed;
            }
    
            static async void LifeCycle()
            {
                bool isCrashed = false;
    
                Task iptTask = Task.Run(() =>
                {
                    while (true)
                    {
                        ipt = Console.ReadKey(true);
                        if (ipt.Key == ConsoleKey.Escape)
                        {
                            applicationQuit = true;
                            break;
                        }
                        else if (ipt.Key == ConsoleKey.Enter)
                        {
                            isEnterPressed = true;
                        }
                    }
                });
    
    
                while (applicationQuit == false)
                {
                    await Task.Delay(100);
    
                    if (isCrashed == true)
                    {
                        Console.Clear();
                        map.RenderMap();
                        Console.WriteLine("=====================================================");
                        Console.WriteLine("점수 : {0}        최고 점수 : {1}        먹은 수 : {2}", gameScore, highestScore, foodCollected);
                        Console.WriteLine("=====================================================");
                        Console.WriteLine("당신은 죽었습니다. 다시 하려면 엔터를 누르세요....");
    
                        if (isEnterPressed == true)
                        {
                            Release();
                            Init();
                            isEnterPressed = false;
                            isCrashed = false;
                        }
                    }
                    else
                    {
                        switch (ipt.Key)
                        {
                            case ConsoleKey.RightArrow:
                                direction = new NormalizedVector2(1, 0);
                                break;
                            case ConsoleKey.LeftArrow:
                                direction = new NormalizedVector2(-1, 0);
                                break;
                            case ConsoleKey.UpArrow:
                                direction = new NormalizedVector2(0, -1);
                                break;
                            case ConsoleKey.DownArrow:
                                direction = new NormalizedVector2(0, 1);
                                break;
                        }
                        isCrashed = Update();
                    }
                }
            }
    
            static void Release()
            {
                gameScore = 0;
                foodCollected = -1;
    
                map    = null;
                player = null;
                direction = new NormalizedVector2(1, 0);
            }
        }
    }

     

    숙제라서 한개에 다 작성했어야 했기에 그냥 한곳에 다 박았다...............

Designed by Tistory.