2021-08-31

C# 基于控制台的贪吃蛇

简述:利用控制台实现贪吃蛇游戏,可以退出,刷新,暂停,继续。
游戏界面截图
代码部分:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace GreedySnake
{
    class Program
    {
        public static ConsoleKey inputKey;
        static void Main(string[] args)
        {


                int var = 20;

            unsafe
            {
                
                int* p = &var;
                Console.WriteLine("Data is: {0} ", var);
                Console.WriteLine("Data is: {0} ", var.GetType().ToString());
                Console.WriteLine("Data is: {0} ", *p);
                Console.WriteLine("Address is: {0} ", (int)p);
            }



            var snake = new Snake();
            var screen = new Screen(20,40);

            Console.SetCursorPosition(3, 2);
            Console.ForegroundColor = ConsoleColor.White;
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.Title = "Juke's Snake Game";
            Console.SetWindowSize(41, 26);

            screen.Update(snake, false);
            
            if (Console.ReadKey(true).Key == ConsoleKey.S)
            {
                //New thread to detect user input
                     Thread thread_ReadKey = new Thread(ReadKey);
                     thread_ReadKey.Start();
                //New controller.
                    var controller = new Controller();
                    controller.Run(snake, screen);
            }            
        }
        static void ReadKey()
        {
            while (true)
            {
                inputKey = Console.ReadKey(true).Key;
                if (inputKey==ConsoleKey.X)return;
                Thread.Sleep(50);
            }   
        }
    }

   class Controller
    {
        direction dir = direction.right;
        bool pause = false;
        bool reset = false;
        bool dead = false;
        ConsoleKey keyValue=ConsoleKey.A;
        ConsoleKey keyTemp = ConsoleKey.A;
        public void Run(Snake snake, Screen screen)
        {

            while (true)
            {

                //Check user input key info.
                keyTemp = keyValue;
                keyValue = Program.inputKey;
                if (keyValue!=keyTemp)
                {                
                    switch (keyValue)  
                    {
                        case ConsoleKey.LeftArrow:
                            dir = direction.left;
                            break;
                        case ConsoleKey.UpArrow:
                            dir = direction.up;
                            break;
                        case ConsoleKey.RightArrow:
                            dir = direction.right;
                            break;
                        case ConsoleKey.DownArrow:
                            dir = direction.down;
                            break;
                        case ConsoleKey.X:
                            return;
                        case ConsoleKey.P:
                            pause = true;
                            break;
                        case ConsoleKey.C:
                            pause = false;
                            break;
                        case ConsoleKey.F1:
                            reset = true;
                            break;
                        default:                            
                            break;
                    }
                }
                //reset
                if (reset)
                {
                    snake = new Snake();
                    screen = new Screen(20, 40);
                    screen.Update(snake, false);
                    dir = direction.right;
                    pause = false;
                    reset = false;
                    dead  = false;
                    Program.inputKey = ConsoleKey.RightArrow;
                }

                //dead
                if (dead)continue;

                //pause
                if (pause) continue;

                //snake move, dead check,eat check,update display.              
                if (snake.Die(screen.xSize,screen.ySize))//if snake dies.
                {
                    screen.Update(snake, true);
                    dead = true;
                }
                else
                {
                    if (snake.body[1].Equals(screen.foodPos))//move or eat and move
                    {
                        snake.Move(dir,true);
                        screen.foodExist = false;
                        screen.Update_Eco(snake, false);//update display...
                    }
                    else
                    {
                        snake.Move(dir,false);
                        screen.Update_Eco(snake, true);//update display...
                    }
                    
                }              

                Thread.Sleep(300);               
            }
        }
    }
     class Snake
    {
        public Dictionary<int, Pos> body;
        public Pos tail=new Pos(0,0);
        public Snake()
        {
            body = new Dictionary<int, Pos>();
            body.Add(1, new Pos(10, 20));
            body.Add(2, new Pos(10, 19));
            body.Add(3, new Pos(10, 18));
            body.Add(4, new Pos(10, 17));
        }
        public void Move(direction dir,bool eat)
        {
            var tempx = body[body.Count].x;
            var tempy = body[body.Count].y;
            //tail.x = body[body.Count].x;
            //tail.y = body[body.Count].y;            


            for (int i = body.Count; i >=2; i--)
            {
                body[i].x = body[i - 1].x;
                body[i].y = body[i - 1].y;
            }
            switch (dir)
            {
                case direction.up:
                    body[1].x--;
                    break;
                case direction.down:
                    body[1].x++;
                    break;
                case direction.left:
                    body[1].y--;
                    break;
                case direction.right:
                    body[1].y++;
                    break;
                default:
                    break;
            }
            tail = new Pos(tempx, tempy);
            if (eat)
            {
                body.Add(body.Count + 1, tail);
            }
        }

        public bool Die(int xSize,int ySize)
        {
            // die from crash on walls
            if (body[1].x>=xSize-1 || body[1].y>=ySize-1 ||body[1].x<=0 || body[1].y<=0)return true;

            // die from eating itself,Linq used,此处新建了一个匿名类型new{int,int},做成集合,
            // 然后判断新类型在集合中的个数。如用Pos类型,数不出来。。。
            var col = body.Values.GroupBy(xyPair => new { xyPair.x, xyPair.y }).Where(xyPair => xyPair.Count() > 1);
            if (col.Count() >= 1)
            { 
                return true;
            }

            return false;
        }
    }
    class Screen
    {
        public string[,] pixes;
        public int xSize;
        public int ySize;
        public bool foodExist;
        public Pos foodPos;
        public Screen(int xSize,int ySize)
        {
            this.xSize = xSize;
            this.ySize = ySize;
            pixes = new string[xSize, ySize];
            foodExist = false;
            foodPos = new Pos(2, 2);

        }
        public void Update(Snake snake, bool dead)
        {
            for (int i = 0; i < xSize; i++)//清空
            {
                for (int j = 0; j < ySize; j++)
                {
                    pixes[i, j] = " ";
                }
            }

            if (!dead)//打印蛇及食物
            {
                for (int i = 1; i <= snake.body.Count; i++)
                {
                    pixes[snake.body[i].x, snake.body[i].y] = "*";
                }
                if (!foodExist)
                {
                    RandomFood();
                    while (snake.body.ContainsValue(foodPos)) RandomFood();
                }
                pixes[foodPos.x, foodPos.y] = "#";
                foodExist = true;
            }
            else//打印结束语
            {
                var xMiddle = xSize / 2;
                var yMiddle = ySize / 2;

                pixes[xMiddle, yMiddle - 4] = "G";
                pixes[xMiddle, yMiddle - 3] = "A";
                pixes[xMiddle, yMiddle - 2] = "M";
                pixes[xMiddle, yMiddle - 1] = "E";
                pixes[xMiddle, yMiddle] = " ";
                pixes[xMiddle, yMiddle + 1] = "O";
                pixes[xMiddle, yMiddle + 2] = "V";
                pixes[xMiddle, yMiddle + 3] = "E";
                pixes[xMiddle, yMiddle + 4] = "R";
            }

            Console.Clear();           
            for (int i = 0; i < xSize; i++)//打印所有行
            {
                for (int j = 0; j < ySize; j++)
                {
                    bool wall = i == 0 || i == xSize - 1 || j == 0 || j == ySize - 1;//Print walls by symbol
                    Console.Write(wall ? "@" : pixes[i, j]); 
                }
                Console.Write('\n');
            }
            Console.WriteLine(" Operation:");
            Console.WriteLine(" 按上下左右操作蛇的动作.");
            Console.WriteLine(" Press S = Start ,X = Exit, F1 = Reset.");
            Console.WriteLine(" Press P = Pause.,C = Continue.");
            Console.WriteLine("@ Valmet Juke @");
            Console.SetCursorPosition(0, 0);
        }

        public void Update_Eco(Snake snake, bool notEat)
        {  //print head.
                    pixes[snake.body[1].x, snake.body[1].y] = "*";
                    Console.SetCursorPosition(snake.body[1].y, snake.body[1].x);
                    Console.Write("*");
            //print tail.
            if (notEat)
            {
                    pixes[snake.tail.x, snake.tail.y] = " ";
                    Console.SetCursorPosition(snake.tail.y, snake.tail.x);
                    Console.Write(" ");
            }

            //print food to * if eaten, while # after created.  
                    if (!foodExist)
                    {  //create food
                        RandomFood();
                        while (snake.body.ContainsValue(foodPos)) RandomFood();
                        foodExist = true;
                        //print food
                        pixes[foodPos.x, foodPos.y] = "#";
                        Console.SetCursorPosition(foodPos.y, foodPos.x);
                        Console.Write("#");
                    }
                     Console.SetCursorPosition(0, 0);
        }

        private void RandomFood()
        {
            var rdm = new Random();
            foodPos.x = rdm.Next(1, xSize-2);
            foodPos.y = rdm.Next(1, ySize-2);            
        }
    }
    class Pos:IComparable
    {
        public  int x = 0;
        public  int y = 0;
        public Pos(int a, int b)
        {
            x = a;
            y = b;
        }

        public int CompareTo(object obj)
        {
            var a=obj as Pos;
            if (a.x==this.x && a.y==this.y)
            {
                return 1;
            }
            return 0;
        }
        public override bool Equals(object obj)
        {
            var a = obj as Pos;
            if (a.x == this.x && a.y == this.y)
            {
                return true;
            }
            return false;
        }
    }
    enum direction
    {
        up = 1,
        down = 2,
        left = 3,
        right = 4
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值