C#游戏编程:《控制台小游戏系列》之《六、贪吃蛇实例》

C#winform 经典小游戏贪吃蛇V1.0(一) 关于V1.0   为什么我给这个版本定义为V1.0嘞,因为在这个版本中仅仅实现了蛇的自动行进,按键对蛇的行进方向的操作和吃掉食物蛇身的增长等操作。 但是任何事情都必须一步一步来,当我们完成这个乞丐版的贪吃蛇,就为我们版本的更新打下了基础。 思路 首先我们生成一个空白的的窗体,然后再放一个timer控件,好了我们的游戏界面就建好了。 直接写后台代码。 没错就是这么简陋, 你可能会问:”... 阅读详情

一、游戏分析

  1976年,Gremlin平台推出一款经典街机游戏Blockade,则为贪吃蛇的原型,这款简单的小游戏很受欢迎,给80后这代人带来不可磨灭的记忆。作为未来程序员的我们,玩自己设计出的贪吃蛇比玩现有的更加有趣,我们可以添加我们所想到的各种特征,即使游戏多么另类都不觉得奇怪,我的游戏我做主!
  贪吃蛇的设计并不复杂,是很多游戏编程爱好者入门的首选项目之一,老衲也一样。整观这个游戏,屏蔽掉其他花俏的特征,让我们把焦点放到这个游戏的两个主要对象上:蛇和食物。玩过这款小游戏的人(难道有人没玩过的?)都知道,为了让自己的小蛇疯狂生长,就必须东西南北寻找食物来吃,前提是不要碰上障碍物,否则蛇就挂了。蛇由玩家通过键盘方向键来控制爬行方向,而食物在蛇视野范围内随机生成,当蛇吃掉食物之后,蛇长一节,食物再次随机生成,当然,食物不会落到蛇身上,否则蛇也只好自断了结了。
  通过上述,我们不难发现玩家的主要操作是控制蛇的爬行,对于蛇对象来说,它的特征就是会爬能爬,所以如何设计蛇的爬行并且如何反馈到画面上就是我们现在需要考虑的地方。蛇的爬行方法多种多样,但在这之前,我们还必须考虑蛇的表示方法,如何用数据结构表达一条蛇?
  ■或许可以想到用线性表来存储蛇的各个节点,当蛇移动时遍厉每个节点,更新为对应爬行方向之后的新值,这样每次蛇移动一步,则动全身:所有节点都要访问一次,可以看出最后的效率一定不会太高;
  ■或许可以想到用线性表来存储蛇的各个节点,当蛇移动时根据爬行方向把新的坐标节点添加到线性表中,然后把相对的“蛇尾”节点删除,最后遍历每个节点,调整各个节点在线形表的位置,防止线形表前后出现空缺的问题。这个方法还是避免不了要动全身,效率也不高。
  ■或许可以想到用链表来存储蛇的各个节点,当蛇移动时只需要操作链头链尾指针,其他节点无须逐一访问,效率相对前面两种来说提升不少。
  然而在C#中,我们没必要考虑这么多,List<>就能很好的解决这个问题了,用List<>表达一条蛇,当蛇爬行的时候插入一个新节点,而删除相对尾端的尾节点,从而实现蛇的爬行效果;当蛇吃到食物时,只管往里添新节点即可,无须删除旧节点操作,这样蛇的身体就会生长一节。对于如何渲染蛇到画面上也是同样的思路(或许这是因为我们的蛇每个节点都是相同样式的情况),我们没有必要遍历每个节点然后把它们逐个渲染到画面上,而是采取“画头擦尾”的方式,只画改变的节点,不变的节点不需要考虑,从而使游戏性能大大提升,即使蛇的节点几千几万个,最终需要考虑的只有前后两个节点,蛇爬行起来腰不累了,吃嘛嘛香!以下用图来表达这种思想:


二、游戏实现

   根据上面的分析,我们很清晰的知道我们这个游戏主要的对象是什么了,万事开头难,分析清楚以后我们就很容易实现我们所需要的东西了,首先来看蛇类的实现。
  ///Snake类实现
[csharp]  view plain copy print ?
  1. using System;  
  2. using System.Collections.Generic;  
  3. using CEngine;  
  4. using CGraphics;  
  5.   
  6. namespace Snake  
  7. {  
  8.     /// <summary>  
  9.     /// 贪吃蛇类  
  10.     /// </summary>  
  11.     internal class Snake  
  12.     {  
  13.         #region 字段  
  14.   
  15.         /// <summary>  
  16.         /// 蛇身  
  17.         /// </summary>  
  18.         private List<CPoint> m_body;  
  19.         /// <summary>  
  20.         /// 爬行方向  
  21.         /// </summary>  
  22.         private CDirection m_dir;  
  23.         /// <summary>  
  24.         /// 蛇头  
  25.         /// </summary>  
  26.         private CPoint m_head;  
  27.         /// <summary>  
  28.         /// 蛇尾  
  29.         /// </summary>  
  30.         private CPoint m_tail;  
  31.  
  32.         #endregion  
  33.  
  34.         #region 构造函数  
  35.   
  36.         /// <summary>  
  37.         /// 构造函数  
  38.         /// </summary>  
  39.         /// <param name="len"></param>  
  40.         /// <param name="dir"></param>  
  41.         public Snake(Int32 len, CDirection dir)  
  42.         {  
  43.             this.m_dir = dir;  
  44.   
  45.             this.m_body = new List<CPoint>();  
  46.   
  47.             for (Int32 i = 0; i <= len; i++)  
  48.             {  
  49.                 m_body.Add(new CPoint(i+1, 2));  
  50.             }  
  51.   
  52.             if (m_body.Count > 0)  
  53.             {  
  54.                 m_head = m_body[m_body.Count - 1];  
  55.                 m_tail = m_body[0];  
  56.             }  
  57.         }  
  58.  
  59.         #endregion  
  60.  
  61.         #region 方法  
  62.   
  63.         /// <summary>  
  64.         /// 设置方向  
  65.         /// </summary>  
  66.         /// <param name="dir"></param>  
  67.         public void setDirection(CDirection dir)  
  68.         {  
  69.             this.m_dir = dir;  
  70.         }  
  71.   
  72.         /// <summary>  
  73.         /// 获取方向  
  74.         /// </summary>  
  75.         /// <returns></returns>  
  76.         public CDirection getDirection()  
  77.         {  
  78.             return this.m_dir;  
  79.         }  
  80.   
  81.         /// <summary>  
  82.         /// 获取蛇头  
  83.         /// </summary>  
  84.         /// <returns></returns>  
  85.         public CPoint getHead()  
  86.         {  
  87.             return m_body[m_body.Count - 1];  
  88.         }  
  89.   
  90.         /// <summary>  
  91.         /// 获取蛇尾  
  92.         /// </summary>  
  93.         /// <returns></returns>  
  94.         private CPoint getTail()  
  95.         {  
  96.             return m_body[0];  
  97.         }  
  98.   
  99.         /// <summary>  
  100.         /// 添加蛇body节点  
  101.         /// </summary>  
  102.         /// <param name="point">新节点</param>  
  103.         /// <param name="food">是否是食物节点</param>  
  104.         public void addBodyNode(CPoint point, bool food)  
  105.         {  
  106.             //添加新节点  
  107.             this.m_body.Add(point);  
  108.             //非食物节点则移除尾巴  
  109.             if (!food)  
  110.             {  
  111.                 if (this.m_body.Count > 0)  
  112.                 {  
  113.                     this.m_body.Remove(getTail());  
  114.                 }  
  115.             }  
  116.         }  
  117.   
  118.         /// <summary>  
  119.         /// 是否在某位置发生碰撞  
  120.         /// </summary>  
  121.         /// <param name="point"></param>  
  122.         /// <returns></returns>  
  123.         public Boolean isCollision(CPoint point)  
  124.         {  
  125.             Boolean flag = false;  
  126.             foreach (CPoint p in m_body)  
  127.             {  
  128.                 flag = false;  
  129.                 if (p == point)  
  130.                 {  
  131.                     flag = true;  
  132.                     break;  
  133.                 }  
  134.             }  
  135.             return flag;  
  136.         }  
  137.   
  138.         /// <summary>  
  139.         /// 是否与自身发生碰撞  
  140.         /// </summary>  
  141.         /// <returns></returns>  
  142.         public Boolean isSeftCollision()  
  143.         {  
  144.             Boolean flag = false;  
  145.             for (Int32 i = 0; i <m_body.Count-1; i++)  
  146.             {  
  147.                 flag = false;  
  148.                 if (m_body[i] == getHead())  
  149.                 {  
  150.                     flag = true;  
  151.                     break;  
  152.                 }  
  153.             }  
  154.             return flag;  
  155.         }  
  156.   
  157.         /// <summary>  
  158.         /// 蛇移动  
  159.         /// </summary>  
  160.         /// <returns></returns>  
  161.         public bool move()  
  162.         {  
  163.             CPoint head = getHead();  
  164.             switch (m_dir)  
  165.             {  
  166.                 case CDirection.Left:  
  167.                     if (head.getX() == 1)  
  168.                         return false;  
  169.                     head.setX(head.getX() - 1);  
  170.                     break;  
  171.                 case CDirection.Right:  
  172.                     if (head.getX() == 28)  
  173.                         return false;  
  174.                     head.setX(head.getX() + 1);  
  175.                     break;  
  176.                 case CDirection.Up:  
  177.                     if (head.getY() == 1)  
  178.                         return false;  
  179.                     head.setY(head.getY() - 1);  
  180.                     break;  
  181.                 case CDirection.Down:  
  182.                     if (head.getY() == 23)  
  183.                         return false;  
  184.                     head.setY(head.getY() + 1);  
  185.                     break;  
  186.                 default:  
  187.                     break;  
  188.             }  
  189.             addBodyNode(head, false);  
  190.             return true;  
  191.         }  
  192.   
  193.         /// <summary>  
  194.         /// 绘制蛇  
  195.         /// </summary>  
  196.         /// <param name="draw"></param>  
  197.         public void draw(CDraw draw)  
  198.         {  
  199.             draw.setDrawSymbol(CSymbol.RING_SOLID);  
  200.             draw.fillRect(getHead().getX(), getHead().getY(), 1, 1, ConsoleColor.Yellow);  
  201.             draw.setDrawSymbol(CSymbol.DEFAULT);  
  202.             draw.fillRect(getTail().getX(), getTail().getY(), 1, 1, ConsoleColor.Black);  
  203.         }  
  204.  
  205.         #endregion  
  206.     }  
  207. }  
   蛇方向是一个枚举值,具体实现为下:
  ///CDirection枚举实现
[csharp]  view plain copy print ?
  1. using System;  
  2.   
  3. namespace CEngine  
  4. {  
  5.     [Flags]  
  6.     public enum CDirection  
  7.     {  
  8.         Left = 0x01,  
  9.         Right = 0x02,  
  10.         Up = 0x04,  
  11.         Down = 0x08,  
  12.         None = 0  
  13.     }  
  14. }  
   蛇类主要处理的是蛇的爬行、蛇是否吃到吃到食物、蛇是否自残和蛇的绘制等,此蛇类相对比较简单,就不必过多讨论了,接下来是食物类,鉴于此游戏DEMO是测试这个游戏框架的特征,所以以简为主,就不必讨论不同食物间的特征等问题,这只是一个游戏DEMO,不是一个完整的游戏,知道这一点是必须的。
  ///Food类实现
[csharp]  view plain copy print ?
  1. using System;  
  2. using CEngine;  
  3. using CGraphics;  
  4.   
  5. namespace Snake  
  6. {  
  7.     /// <summary>  
  8.     /// 食物类  
  9.     /// </summary>  
  10.     internal class Food  
  11.     {  
  12.         /// <summary>  
  13.         /// 位置  
  14.         /// </summary>  
  15.         private CPoint m_position;  
  16.   
  17.         /// <summary>  
  18.         /// 构造函数  
  19.         /// </summary>  
  20.         public Food()  
  21.         {  
  22.              
  23.         }  
  24.   
  25.         public Food(CPoint point)  
  26.         {  
  27.             this.m_position = point;  
  28.         }  
  29.   
  30.         /// <summary>  
  31.         /// 获取位置  
  32.         /// </summary>  
  33.         /// <returns></returns>  
  34.         public CPoint getPosition()  
  35.         {  
  36.             return this.m_position;  
  37.         }  
  38.   
  39.         /// <summary>  
  40.         /// 设置位置  
  41.         /// </summary>  
  42.         /// <param name="point"></param>  
  43.         public void setPosition(CPoint point)  
  44.         {  
  45.             this.m_position = point;  
  46.         }  
  47.   
  48.         /// <summary>  
  49.         /// 设置位置  
  50.         /// </summary>  
  51.         /// <param name="x"></param>  
  52.         /// <param name="y"></param>  
  53.         public void setPosition(Int32 x, Int32 y)  
  54.         {  
  55.             this.m_position = new CPoint(x,y);  
  56.         }  
  57.   
  58.         /// <summary>  
  59.         /// 绘制食物  
  60.         /// </summary>  
  61.         /// <param name="draw"></param>  
  62.         public void draw(CDraw draw)  
  63.         {  
  64.             draw.setDrawSymbol(CSymbol.RING_SOLID);  
  65.             draw.drawRect(m_position.getX(), m_position.getY(), 1,1,ConsoleColor.Green);  
  66.         }  
  67.     }  
  68. }  
   接下来是处理游戏逻辑,也就是实现这个游戏的控制类,这个类继承我们的游戏框架类,拥有框架提供的各种功能,从而对游戏实行控制和渲染,实现如下:
  ///SnakeGame类实现:
[csharp]  view plain copy print ?
  1. using System;  
  2. using CEngine;  
  3. using CGraphics;  
  4.   
  5. namespace Snake  
  6. {  
  7.     /// <summary>  
  8.     /// 贪吃蛇游戏类  
  9.     /// </summary>  
  10.     public sealed class SnakeGame : CGame  
  11.     {  
  12.         /// <summary>  
  13.         /// 游戏状态  
  14.         /// </summary>  
  15.         public enum GameState  
  16.         {  
  17.             /// <summary>  
  18.             /// 初始化  
  19.             /// </summary>  
  20.             Init,  
  21.             /// <summary>  
  22.             /// 开始游戏  
  23.             /// </summary>  
  24.             Start,  
  25.             /// <summary>  
  26.             /// 暂停游戏  
  27.             /// </summary>  
  28.             Pause,  
  29.             /// <summary>  
  30.             /// 结束游戏  
  31.             /// </summary>  
  32.             End  
  33.         }  
  34.   
  35.         /// <summary>  
  36.         /// 贪吃蛇  
  37.         /// </summary>  
  38.         private Snake g_snake;  
  39.         /// <summary>  
  40.         /// 食物  
  41.         /// </summary>  
  42.         private Food g_food;  
  43.         /// <summary>  
  44.         /// 随机数  
  45.         /// </summary>  
  46.         private Random g_random;  
  47.         /// <summary>  
  48.         /// 分数  
  49.         /// </summary>  
  50.         private Int32 g_score;  
  51.         /// <summary>  
  52.         /// 生命  
  53.         /// </summary>  
  54.         private Int32 g_lifes;  
  55.         /// <summary>  
  56.         /// 状态  
  57.         /// </summary>  
  58.         private GameState g_state;  
  59.  
  60.  
  61.         #region 游戏运行函数  
  62.   
  63.         /// <summary>  
  64.         /// 游戏初始化  
  65.         /// </summary>  
  66.         protected override void gameInit()  
  67.         {  
  68.             base.setTitle("控制台游戏之——简易贪吃蛇v1.0");  
  69.             base.setCursorVisible(false);  
  70.             base.setUpdateRate(50);  
  71.   
  72.             this.g_random = new Random();  
  73.             this.g_snake = new Snake(3, CDirection.Right);  
  74.             this.g_food = new Food();  
  75.   
  76.             this.g_lifes = 3;  
  77.             this.g_state = GameState.Init;  
  78.   
  79.             this.drawInitUI();  
  80.         }  
  81.   
  82.         /// <summary>  
  83.         /// 游戏重绘时响应  
  84.         /// </summary>  
  85.         /// <param name="e"></param>  
  86.         protected override void onRedraw(CPaintEventArgs e)  
  87.         {  
  88.             base.onRedraw(e);  
  89.   
  90.             CDraw draw = e.getDraw();  
  91.             //绘制食物  
  92.             g_food.draw(draw);  
  93.             //绘制数据  
  94.             draw.drawText("得分:" + g_score.ToString(), 63, 2, ConsoleColor.Green);  
  95.             draw.drawText("生命:" + g_lifes.ToString(), 63, 4, ConsoleColor.Red);  
  96.         }  
  97.   
  98.         /// <summary>  
  99.         /// 游戏渲染  
  100.         /// </summary>  
  101.         /// <param name="draw"></param>  
  102.         protected override void gameDraw(CGraphics.CDraw draw)  
  103.         {  
  104.             if (g_state == GameState.Start)  
  105.             {  
  106.                 g_snake.draw(draw);  
  107.                 draw.drawText("FPS:" + getFPS(), 63, 6, ConsoleColor.Blue);  
  108.             }  
  109.         }  
  110.   
  111.         /// <summary>  
  112.         /// 游戏逻辑  
  113.         /// </summary>  
  114.         protected override void gameLoop()  
  115.         {  
  116.             //游戏开始状态  
  117.             if (g_state == GameState.Start)  
  118.             {  
  119.                 //如果蛇能爬行或者没有自残则爬行  
  120.                 if (g_snake.move() && !g_snake.isSeftCollision())  
  121.                 {  
  122.                     //吃到食物  
  123.                     if (g_snake.getHead() == g_food.getPosition())  
  124.                     {  
  125.                         //加10分  
  126.                         this.g_score += 10;  
  127.                         //蛇长大  
  128.                         g_snake.addBodyNode(g_food.getPosition(), true);  
  129.                         //创建新食物  
  130.                         createFood();  
  131.                     }  
  132.                 }  
  133.                 else  
  134.                 {  
  135.                     //蛇死亡,减一条生命  
  136.                     this.g_lifes--;  
  137.   
  138.                     //扣分算法  
  139.                     if (this.g_score > 20)  
  140.                     {  
  141.                         this.g_score -= 20;  
  142.                     }  
  143.   
  144.                     //延时一秒钟  
  145.                     base.delay(1000);  
  146.   
  147.                     //蛇回到原始状态  
  148.                     this.g_snake = new Snake(3, CDirection.Right);  
  149.                     //更新导致重绘区域  
  150.                     base.update(new CRect(1, 1, 28, 23));  
  151.   
  152.                     //游戏结束  
  153.                     if (this.g_lifes == 0)  
  154.                     {  
  155.                         this.g_state = GameState.End;  
  156.   
  157.                         this.setGameOver(true);  
  158.                     }  
  159.                 }  
  160.             }  
  161.         }  
  162.   
  163.         /// <summary>  
  164.         /// 游戏结束  
  165.         /// </summary>  
  166.         protected override void gameExit()  
  167.         {  
  168.             drawEndUI();  
  169.   
  170.             g_snake = null;  
  171.             g_food = null;  
  172.         }  
  173.   
  174.         /// <summary>  
  175.         /// 键盘事件  
  176.         /// </summary>  
  177.         /// <param name="e"></param>  
  178.         protected override void gameKeyDown(CKeyboardEventArgs e)  
  179.         {  
  180.             if (g_snake != null)  
  181.             {  
  182.                 if (e.getKey() == CKeys.Left)  
  183.                 {  
  184.                     if (g_snake.getDirection() != CDirection.Right)  
  185.                     {  
  186.                         g_snake.setDirection(CDirection.Left);  
  187.                     }  
  188.                 }  
  189.                 else if (e.getKey() == CKeys.Right)  
  190.                 {  
  191.                     if (g_snake.getDirection() != CDirection.Left)  
  192.                     {  
  193.                         g_snake.setDirection(CDirection.Right);  
  194.                     }  
  195.                 }  
  196.                 else if (e.getKey() == CKeys.Up)  
  197.                 {  
  198.                     if (g_snake.getDirection() != CDirection.Down)  
  199.                     {  
  200.                         g_snake.setDirection(CDirection.Up);  
  201.                     }  
  202.                 }  
  203.                 else if (e.getKey() == CKeys.Down)  
  204.                 {  
  205.                     if (g_snake.getDirection() != CDirection.Up)  
  206.                     {  
  207.                         g_snake.setDirection(CDirection.Down);  
  208.                     }  
  209.                 }  
  210.                 else if (e.getKey() == CKeys.Space)  
  211.                 {  
  212.                     if (g_state == GameState.Init)  
  213.                     {  
  214.                         g_state = GameState.Start;  
  215.   
  216.                         drawStartUI();  
  217.                     }  
  218.                     else if (g_state == GameState.Pause)  
  219.                     {  
  220.                         g_state = GameState.Start;  
  221.                     }  
  222.                     else if (g_state == GameState.Start)  
  223.                     {  
  224.                         g_state = GameState.Pause;  
  225.                     }  
  226.                 }  
  227.                 else if (e.getKey() == CKeys.Escape)  
  228.                 {  
  229.                     setGameOver(true);  
  230.                 }  
  231.             }  
  232.         }  
  233.  
  234.         #endregion  
  235.   
  236.         /// <summary>  
  237.         /// 创建食物  
  238.         /// </summary>  
  239.         private void createFood()  
  240.         {  
  241.             CPoint point = new CPoint(g_random.Next(1, 29), g_random.Next(1, 24));  
  242.             //防止食物出现在蛇身  
  243.             while (g_snake.isCollision(point))  
  244.             {  
  245.                 point.setX(g_random.Next(1, 29));  
  246.                 point.setY(g_random.Next(1, 24));  
  247.             }  
  248.   
  249.             g_food.setPosition(point);  
  250.             //调用更新函数导致控制台重绘  
  251.             base.update(new CRect(point.getX(), point.getY(), 1, 1));  
  252.         }  
  253.  
  254.         #region 绘制界面  
  255.           
  256.         //绘制游戏初始界面  
  257.         private void drawInitUI()  
  258.         {  
  259.             CDraw draw = base.getDraw();  
  260.             draw.clear(ConsoleColor.Black);  
  261.             draw.setDrawSymbol(CSymbol.RECT_EMPTY);  
  262.             draw.drawRect(6, 4, 29, 12, ConsoleColor.DarkBlue);  
  263.             draw.fillRect(7, 5, 27, 10, ConsoleColor.Blue);  
  264.             draw.drawText("<<C#控制台游戏系列>>", 16, 5, ConsoleColor.White);  
  265.             draw.drawText("简 易 贪 吃 蛇", 34, 9, ConsoleColor.Yellow);  
  266.             draw.drawText("Copyright. D-Zone Studio", 42, 14, ConsoleColor.Gray);  
  267.             draw.drawText("Space to Play", 35, 20, ConsoleColor.White);  
  268.         }  
  269.           
  270.         //绘制游戏开始界面  
  271.         private void drawStartUI()  
  272.         {  
  273.             CDraw draw = base.getDraw();  
  274.             //绘制界面  
  275.             draw.clear(ConsoleColor.Black);  
  276.             draw.setDrawSymbol(CSymbol.RECT_EMPTY);  
  277.             draw.drawRect(0, 0, 30, 25, ConsoleColor.White);  
  278.             draw.setDrawSymbol(CSymbol.RHOMB_SOLID);  
  279.             draw.drawRect(30, 0, 10, 25, ConsoleColor.DarkYellow);  
  280.             draw.drawText("操作:键盘操作,方向键控制贪吃蛇爬行方向,空格键控制开始游戏和暂停游戏,ESC键退出游戏。", new CRect(32, 14, 6, 10), ConsoleColor.DarkGreen);  
  281.             this.createFood();  
  282.         }  
  283.   
  284.         //绘制游戏结束界面  
  285.         private void drawEndUI()  
  286.         {  
  287.             CDraw draw = base.getDraw();  
  288.             //绘制界面  
  289.             draw.clear(ConsoleColor.Black);  
  290.             draw.drawText("Game over, ", 30, 10, ConsoleColor.White);  
  291.             draw.drawText("score:" + g_score.ToString(), 42, 10, ConsoleColor.White);  
  292.             Console.ReadLine();  
  293.         }  
  294.  
  295.         #endregion  
  296.     }  
  297. }  
   与以往编写小游戏的经验比较,我们发现没有必要每次都要编写代码驱动和维护游戏的运行,在这里,游戏框架类已为我们封装这些特征,我们制作游戏时只需要考虑游戏如何玩法等设计上的问题,而不需要考虑其他细节问题,一定程度上提高我们的开发效率。尽管这个小游戏是一个DEMO版本,但它也具备一定的完整性,比如拥有了游戏必须的几个界面,然而它还不是完整的,没有关卡的设计,没有信息的保存,也没有参数的配置,但对于说明游戏框架如何使用已经足够了。
   接下来让我们欣赏一下我们的劳动成果:



三、结语

   终于完成了这个DEMO,如果读者也制作了贪吃蛇,不防给个链接,让我们娱乐娱乐!
C语言小游戏:贪吃蛇(游戏开发的环境和功能介绍) ❀❀❀ 文章由@不准备秃的大伟原创 ❀❀❀♪♪♪ 若有转载,请联系博主哦~ ♪♪♪❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤生命不停,学习不止。铁汁们,我是大伟,欢迎来到大伟的游戏时间,今天带大家来玩一款几乎是所有人童年的记忆中的一款经典的不能再经典的游戏:贪吃蛇!当然了,在玩游戏前,我们还是要先把游戏写出来啦!○( ^皿^)っHiahiahia…废话不多说,在开始游戏前,有些知识是希望大家了解的(因为博主也不是很懂,所以只能理解了,QWQ)。 阅读详情

相关推荐

c#编写的贪吃蛇游戏

     前几天和同事聊天,同事说他的一个朋友去某公司面式,公司出题目要一下午编写一个贪吃蛇游戏,结果没有写出来,没有应聘上,我仔细想了想觉得算法也不是很复杂,就在空闲的时候试着写了一下,当然没有到网上去看别人写的程序,完全是想自我测试的意思,并没有想写一个特别完善的东西,只是拿来练习联系吧,主要是想锻炼锻炼面向对象的编程的方法,一下午应该是可以写出来的,不过我人比较懒*^_^*只是写了个架子就不

prince_y的专栏 2929

C#开发迷宫控制台小游戏MazeDemo

迷宫小游戏,主要使用二维数组,栈Stack,自定义操作符operator,递归遍历等功能。 在VS2017中,新建控制台应用程序MazeDemo,选择.net framework 4.5。 一、新建一个枚举Direction,用于记录方向。Direction.cs代码如下: using System; namespace MazeDemo { /// <summary>...

ylq1045的专栏 1435

C#开发贪吃蛇小游戏实战项目

为了便于管理蛇的各个部分,我们通常会使用面向对象的方式,将蛇头与身体节点分别建模。通常的做法是将蛇的每一节身体作为一个独立的对象,并使用一个链表或列表来存储这些对象。set;set;X = x;Y = y;代码分析:类用于表示蛇的每一个身体节点,包含其坐标(X, Y)。- 通过构造函数传入初始坐标,方便在不同位置创建身体节点。接着,我们可以定义一个Snake类,用于管理蛇的整体状态:set;

weixin_42298254的博客 641

C#之控制台版本得贪吃蛇

2.生成墙壁,小蛇碰撞到墙壁或者咬到自己的尾巴,游戏结束。定义一个小蛇类,该类包含吃东西,移动,检测碰撞等方法。4.吃掉食物,增加自身的体长,并生成新的食物。1.给游戏制造一个有限得空间。3.生成随机的食物。

csdn2990的博客 908

C#贪吃蛇小游戏课程设计与源码解析

开发一款贪吃蛇游戏不仅是对编程技能的挑战,也是一个学习和应用编程知识、设计模式和软件工程原则的绝佳机会。在本章中,我们将介绍贪吃蛇游戏的基本规则和目标,并概述如何使用C#语言结合.NET框架来实现这一经典游戏。我们将探索整个开发周期,从最初的概念设计到最终的游戏部署,同时注重于面向对象编程、图形用户界面(GUI)设计和多线程技术在游戏开发中的实际应用。在开始编码之前,理解游戏的逻辑和设计模式至关重要。

weixin_30653091的博客 711

C# 小游戏实例程序大全

吃豆子、打砖块、翻牌游戏、满堂红、判颜色、拼图游戏、三线一点游戏、、、、、、、

c#用控制台实现贪吃蛇小游戏

写在前面: 有一天突发奇想,如果我只用算法实现基本逻辑,让控制台输出图像,不用任何组件,只用一门编程语言,能否实现一个可以人机交互的小游戏,抱着试一试的想法,博主用c#控制台程序复原了贪吃蛇玩法的小游戏。 目录 一、可视化界面 二、贪吃蛇基本逻辑 1.游戏玩法 一、可视化界面 众所周知,控制台程序通常没有可视化的界面,只是通过字符串来显示或者监控程序,在使用控制台写程序时,我们只关心数据,不在乎界面。但是,如果我们偏偏反其道而行之,用控制台可视化形式将游戏界面...

sinsted的博客 1万+

Carsim和Matlab/Simulink联合仿真时Carsim匹配不到Matlab的解决方法

      本人使用Carsim和Matlab/Simulink联合仿真做过用机器学习方法解决ACC和简单换道的仿真,曾将8.02 2016 2018三个版本Carsim反复安装N次,有相同方向的同学或安装过程遇到问题的同学可以加本人qq505625869一起交流经验心得。 一.前言       Carsim是一款很好的联合仿真软件,使用Carsim,可以避免搭建很多非常复杂的动力学模型

Kaikai_Liao的博客 8768

C#实现贪吃蛇

在Game类中使用定时器或循环来不断更新游戏状态,并根据用户输入来改变蛇的移动方向。每次更新游戏状态时,检查蛇是否吃到了食物,并根据情况增加蛇的长度和生成新的食物。这是一个简单的贪吃蛇游戏的C#代码示例。在游戏中,使用WASD键来控制蛇的移动方向,游戏目标是吃掉食物,得到分数,尽量避免蛇头碰到边界或自身身体。该类需要维护游戏地图、蛇对象以及食物的位置等信息,并提供方法来更新游戏状态、处理用户输入等操作。该类需要包含蛇的位置、长度、移动方向等信息,并提供方法来移动蛇、增长蛇的长度等操作。

2201_75443732的博客 2699

【没有网络,安装python包】如何从 PyPI 下载并安装 Plotly 的离线包

在某些情况下,您可能需要在没有互联网连接的环境中安装 Python 包,例如在飞机上、在某些受限制的网络环境中或在需要离线安装的场景下。以下是如何在 PyPI(Python Package Index)下载 Plotly 包并进行离线安装的详细步骤。

赖德发的博客 1104

C# 读取图片和扫描PDF中的文本

本博客将探讨如何使用C#和OCR库实现从图片和扫描的 PDF 中提取文本。Spire.OCR for .NET 是一个OCR文字识别库,专为在 .NET 应用程序中识别图片的文本而设计。首先,使用 Spire.PDF 将扫描的 PDF 转换为图片,然后利用 Spire.OCR 从这些图片中提取文本。由于该OCR库并不支持直接处理PDF,因此要从扫描的 PDF 中提取文本,我们首先需要将 PDF 文档转换为图片。转换完成后,再利用 Spire.OCR 从生成的图片中提取文本。方法来识别图片中的文本。

nuclear2011的博客 5401

[代码艺术]17行代码的贪吃蛇小游戏

一个贪吃蛇小游戏javascrpt有效代码17行加上html代码的话,共25行运行方法chrome或者firefox测试连接http://lufylegend.com/html5/lufylegend/tcs.html完整代码如下 Your browser does not support the HTML5 canvas tag. var ctx=document.getElementBy

lufy小屋 2万+

FreeRtos——10、全局看门狗设计

RTOS 里的看门狗不只是为了证明 CPU 还在动,而是为了证明每个业务逻辑都在按预期的节奏“呼吸”。

qq_40170041的博客 901

C#编程挑战:从零开始构建贪吃蛇游戏

在编程的世界里,贪吃蛇游戏是一个经典且广受欢迎的入门级项目,它不仅能够锻炼编程基础,还能加深对游戏开发的理解。本文将带你从零开始,使用C#语言和.NET框架,一步步构建一个简单的贪吃蛇游戏。

Unity打怪升级 2951

NCCL 源码深度解析:从初始化到通信链路构建全流程

本文深入解析了NVIDIA Collective Communication Library (NCCL) 的核心工作机制,从通信组初始化、硬件拓扑发现,到P2P、共享内存及网络传输链路的构建。详细剖析了源码中集合通信任务的执行流程与Proxy线程的协同机制,为开发者进行高性能分布式训练的性能调优与深度问题排查提供了清晰的底层视角。

hp777的博客 551

5、Visual Studio Code:强大的编码与文件管理功能

本文详细介绍了 Visual Studio Code 的强大编码与文件管理功能,涵盖代码导航、引用查找、符号重命名、实时代码分析、IntelliCode 提示、文件和文件夹操作等内容。通过功能对比、流程图和实际开发案例,展示了 VS Code 如何提升开发效率和代码质量,适用于各类编程语言和项目开发场景。

water的专栏 134

C语言——基于控制台实现贪吃蛇小游戏

本文章将介绍如何使用C语言在Windows环境的控制台中模拟实现经典小游戏贪吃蛇。

laso2024的博客 1592

嵌入式编程模型 | 原型模式

本文介绍了原型模式在嵌入式传感器网络中的应用。原型模式通过复制现有对象创建新实例,避免了重复初始化开销,适用于设备配置克隆、状态复制等场景。文章以传感器网络为例,展示了原型模式的结构(抽象原型类、具体原型类、客户端)和实现方式,通过C语言代码演示了温度/湿度传感器的克隆过程。该模式能有效提升嵌入式系统资源复用效率,实现快速部署相似配置的传感器节点,同时保持内存优化和配置灵活性。

嵌入式大杂烩 147

C#游戏编程:《控制台小游戏系列》之《一、黎明前的黑暗》

本系列文章转载至hwenycocodq520 一、前言         码夫掐指一算,博客搁置已半载有余。这半年多来,油价涨的涨,食物毒的毒,小日本越发嚣张……惟独码夫心如止水,不,是技如止水,技术还停留在“社会主义初级阶段”,丝毫没有进步的痕迹。惟叹息:天纵然生我,何还为吾配愚脑……     回到现实,即使码夫天生愚笨,但生活还是要过,技术也要沾沾,不枉老

fa6507的专栏 3111

机器人中的数值优化(十四)——罚函数法(Penalty Method)、障碍函数法(Barrier Method)、拉格朗日松弛法(Lagrangian Relaxation)

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考,主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等,本系列文章篇数较多,不定期更新,上半部分介绍无约束优化,下半部分介绍带约束的优化,中间会穿插一些路径规划方面的应用实例

慕羽★的博客 5217

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C#游戏编程:《控制台小游戏系列》之《八、爆破七色砖实例》

一、游戏分析   相信各位读者都曾玩过一款叫做《打砖块》的小游戏,和贪吃蛇一样,也是一款80后皆知的经典小游戏。游戏虽然简单但极富挑战性,这章的内容就是制作一款类打砖块的小游戏,继续说明和熟悉游戏框架的使用。和前几个小游戏不同,本章的小游戏有了一些进步,最明显的是有了关卡的概念,游戏不再是单调的一关,你可以自己设计自己所想要的关卡,这一定程度上提高了游戏的可玩性。但是这个游戏和前面的一样,也

fa6507的专栏 2133

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

C#写的控制台贪吃蛇

周末无聊准备自己写一个小游戏玩玩,结果写了一上午的贪吃蛇bug重重,根本没法玩(水平太菜,惭愧,惭愧)。然后去github找了一个写好的游戏,自己过了一遍,然后加上了注释。也做了一些小小的改动,玩起来还蛮好玩的,记录一下。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using System.Threading; using Sy

yasenRK的博客 1908

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

C#下WPF中实现贪吃蛇小游戏(超详细步骤附带源码)

一.编程思想,在制作此小游戏的时候我们应该明白我们的目标是什么,然后一步步去实现: 1.首先得考虑到游戏页面的布局,游戏区域以及控制游戏的区域两部分; 2.在计时器下小蛇的生成; 3.小蛇自身的长度,以及位置和蛇头与蛇身的区别; 4.食物的随机生成,以及食物的随机位置和渐变色; 5.点击游戏开始时,播放游戏背景音乐,当音乐播放完时让其音乐重新播放也就是所谓的音乐循环播放; 6.控制小蛇的移动,还有按下方向键的时候改变小蛇移动的方向; 7.蛇吃到食物后自身的长度和得分加一,而且被吃到的食物消失,并播放吃到食物

凭时间赢来的东西,时间肯定会为之作证 13万+

C#贪吃蛇游戏(初学简易版本)

学完c#程序设计,就赶紧想写个什么小程序感受一下编程乐趣,于是写了这个简单好玩又刺激的经典游戏–贪吃蛇;由于是初学,刚开始也是不知道从哪写起,我也是看了好多大哥写的,我的程序很多地方也是受他们启发写的。我这篇仅仅作为自己写程序的一个记录,也是存在有一些问题,望大佬指出,不过目前还是可以完美运行的,分享出来作为给我和一样的初学者一些借鉴。 为了提高我的激情,我的游戏名为 《虚空巨蟒》。 现为大家看一下效果: 效果展示 大致思路 先创建新的食物和五节巨蟒身体(都为标签),打开定时器,初始化按键状态为“暂停”,.

mmeeed的博客 4314

C#简单小游戏之贪吃蛇

贪吃蛇的创建 1:声明地图 通过声明一个40x40的地图 把边界都表示为墙 为55 private int[,] Map = new int[40, 40];//地图 我把0作为当前位置为空,可以行走,1作为蛇的位置 2,作为果子的位置 private void Show() { for(int i = 0; i < 40; i++) { ...

m0_62183109的博客 1213
上一篇: C#游戏编程:《控制台小游戏系列》之《五、游戏框架完善》
下一篇: C#游戏编程:《控制台小游戏系列》之《七、键盘熟练工实例》
fa6507
博客等级 码龄16年 84粉丝 1原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值