C#贪吃蛇二

前言

  上一篇小菜学习Winform(一)贪吃蛇》中实现了简单版的贪吃蛇,在文章末也提到需要优化的地方,比如使用oo、得分模式、速度加快模式和减少界面重绘。因为是优化篇,实现方式上一篇有,这一篇大家看看代码就行。当然小菜不是搞游戏开发的,程序可能有很多问题,这里点到即止,有时间小菜会加强学习。

实现

  说到oo可能一说一大堆,这里面小菜只是简单的把贪吃蛇抽象出来,先来说蛇,具有的属性和行为,属性比如蛇的长度、蛇的宽度、蛇的行动方向等;行为比如是否吃到食物、是否撞墙等,那我们可以抽象一个蛇的类,这样实现:

复制代码
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Drawing;
  6 
  7 namespace SnakeGame
  8 {
  9     public class Snake
 10     {
 11         public int SnkWidth = 16;//蛇的每个点的宽度
 12         public const int SnakeMaxLength = 500;//最大长度
 13         public Point[] SnkLct = new Point[SnakeMaxLength];
 14         public int SnkLen;//蛇的长度
 15         public byte SnkDrt = 2;//方向 1上 2右 3下 4左
 16         
 17         /// <summary>
 18         /// 属性初始化
 19         /// </summary>
 20         public void SnakeInit()
 21         {
 22             int start = 0;
 23             this.SnkLen = 5;
 24             for (int i = 5; i >=1; i--)
 25             {
 26                 this.SnkLct[i].X = start;
 27                 this.SnkLct[i].Y = 32;
 28                 start += this.SnkWidth;
 29             }
 30             this.SnkDrt = 2;//初始方向
 31         }
 32         /// <summary>
 33         /// 判断是否撞到自己
 34         /// </summary>
 35         /// <returns></returns>
 36         public bool CheckSnakeHeadInSnakeBody()
 37         {
 38             return this.CheckInSnakeBody(this.SnkLct[1].X, this.SnkLct[1].Y, 2);
 39         }
 40         /// <summary>
 41         /// 检查输入的坐标是否在蛇的身上
 42         /// </summary>
 43         /// <param name="x"></param>
 44         /// <param name="y"></param>
 45         /// <param name="snkHead"></param>
 46         /// <returns></returns>
 47         public bool CheckInSnakeBody(int x, int y, int snkHead)
 48         {
 49             for (int i =snkHead; i <=this.SnkLen; i++)
 50             {
 51                 if(x==this.SnkLct[i].X&&y==this.SnkLct[i].Y)
 52                 {
 53                     return true;
 54                 }
 55             }
 56             return false;
 57         }
 58         /// <summary>
 59         /// 判断是否撞墙
 60         /// </summary>
 61         /// <returns></returns>
 62         public bool CheckSnakeBodyInFrm()
 63         {
 64             if (this.SnkLct[1].X >= 560 || this.SnkLct[1].Y >= 512 || this.SnkLct[1].X < 0 || this.SnkLct[1].Y < 32)
 65                   return true;
 66             else
 67                  return false;
 68         }
 69         /// <summary>
 70         /// 判断是否吃到食物
 71         /// </summary>
 72         /// <param name="FoodLct"></param>
 73         /// <returns></returns>
 74         public bool EatedFoot(Point FoodLct)
 75         {
 76             if (SnkLct[1].X == FoodLct.X && SnkLct[1].Y == FoodLct.Y)
 77             {
 78                 if (SnkLen < SnakeMaxLength)
 79                 {
 80                     SnkLen++;
 81                     SnkLct[SnkLen].X = SnkLct[SnkLen - 1].X;
 82                     SnkLct[SnkLen].Y = SnkLct[SnkLen - 1].Y;
 83                 }
 84                 return true;         
 85             }
 86             else
 87                 return false;         
 88         }
 89         /// <summary>
 90         /// 设置Point数组坐标
 91         /// </summary>
 92         /// <param name="drc"></param>
 93         public void Forward(int drc)
 94         {
 95             Point tmp = new Point();
 96             tmp.X = SnkLct[1].X;
 97             tmp.Y = SnkLct[1].Y;
 98             for (int i = SnkLen; i > 1; i--)
 99             {//蛇头动,把蛇头的坐标逐个后移(蛇身往蛇头方向位移) 
100                 SnkLct[i].X = SnkLct[i - 1].X;
101                 SnkLct[i].Y = SnkLct[i - 1].Y;
102             }
103 
104             switch (drc)
105             {//根据设置的方向,计算蛇头的坐标 
106                 case 1:
107                     SnkLct[1].X = tmp.X;
108                     SnkLct[1].Y = tmp.Y - SnkWidth;
109                     break; //
110                 case 2:
111                     SnkLct[1].X = tmp.X + SnkWidth;
112                     SnkLct[1].Y = tmp.Y;
113                     break; //
114                 case 3:
115                     SnkLct[1].X = tmp.X;
116                     SnkLct[1].Y = tmp.Y + SnkWidth;
117                     break; //
118                 case 4:
119                     SnkLct[1].X = tmp.X - SnkWidth;
120                     SnkLct[1].Y = tmp.Y;
121                     break; //
122             }
123         }
124     }
125 }
复制代码

  抽象完蛇,那我们再说下贪吃蛇游戏,贪吃蛇这个游戏具有的元素有:蛇、食物、得分等,那我们这样来表现:

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Drawing;
 6 
 7 namespace SnakeGame
 8 {
 9     public class Game
10     {
11         public Point FoodLct = new Point();//缓存食物的坐标
12         public int score = 0;//得分
13         public bool pause;//暂停
14         public Snake snake = new Snake();
15         /// <summary>
16         /// 游戏初始化
17         /// </summary>
18         public void GameInit()
19         {
20             this.pause = false;
21             this.score = 0;
22             this.snake.SnakeInit();//初始化
23         }
24         /// <summary>
25         /// 随机显示食物
26         /// </summary>
27         public void ShowFood()
28         {
29             Random rmd = new Random();
30             int x, y;
31             x = rmd.Next(0, 35) * this.snake.SnkWidth;
32             y = 32 + rmd.Next(0, 30) * this.snake.SnkWidth;
33             while (this.snake.CheckInSnakeBody(x,y,1))
34             {
35                 x = rmd.Next(0,32)*this.snake.SnkWidth;
36                 y = 32 + rmd.Next(0, 30) * this.snake.SnkWidth;
37             }
38             FoodLct.X = x;
39             FoodLct.Y = y;
40         }
41         /// <summary>
42         /// 分数
43         /// </summary>
44         /// <returns></returns>
45         public bool AddScore()
46         {
47             if(this.snake.EatedFoot(FoodLct))
48             {
49                 this.score += 10;
50             return true;
51             }
52             return false;
53         }
54         /// <summary>
55         /// 判断游戏是否结束
56         /// </summary>
57         /// <returns></returns>
58         public bool Dead()
59         {
60             return this.snake.CheckSnakeBodyInFrm()||this.snake.CheckSnakeHeadInSnakeBody();
61         }
62     }
63 }
复制代码

  其实使用oo还有很多地方需要细化,这里不是讲oo,所以只是简单的带过下。

  然后是得分模式,就是蛇吃到一个食物就加10分,这个在AddScore()方法中有实现:

复制代码
 1         /// <summary>
 2         /// 分数
 3         /// </summary>
 4         /// <returns></returns>
 5         public bool AddScore()
 6         {
 7             if(this.snake.EatedFoot(FoodLct))
 8             {
 9                 this.score += 10;
10                 return true;
11             }
12             return false;
13         }
复制代码

  再者是加速模式,蛇吃到一定量的时候后,难度会增加,爬行的速度会更快,这个可以在timer事件里面根据得分设置timer的执行间隔时间:

复制代码
 1             if (this.game.score < 100)
 2             {
 3                 this.timMove.Interval = 150;
 4             }
 5             else if (this.game.score < 150)
 6             {
 7                 this.timMove.Interval = 100;
 8             }
 9             else
10             {
11                 this.timMove.Interval = 50;
12             }
复制代码

  最后是减少界面重绘这个问题,因为小菜不是搞游戏开发的,那我只能减少界面的重绘数量,这边我是这样实现的,食物用label控件,显示用定位来体现,蛇的动作还是用GDI+来绘制。

  主程序代码:

  View Code

  运行截图:

  程序下载:贪吃蛇2

  附录:小菜学习编程-Winform系列(初学者)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值