贪食蛇

这次在工作之余用C#写了一个简单的贪吃蛇程序,一般的都是WinForm形式的,这次弄了个控制台版本的,因为C# Console全部都是输入输出流,要在CMD窗口做这种有前台UI界面的程序应该是不适合的,但是想起之前的DOS版本的系统,我觉得应该是可以做到了,所以就花了几个晚上弄了这么一个东西,先上个截图:

界面比较简单,一个CMD窗口,其他的就是由字符构成的各种形状,做这种Console的贪吃蛇有以下几个需要注意的地方:

1.理解Console这个东西,它是一个标准的I/O输入输出流;

2.控制台有2个术语 :屏幕缓冲区和控制台窗口,我们一般获取的大小是控制台大小而不是缓冲区大小,这个可以看看MSDN;

3.关于贪吃蛇本身的有一下几个问题:如何让蛇移动?如何判断蛇吃了食物?如何判断蛇碰了边框?等等,下面就详细的说说。

首先,我想说,不管做什么程序或者软件,设计数据结构非常重要,数据结构设计好了,问题也就变的简单了,真的如此!

按照面向对象的要求,设计Snake类,由于Console程序中全部是以字符形式的,所以画Snake必须要有点,点构成线,首先设计Point类如下:

1.Point.cs

[csharp] view plaincopy
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5.   
  6. namespace Snake  
  7. {  
  8.     /// <summary>  
  9.     /// Class Point  
  10.     /// </summary>  
  11.     public class Point : IComparable<Point>  
  12.     {  
  13.         private int x = 0;  
  14.         /// <summary>  
  15.         /// Gets or sets the x  
  16.         /// </summary>  
  17.         public int X  
  18.         {  
  19.             get { return x; }  
  20.             set { x = value; }  
  21.         }  
  22.         private int y = 0;  
  23.         /// <summary>  
  24.         /// Gets or sets the y  
  25.         /// </summary>  
  26.         public int Y  
  27.         {  
  28.             get { return y; }  
  29.             set { y = value; }  
  30.         }  
  31.         /// <summary>  
  32.         /// Compare the two point  
  33.         /// </summary>  
  34.         /// <param name="other">Other point</param>  
  35.         /// <returns>-1 if x < other.X && y < other.Y , 0 if x == other.X && y == other.Y , otherwise 1</returns>  
  36.         public int CompareTo(Point other)  
  37.         {  
  38.             if (x < other.X && y < other.Y)  
  39.             {  
  40.                 return -1;  
  41.             }  
  42.             else if (x == other.X && y == other.Y)  
  43.             {  
  44.                 return 0;  
  45.             }  
  46.             else  
  47.             {  
  48.                 return 1;  
  49.             }  
  50.         }  
  51.     }  
  52. }  


 

这里需要说一下这个point继承了IComparable接口,是为了下面的比较和判断蛇是否触碰了其他物体或者自己本身,好了下面就可以设计Snake.cs类了。

2.Snake.cs

[csharp] view plaincopy
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5.   
  6. namespace Snake  
  7. {  
  8.     /// <summary>  
  9.     /// Class Snake  
  10.     /// </summary>  
  11.     public class Snake  
  12.     {  
  13.         private Point head = null;  
  14.         /// <summary>  
  15.         /// Gets or sets the snake's head  
  16.         /// </summary>  
  17.         public Point Head  
  18.         {  
  19.             get { return head; }  
  20.             set { head = value; }  
  21.         }  
  22.         private Point[] body = null;  
  23.         /// <summary>  
  24.         /// Gets or sets the snake's body  
  25.         /// </summary>  
  26.         public Point[] Body  
  27.         {  
  28.             get { return body; }  
  29.             set { body = value; }  
  30.         }  
  31.         private Point tail = null;  
  32.         /// <summary>  
  33.         /// Gets or sets the snake's tail  
  34.         /// </summary>  
  35.         public Point Tail  
  36.         {  
  37.             get { return tail; }  
  38.             set { tail = value; }  
  39.         }  
  40.     }  
  41. }  


为什么要有蛇头、蛇身和蛇尾呢?简单的来说,按照面向对象的话你会想到的,复杂的就要看代码的逻辑处理了,这里不多说了,自己体会。接下来就是食物类Food.cs。

3.Food.cs

[csharp] view plaincopy
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5.   
  6. namespace Snake  
  7. {  
  8.     /// <summary>  
  9.     /// Class Food  
  10.     /// </summary>  
  11.     public class Food  
  12.     {  
  13.         private Point position = null;  
  14.         /// <summary>  
  15.         /// Gets or sets the food's position  
  16.         /// </summary>  
  17.         public Point Position  
  18.         {  
  19.             get { return position; }  
  20.             set { position = value; }  
  21.         }  
  22.     }  
  23. }  


 

食物就是一个位置上的一个点就足够了,没有其他属性。这样基本的数据结构就构造好了,剩下的就是怎么将这些结构联系起来构造这个游戏的逻辑了,首先,进入游戏,肯定是要按方向键来控制蛇的移动的,Console里面就有这样判断键盘输入的方法和属性,如下:

[csharp] view plaincopy
 
  1. ConsoleKey key = Console.ReadKey(true).Key;  

ConsoleKey这个类里面就有属性判断是属于按下了键盘上的哪个键,这个可以看MSDN。ConsoleKey这个搞定了之后再来看看如何画出游戏界面,这个就不是太复杂,Console类里面有这样的一个方法如下:

[csharp] view plaincopy
 
  1. Console.SetCursorPosition(i, j);  


设置光标所在的位置,这样就可以再这个为写入字符了,如果没有了这个方法,那我们就需要每次蛇移动都要重新画整个界面,这样会导致一个问题:控制台窗口屏幕会一直闪,因为我们是绘制整个控制台,有了这个方法,我们只需要刷新局部区域就可以了,比如蛇移动我们只需要更新蛇的位置就可以了。 最后说一下蛇碰到食物和边框之后怎么处理,当蛇碰到食物,这时候我们就可以将食物作为当前的蛇头,之前的蛇头作为蛇的身体的第一个节点,这样蛇身长度加1,蛇尾还是原来的蛇尾;当蛇头碰到边框游戏就结束。还有,当蛇移动且没碰到食物也没碰到边框的时候,这时蛇头就变成蛇当前移动到的点,蛇身的第一个点就变成了之前的蛇头的那个点,以此类推,蛇就像前移动了一个位置。 好了,大概就这么多了,最后就是画界面,代码如下:

[csharp] view plaincopy
 
    1. /// <summary>  
    2. /// Draw console ui  
    3. /// </summary>  
    4. private void DrawConsoleUI()  
    5. {  
    6.     Console.Clear();  
    7.     Point tempPoint = null;  
    8.   
    9.     Console.SetCursorPosition(0, 0);  
    10.     Console.WriteLine("Name : " + name);  
    11.     Console.SetCursorPosition(0, 1);  
    12.     Console.WriteLine("Score : " + score);  
    13.     Console.SetCursorPosition(0, 2);  
    14.     Console.WriteLine("Press R to restart game after you losed the game, press E to exit game");  
    15.     for (int i = 0; i < uiWidth; i += 2)  
    16.     {  
    17.         Console.SetCursorPosition(i, 3);  
    18.         Console.Write(".");  
    19.     }  
    20.   
    21.     for (int i = 2; i < uiHeight; i++)  
    22.     {  
    23.         for (int j = 0; j < uiWidth; j++)  
    24.         {  
    25.             tempPoint = new Point();  
    26.             tempPoint.X = j;  
    27.             tempPoint.Y = i;  
    28.   
    29.             if (tempPoint.CompareTo(currentFood.Position) == 0)  
    30.             {  
    31.                 Console.SetCursorPosition(j, i);  
    32.                 Console.Write(GetFoodElement());  
    33.             }  
    34.             else if (tempPoint.CompareTo(currentSnake.Head) == 0)  
    35.             {  
    36.                 Console.SetCursorPosition(j, i);  
    37.                 Console.Write(GetHeadElement());  
    38.             }  
    39.             else if (IsSnakeBodyCoverPoint(currentSnake.Body, tempPoint))  
    40.             {  
    41.                 Console.SetCursorPosition(j, i);  
    42.                 Console.Write(GetBodyElement());  
    43.             }  
    44.             else if (tempPoint.CompareTo(currentSnake.Tail) == 0)  
    45.             {  
    46.                 Console.SetCursorPosition(j, i);  
    47.                 Console.Write(GetTailElement());  
    48.             }  
    49.         }  
    50.     }  
    51. }  
高山仰止, 景行行止。 四牡鲱鲱, 六辔如琴。 觏尔新婚, 以慰我心。
原文地址:https://www.cnblogs.com/davidshi/p/3340313.html