小菜学习Winform(一)贪吃蛇

前言

  说到贪吃蛇,大家可能小时候都玩过,小菜最近在整理Winfrom的学习系列,那我觉得有兴趣才会有学习,就从这个小游戏讲起吧。

实现

  其实我刚开始学习编程的时候,感觉写个贪吃蛇的程序会很难,因为涉及到画图什么的,其实现在来看,实现很简单。

  实现贪吃蛇首先有几个元素:

  •  蛇
  •  食物

  然后有几个行为:

  •  吃食物和吃不到食物
  •  撞墙和撞自己

  说到这有点oo的意思啊,这篇就不啰嗦,只是简单实现,下篇会优化下。

  其实整个贪吃蛇的难点就在于画图,可能用其他语言实现有点复杂,但是强大的.net提供了GDI+绘图机制,实现起来就很方便了,其次就是细节的处理,比如坐标的定位,蛇的行走路线等。

  我们简单一点来看,食物可以看成一个小方格,蛇是有N个小方格组成,那我们就可以用GDI+这样实现:

 1         /// <summary>

 2         /// 画一个小方块

 3         /// </summary>

 4         public void DrawShape(int x, int y)

 5         {

 6             Graphics g = this.CreateGraphics();

 7             Pen pen = new Pen(Color.Blue, 2);

 8             g.DrawRectangle(pen, x, y, 15, 15);

 9             g.FillRectangle(Brushes.Green, x, y, 15, 15);

10         }

11 

12         /// <summary>

13         /// 画一个食物

14         /// </summary>

15         public void DrawFood(int x, int y)

16         {

17             Graphics g = this.CreateGraphics();

18             Pen pen = new Pen(Color.Red, 2);

19             SolidBrush brush = new SolidBrush(Color.Green);

20             g.DrawRectangle(pen, x, y, 15, 15);

21             g.FillRectangle(brush, x, y, 15, 15);

22         }

  Graphics这个类我就不多说,大家可以看看MSDN上介绍的用法,上面是画蛇的最小单元-方格,和一个食物方格,蛇的方格大小是15*15,边框颜色是Blue,填充色是Green;食物方格的大小是15*15,边框颜色是Red,填充色是Green。

  画好了基本元素,那下面就是用基本元素来表现蛇了,可以用Point数组来存储蛇的坐标,也就是每个方格的坐标,我们先看下代码:

 1         /// <summary>

 2         /// 设置Point数组坐标

 3         /// </summary>

 4         public void Forward(int drt)

 5         {

 6             Point temp = snakeArr[0];

 7 

 8             for (int i = snakeLen-1; i > 0; i--)

 9             {

10                 snakeArr[i].X = snakeArr[i - 1].X;

11                 snakeArr[i].Y = snakeArr[i - 1].Y;

12             }

13             switch (drt)

14             {

15                 case 1:

16                     snakeArr[0].X = temp.X;

17                     snakeArr[0].Y = temp.Y - 15;

18                     break; //

19                 case 2:

20                     snakeArr[0].X = temp.X + 15;

21                     snakeArr[0].Y = temp.Y;

22                     break; //

23                 case 3:

24                     snakeArr[0].X = temp.X;

25                     snakeArr[0].Y = temp.Y + 15;

26                     break; //

27                 case 4:

28                     snakeArr[0].X = temp.X - 15;

29                     snakeArr[0].Y = temp.Y;

30                     break; //

31             }

32         }

  drt参数是键盘上上下左右键对应的数字,snakeLen是数组的长度也就是方格的个数,上面那个for循环主要的作用是把前一个数组的坐标赋值给下一个,就像是毛毛虫爬行一样,后一节会按照前一节的路线来爬,下面那个switch的作用是,设置蛇头的行进路线。

  再下面就是判断蛇是否吃到食物、是否撞到墙和撞到自己,因为蛇和食物都是用坐标存储的,所以只要判断蛇头坐标是否等于食物坐标就可以了:

 1         /// <summary>

 2         /// 判断是否吃到食物

 3         /// </summary>

 4         public bool EatedFoot(Point FoodLct)

 5         {

 6             if (snakeArr[0].X == FoodLct.X && snakeArr[0].Y == FoodLct.Y)

 7             {

 8                 if (snakeLen < SnakeMaxLength)

 9                 {

10                     snakeLen++;

11                     snakeArr[snakeLen].X = snakeArr[snakeLen - 1].X;

12                     snakeArr[snakeLen].Y = snakeArr[snakeLen - 1].Y;

13                 }

14                 return true;

15             }

16             else

17                 return false;

18         }        

19 

20         /// <summary>

21         /// 判断是否撞到自己

22         /// </summary>

23         public bool CheckSnakeHeadInSnakeBody()

24         {

25             return this.CheckInSnakeBody(this.snakeArr[0].X, this.snakeArr[0].Y, 1);

26         }

27         /// <summary>

28         /// 检查输入的坐标是否在蛇的身上

29         /// </summary>

30         public bool CheckInSnakeBody(int x, int y, int snkHead)

31         {

32             for (int i = snkHead; i < snakeLen; i++)

33             {

34                 if (x == this.snakeArr[i].X && y == this.snakeArr[i].Y)

35                 {

36                     return true;

37                 }

38             }

39             return false;

40         }

41 

42         /// <summary>

43         /// 判断是否撞墙

44         /// </summary>

45         /// <returns></returns>

46         public bool CheckSnakeBodyInFrm()

47         {

48             if (this.snakeArr[0].X >= 594 || this.snakeArr[0].Y >= 399 - 32 || this.snakeArr[0].X < 0 || this.snakeArr[0].Y < 0)

49                 return true;

50             else

51                 return false;

52         }    

  实现上面的几个步骤,简单版的贪吃蛇基本上就完成了,再加上一个timer控件,这样蛇就会“动”起来了,就这么简单。

  完整代码:

小菜学习Winform(一)贪吃蛇
  1 using System;

  2 using System.Collections.Generic;

  3 using System.ComponentModel;

  4 using System.Data;

  5 using System.Drawing;

  6 using System.Linq;

  7 using System.Text;

  8 using System.Windows.Forms;

  9 

 10 namespace 贪吃蛇自练_GDI_

 11 {

 12     public partial class Form1 : Form

 13     {

 14         public Point FoodLct = new Point();//缓存食物的坐标

 15         public int snakeLen=6;

 16         public const int SnakeMaxLength = 500;

 17         public Point[] snakeArr = new Point[SnakeMaxLength];

 18         public int snakeDrt = 2;

 19         public bool panDuan = true;

 20 

 21         public Form1()

 22         {

 23             InitializeComponent();

 24 

 25             int temp = 0;

 26             for (int i = snakeLen - 1; i >= 0; i--)

 27             {

 28                 snakeArr[i].X = temp;

 29                 snakeArr[i].Y = 0;

 30                 temp += 15;

 31             }

 32         }

 33 

 34         /// <summary>

 35         /// 画一个小方块

 36         /// </summary>

 37         public void DrawShape(int x, int y)

 38         {

 39             Graphics g = this.CreateGraphics();

 40             Pen pen = new Pen(Color.Blue, 2);

 41             g.DrawRectangle(pen, x, y, 15, 15);

 42             g.FillRectangle(Brushes.Green, x, y, 15, 15);

 43         }

 44 

 45         /// <summary>

 46         /// 画一个食物

 47         /// </summary>

 48         public void DrawFood(int x, int y)

 49         {

 50             Graphics g = this.CreateGraphics();

 51             Pen pen = new Pen(Color.Red, 2);

 52             SolidBrush brush = new SolidBrush(Color.Green);

 53             g.DrawRectangle(pen, x, y, 15, 15);

 54             g.FillRectangle(brush, x, y, 15, 15);

 55         }

 56 

 57         /// <summary>

 58         /// 设置Point数组坐标

 59         /// </summary>

 60         public void Forward(int drt)

 61         {

 62             Point temp = snakeArr[0];

 63 

 64             for (int i = snakeLen-1; i > 0; i--)

 65             {

 66                 snakeArr[i].X = snakeArr[i - 1].X;

 67                 snakeArr[i].Y = snakeArr[i - 1].Y;

 68             }

 69             switch (drt)

 70             {

 71                 case 1:

 72                     snakeArr[0].X = temp.X;

 73                     snakeArr[0].Y = temp.Y - 15;

 74                     break; //

 75                 case 2:

 76                     snakeArr[0].X = temp.X + 15;

 77                     snakeArr[0].Y = temp.Y;

 78                     break; //

 79                 case 3:

 80                     snakeArr[0].X = temp.X;

 81                     snakeArr[0].Y = temp.Y + 15;

 82                     break; //

 83                 case 4:

 84                     snakeArr[0].X = temp.X - 15;

 85                     snakeArr[0].Y = temp.Y;

 86                     break; //

 87             }

 88         }

 89 

 90         /// <summary>

 91         /// 时间事件

 92         /// </summary>

 93         private void timer1_Tick(object sender, EventArgs e)

 94         {

 95             Graphics g = this.CreateGraphics();

 96             g.Clear(Color.DarkKhaki);//清除整个画面

 97 

 98             Forward(snakeDrt);

 99             for (int i = 0; i < snakeLen; i++)

100             {

101                 DrawShape(snakeArr[i].X, snakeArr[i].Y);

102             }

103 

104             if (panDuan)

105             {

106                 ShowFood();

107                 //DrawFood(FoodLct.X, FoodLct.Y);

108                 panDuan = false;

109             }

110 

111             if (EatedFoot(FoodLct))

112             {

113                 ShowFood();

114                 DrawFood(FoodLct.X, FoodLct.Y);

115             }

116             else

117             {

118                 DrawFood(FoodLct.X, FoodLct.Y);

119             }

120 

121             if (CheckSnakeHeadInSnakeBody() || CheckSnakeBodyInFrm())

122             {

123                 this.timer1.Enabled = false;

124                 MessageBox.Show("游戏结束!");

125             }

126         }

127 

128         /// <summary>

129         /// 按下方向键

130         /// </summary>

131         private void Form1_KeyDown(object sender, KeyEventArgs e)

132         {

133             if (e.KeyCode == Keys.Up)

134                 snakeDrt = 1;

135             else if (e.KeyCode == Keys.Down)

136                 snakeDrt = 3;

137             else if (e.KeyCode == Keys.Right)

138                 snakeDrt = 2;

139             else if (e.KeyCode == Keys.Left)

140                 snakeDrt = 4;

141         }

142 

143         /// <summary>

144         /// 判断是否撞到自己

145         /// </summary>

146         public bool CheckSnakeHeadInSnakeBody()

147         {

148             return this.CheckInSnakeBody(this.snakeArr[0].X, this.snakeArr[0].Y, 1);

149         }

150         /// <summary>

151         /// 检查输入的坐标是否在蛇的身上

152         /// </summary>

153         public bool CheckInSnakeBody(int x, int y, int snkHead)

154         {

155             for (int i = snkHead; i < snakeLen; i++)

156             {

157                 if (x == this.snakeArr[i].X && y == this.snakeArr[i].Y)

158                 {

159                     return true;

160                 }

161             }

162             return false;

163         }

164 

165         /// <summary>

166         /// 判断是否撞墙

167         /// </summary>

168         /// <returns></returns>

169         public bool CheckSnakeBodyInFrm()

170         {

171             if (this.snakeArr[0].X >= 594 || this.snakeArr[0].Y >= 399 - 32 || this.snakeArr[0].X < 0 || this.snakeArr[0].Y < 0)

172                 return true;

173             else

174                 return false;

175         }

176 

177         /// <summary>

178         /// 随机显示食物

179         /// </summary>

180         public void ShowFood()

181         {

182             Random rmd = new Random();

183             int x, y;

184             x = rmd.Next(0, this.Width/15)*15;

185             y = rmd.Next(0, this.Height/15)*15;

186             //while (this.CheckInSnakeBody(x, y, 1))

187             //{

188             //    x = rmd.Next(0, 32) * 15;

189             //    y = 32 + rmd.Next(0, 30) * 15;

190             //}

191             FoodLct.X = x;

192             FoodLct.Y = y;

193         }

194 

195         /// <summary>

196         /// 判断是否吃到食物

197         /// </summary>

198         public bool EatedFoot(Point FoodLct)

199         {

200             if (snakeArr[0].X == FoodLct.X && snakeArr[0].Y == FoodLct.Y)

201             {

202                 if (snakeLen < SnakeMaxLength)

203                 {

204                     snakeLen++;

205                     snakeArr[snakeLen].X = snakeArr[snakeLen - 1].X;

206                     snakeArr[snakeLen].Y = snakeArr[snakeLen - 1].Y;

207                 }

208                 return true;

209             }

210             else

211                 return false;

212         }

213     }

214 }
View Code

  运行截图:

  程序下载:贪吃蛇

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

后记

  其实这个简单的小程序需要做的优化有很多,比如上面说的oo,得分模式,蛇行进加速模式等等,希望在下篇来完成。

 

你可能感兴趣的:(WinForm)