关于贪吃蛇需要用的对象: 1.蛇 (Snake)2.食物(Food) 3. 记录蛇身的位置(Snake_body[x,y]) 4 .食物位置Food[x,y]
简单业务: 1.蛇身移动
2.随机食物
3.蛇头与食物重叠
4.窗体检测上下左右方向,控制蛇身体移动方向
好了,废话不多说,开始:在页面拖入panle1,两个lable和button按钮,页面有点丑 ,关于页面位置的调整在Load实事件中调整,
首先定义成员变量,score 得分,每吃掉一次食物+1、 _Key_Name 初始蛇的移动方向(键盘)、_Snake_Body是蛇身数组、_Random产生随机数定义食物位置
#region 定义成员变量 /// <summary> /// 得分 /// </summary> private int score = 0; /// <summary> /// 键盘状态,初始为 start /// </summary> string _Key_Name = "Start"; /// <summary> /// 蛇身数组 /// </summary> Label[] _Snake_Body = new Label[3000]; /// <summary> /// 随机数生成Food /// </summary> Random _Random = new Random(); /// <summary> /// 记录位置 /// </summary> int Snake_Boby_content_x = 0, Snake_Boby_content_y = 0; #endregion
好了 ,接下来,初始化舍身和食物 在窗体的初始化事件Form1_Load中添加长度为5个label的蛇身一个label的初始大小为10*10,并设置其的一些属性。其中Timer_Tick为蛇的移动事件,既每隔一次timer.Tick执行一次Timer_TickForm1_KeyDown为对键盘的监控,_point 指定panel的位置,Snake_food()生成食物
Bitmap _bitmap = new Bitmap(Resource.zyd); IntPtr h = _bitmap.GetHicon(); this.Icon = System.Drawing.Icon.FromHandle(h); this.Text="Snake张益达"; this.Width = 1000; this.Height = 850;
panel1.BorderStyle = BorderStyle.FixedSingle; panel1.Width = 800; panel1.Height = 840; Point _point = new Point { X = this.Width - 150, Y = 100 }; Point _point1 = new Point { X = this.Width - 80, Y = 100 }; label1.Location = _point; TxtScore.Location = _point1; //初始化蛇 5个label 一个label x =y=10 for (int i=0;i<8;i++) { //身段 Label Snake_Body_Content = new Label { Height = 10, Width = 10, Top = 200,//蛇的位置 Left = 200 - (i * 10), BackColor = Color.Black,//背景色 ForeColor = Color.Black, Text = "▉", //显示类型 Tag=i }; this.BackColor = Color.White;
//加入蛇体型 _Snake_Body[i] = Snake_Body_Content; panel1.Controls.Add(Snake_Body_Content); } //每隔一段时间发生右移动 timer1.Tick += new EventHandler(Timer_Tick); timer1.Interval = 1000; //检测事件监控 Snake_food();}
接下来就是蛇体移动事件 ,在timer中执行
public void Timer_Tick(object sender,EventArgs e) {
int x, y;//记录Snake的Head的XY坐标 x = _Snake_Body[0].Left; y = _Snake_Body[0].Top; if (_Key_Name == "Start") {
_Snake_Body[0].Left = x + 10; //向右偏移x+10 SnakeMove(x, y); } if (_Key_Name == "Right") //键盘状态 向右 { _Snake_Body[0].Left = x + 10; //向右偏移x+10 SnakeMove(x, y);
} if (_Key_Name == "Up") //键盘状态向上 { _Snake_Body[0].Top =y -10; //向右偏移y-10 SnakeMove(x, y); } if (_Key_Name == "Left") { _Snake_Body[0].Left = x - 10; //向右偏移x-10 SnakeMove(x, y); } if (_Key_Name == "Down") { _Snake_Body[0].Top = y + 10; //向右偏移y+10 SnakeMove(x, y); } //穿墙设置 if (x > 800) {
_Snake_Body[0].Left = 0; } if (y > 850) {
_Snake_Body[0].Top = 0; } if (x < 0) {
_Snake_Body[0].Left = 800; } if (y < 0) {
_Snake_Body[0].Top = 840; }
}
/// <summary> /// 键盘相应事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void FormZyd_KeyDown(Object sender, KeyEventArgs e) {
int x, y; x = _Snake_Body[0].Left; y = _Snake_Body[0].Top; _Key_Name = e.KeyCode.ToString(); //获取键盘代码 if (_Key_Name == "Right") { _Snake_Body[0].Left = x + 10; SnakeMove(x, y); } if (_Key_Name == "Left") { _Snake_Body[0].Left = x - 10; SnakeMove(x, y);
} if (_Key_Name == "Up") { _Snake_Body[0].Top = y - 10; SnakeMove(x, y); } if (_Key_Name == "Down") { _Snake_Body[0].Top = y + 10; SnakeMove(x, y); } //每按一次,判断是否与食物重合 Eat_time(); }
//移动 public void SnakeMove(int x,int y) { //记录XY中间变量 int Temp_X = 0, Temp_Y = 0;
//蛇身移动 for (int i = 1; _Snake_Body[i] != null; i++) { if (i >= 3) { //将记录每个位置都给中间变量 Temp_X = Snake_Boby_content_x; Temp_Y = Snake_Boby_content_y; }
if (i == 1) { Temp_X = _Snake_Body[i].Left; //将改变前的位置记录 X Temp_Y = _Snake_Body[i].Top; //将改变前的位置记录 Y _Snake_Body[i].Left = x; //并且赋值给第一蛇段 _Snake_Body[i].Top = y;//并且赋值给第一蛇段
} else { Snake_Boby_content_x = _Snake_Body[i].Left; //记录蛇段的改变前的位置x Snake_Boby_content_y = _Snake_Body[i].Top;//记录蛇段的改变前的位置y
_Snake_Body[i].Left = Temp_X; //temp_赋给第二-N个蛇段, _Snake_Body[i].Top = Temp_Y; //temp_赋给第二-N个蛇段, } }}
此处关于KeyDown检测不了方向键问题解决方法如下:
protected override bool ProcessDialogKey(Keys keyData) { if (keyData == Keys.Up || keyData == Keys.Down ||
keyData == Keys.Left || keyData == Keys.Right)
return false; else return base.ProcessDialogKey(keyData);
}
重写ProcessDialogKey事件,当keyData为方向键时,返回false不执行系统处理,MSDN是这样解释的
在消息预处理过程中调用此方法,以处理对话框字符,比如 Tab、Return、Esc 和箭头键。只有当 IsInputKey 方法指示控件未在处理该键时,才调用此方法。ProcessDialogKey 方法只是将字符发送给父级的 ProcessDialogKey 方法,或者,在该控件没有父级的情况下返回 false。Form 类重写此方法来执行对话框键的实际处理。仅当控件承载在 Windows 窗体应用程序中或充当 ActiveX 控件时,才调用此方法。
蛇的移动事件主要包括:
1.每隔一段时间执行一次的Timer_Tick方法,蛇的自动移动方法既通过判别Key_Name(键盘状态)来确定自动移动的方向,改变Snake_Boby[0](蛇头)的位置,然后Snake_Boby[0]位置改变后再调用Snake_move方法,Snake_move方法是蛇移动的关键,既根据蛇头位置的改变,对蛇体进行遍历,将蛇头后面每一个元素的位置变为它前一个元素改变之前的位置,实现蛇的移动。2.Form1_KeyDown方法既当this.KeyDown监控到键盘发生变化时,改变Key_Name(键盘状态)的值,并改变蛇头位置,执行Snake_move。3.移动事件最后都要执行Eat_time()方法判断是否与食物相遇。4.食物生成:也是生成一个label控件,并设置大小,text等属性。
public void Snake_food() {
Label Food = new Label { Width = 10, Height =10, Top = _Random.Next(1, 20) * 20, Left = _Random.Next(1, 20) * 20, Text = "❤", Tag = "Food", BackColor = Color.White, ForeColor = Color.Black }; panel1.Controls.Add(Food); }
/// <summary> /// 判断是否吃到实物 /// </summary> public void Eat_time() {
//蛇头部位置 //取得食物的位置 double x1=1 , y1=1 , x2=1 , y2=1; foreach (Label _Label in this.panel1.Controls) { if (_Label.Tag.ToString() == "Food".ToString()) { //食物
x2 = _Label.Left; y2 = _Label.Top; } if (_Label.Tag.ToString() == "0".ToString())//Snake { x1 = _Label.Left; y1 = _Label.Top; }
if (x1 == x2 && y1 == y2) { MessageBox.Show($"{x1},{y1},{x2},{y2}"); //吃掉食物 Snake_Eat(); score++; TxtScore.Text=$"共{score}分"; //将食物移位 更换坐标 foreach (Label lb in this.panel1.Controls) { if (lb.Tag.ToString() == "Food".ToString()) { lb.Top = _Random.Next(1, 20) * 20; lb.Left = _Random.Next(1, 20) * 20; } } } } } /// <summary> /// 吃掉食物 /// </summary> public void Snake_Eat() {
int i = 0; //遍历到蛇尾 for (; _Snake_Body[i] != null; i++) ; MessageBox.Show(i.ToString()); Label Snake_Boby_content = new Label { Width = 10, Height = 10, Top = Snake_Boby_content_x, //蛇尾位置X Left =Snake_Boby_content_y, //蛇尾位置Y BackColor = Color.Black, Text= "▉", Tag=i, }; _Snake_Body[i] = Snake_Boby_content; Snake_Boby_content.BackColor = Color.Black; this.Controls.Add(Snake_Boby_content);
}
开始按钮:
private void Btnstart_Click(object sender, EventArgs e) { this.KeyDown += new KeyEventHandler(FormZyd_KeyDown); timer1.Start() ; this.KeyPreview = true; }
暂停按钮:
private void Btnsuspend_Click(object sender, EventArgs e) { timer1.Stop(); this.KeyPreview = false; }
