• 贪食蛇


    这次在工作之余用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. }  
    高山仰止, 景行行止。 四牡鲱鲱, 六辔如琴。 觏尔新婚, 以慰我心。
  • 相关阅读:
    Codeforces F. Bits And Pieces(位运算)
    一场comet常规赛的台前幕后
    【NOIP2019模拟2019.9.4】B(期望的线性性)
    「NOI2016」循环之美(小性质+min_25筛)
    【NOI2011】兔农(循环节)
    LOJ #6538. 烷基计数 加强版 加强版(生成函数,burnside引理,多项式牛顿迭代)
    noi2019感想
    7.12模拟T2(套路容斥+多项式求逆)
    CF 848E(动态规划+分治NTT)
    CF 398 E(动态规划)
  • 原文地址:https://www.cnblogs.com/davidshi/p/3340313.html
Copyright © 2020-2023  润新知