關於貪吃蛇需要用的對象: 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_Tick
Form1_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);
}
蛇吃食物事件 :
- Eat_time方法判別是否和蛇頭相遇,如果相遇,調用Snake_eat方法蛇長加一,且改變食物位置
- Snake_eat遍歷到蛇尾部,生成一個label位置設為蛇尾。
- 吃掉一次食物加分,並且
/// <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;
}