C#winform 經典小遊戲貪吃蛇V1.0(一)
關於V1.0
為什麼我給這個版本定義為V1.0嘞,因為在這個版本中僅僅實現了蛇的自動行進,按鍵對蛇的行進方向的操作和吃掉食物蛇身的增長等操作。
但是任何事情都必須一步一步來,當我們完成這個乞丐版的貪吃蛇,就為我們版本的更新打下了基礎。
思路
首先我們生成一個空白的的窗體,然後再放一個timer控制元件,好了我們的遊戲介面就建好了。
直接寫後臺程式碼。
沒錯就是這麼簡陋,
你可能會問:”蛇喃?“,
別急,別急,
我們的蛇體和食物為在後臺生成的label控制元件,
我們通過控制label控制元件在介面的顯示來表示蛇的移動和生長!
開整
生成成員變數
程式碼中Key_Name
label標籤的陣列Snake_Boby
隨機數R
記錄位置的兩個變數
//定義成員變數
/// <summary>
/// 鍵盤狀態,初始為 start
/// </summary>
string Key_Name = "start";
/// <summary>
/// 蛇身陣列
/// </summary>
Label[] Snake_Boby = new Label[3000];
/// <summary>
/// 隨機數,用於生成food
/// </summary>
Random R = new Random();
/// <summary>
/// 記錄位置
/// </summary>
int Snake_Boby_content_x = 0, Snake_Boby_content_y = 0;
貪吃蛇的初始化
在窗體的初始化事件Form1_Load中新增長度為5個label的蛇身
一個label的初始大小為10*10,並設定其的一些屬性。
其中
Timer_Tick
Form1_KeyDown為對鍵盤的監控
Snake_food()為食物的生成事件
private void Form1_Load(object sender, EventArgs e)
{
this.Top = 120;
this.Left = 120;
this.Width = 800;
this.Height = 800;
this.BackColor = Color.Blue;
//初始化一個label蛇體,長度為5個label,一個label height= width = 10
for (int i = 0; i < 8; i++)
{
//蛇段
Label Snake_Boby_content = new Label();
Snake_Boby_content.Height = 10;
Snake_Boby_content.Width = 10;
//蛇段的位置
Snake_Boby_content.Top = 400;
Snake_Boby_content.Left = 400 - i * 10;
//背景色
this.BackColor = Color.White;
Snake_Boby_content.BackColor = Color.Black;
Snake_Boby_content.Text = "▉";
//獲取或設定包含有關控制元件的資料的物件。
Snake_Boby_content.Tag = i;
//加入蛇體
Snake_Boby[i] = Snake_Boby_content;
this.Controls.Add(Snake_Boby_content);
}
//每隔一段時間發生一次右移
timer.Tick += new EventHandler(Timer_Tick);
//按鍵時發生的事件監控
this.KeyDown += new KeyEventHandler(Form1_KeyDown);
Snake_food(); //food 生成
timer.Start(); //Timer 開始計時
}
蛇的移動事件
蛇的移動事件為整個程式的關鍵程式碼,
下面一大溜都是(⓿_⓿)
肯定有人會說博主又要偷懶了,直接把程式碼複製貼上不管事了( ఠൠఠ )ノ
哼!
把我當成什麼人了?
好的那讓我們來看下一個事件!食物的生成!
/// <summary>
/// 對鍵盤按鍵輸入的響應
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void Form1_KeyDown(object sender, KeyEventArgs e)
{
int x, y;
x = Snake_Boby[0].Left;
y = Snake_Boby[0].Top;
//獲取鍵盤程式碼
Key_Name = e.KeyCode.ToString();
if (Key_Name == "Right") //向右
{
Snake_Boby[0].Left = x + 10;
Snake_move(x, y);
}
if (Key_Name == "Up") //向上
{
Snake_Boby[0].Top = y - 10;
Snake_move(x, y);
}
if (Key_Name == "Down") //向下
{
Snake_Boby[0].Top = y + 10;
Snake_move(x, y);
}
if (Key_Name == "Left") //向左
{
Snake_Boby[0].Left = x - 10;
Snake_move(x, y);
}
//每按一次,判斷是否與食物重合
Eat_time();
}
/// <summary>
/// snake的自動移動事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void Timer_Tick(object sender, EventArgs e)
{
//用來記錄snake的head的xy座標
int x, y;
x = Snake_Boby[0].Left;
y = Snake_Boby[0].Top;
if (Key_Name == "start") //鍵盤狀態處於初始狀態
{
Snake_Boby[0].Left = x + 10;//Snake_Boby[0]右移10
Snake_move(x, y);//呼叫
}
if (Key_Name == "Right") //鍵盤狀態處於 向右 狀態
{
Snake_Boby[0].Left = x + 10;
Snake_move(x, y);
}
if (Key_Name == "Up") //鍵盤狀態處於 向上 狀態
{
Snake_Boby[0].Top = y - 10;
Snake_move(x, y);
}
if (Key_Name == "Down") //鍵盤狀態處於 向下 狀態
{
Snake_Boby[0].Top = y + 10;
Snake_move(x, y);
}
if (Key_Name == "Left") //鍵盤狀態處於 向左 狀態
{
Snake_Boby[0].Left = x - 10;
Snake_move(x, y);
}
// 穿牆設定
if (x > 800)
{
Snake_Boby[0].Left = 0; ;
}
if (x < 0)
{
Snake_Boby[0].Left = 800;
}
if (y > 600)
{
Snake_Boby[0].Top = 0;
}
if (y < 0)
{
Snake_Boby[0].Top = 600;
}
//每動一次,判斷是否與食物重合
Eat_time();
}
/// <summary>
/// 蛇身移動事件
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public void Snake_move(int x, int y)
{
//記錄xy的中間變數
int temp_x = 0, temp_y = 0;
//遍歷蛇身進行移動
for (int i = 1; Snake_Boby[i] != null; i++)
{
if(i >= 3)
{
//將記錄的前一個蛇段位置賦給中間變數
temp_x = Snake_Boby_content_x;
temp_y = Snake_Boby_content_y;
}
if (i == 1)
{
//將記錄蛇頭的改變前的位置的x y賦給第一個蛇段,並記錄蛇段的位置
temp_x = Snake_Boby[i].Left;
temp_y = Snake_Boby[i].Top;
Snake_Boby[i].Left = x;
Snake_Boby[i].Top = y;
}
else
{
//將記錄前一個個蛇段的改變前的位置temp_賦給第二個蛇段,並記錄改前位置
Snake_Boby_content_x = Snake_Boby[i].Left;
Snake_Boby_content_y = Snake_Boby[i].Top;
Snake_Boby[i].Left = temp_x;
Snake_Boby[i].Top = temp_y;
}
}
}
當然不是!(o゚v゚)ノ
蛇的移動事件主要包括:
- 上一個事件中我們用到的每隔一段時間執行一次的Timer_Tick方法,蛇的自動移動方法既通過判別Key_Name(鍵盤狀態)來確定自動移動的方向,改變Snake_Boby[0](蛇頭)的位置,然後Snake_Boby[0]位置改變後再呼叫Snake_move方法,
- Snake_move方法是蛇移動的關鍵,既根據蛇頭位置的改變,對蛇體進行遍歷,將蛇頭後面每一個元素的位置變為它前一個元素改變之前的位置,實現蛇的移動。
- Form1_KeyDown方法既當this.KeyDown監控到鍵盤發生變化時,改變Key_Name(鍵盤狀態)的值,並改變蛇頭位置,執行Snake_move
- 並且這些移動事件最後都要執行Eat_time()方法判斷是否與食物相遇
食物生成
也是生成一個label控制元件,並設定大小,text等屬性
/// <summary>
/// Food的生成事件
/// </summary>
public void Snake_food()
{
Label Food = new Label();
Food.Width = 20;
Food.Height = 20;
//生成一個隨機位置的food
Food.Top = R.Next(1, 20) * 20;
Food.Left = R.Next(1, 20) * 20;
Food.Text = "❤";
Food.Tag = "food";
Food.BackColor = Color.White;
this.Controls.Add(Food);
}
蛇吃食物事件
主要包括:
- Eat_time方法判別是否和蛇頭相遇,如果相遇,呼叫Snake_eat方法蛇長加一,且改變食物位置
- Snake_eat遍歷到蛇尾部,生成一個label位置設為,蛇尾改變前的位置。
public void Eat_time()
{
double x1 = 20, y1 = 20, x2 = 20, y2 = 20;
//遍歷Controls中所有label
foreach (Label lb in this.Controls)
{
//如果lb為food,將label的位置記錄
if (lb.Tag.ToString() == "food".ToString())
{
x2 = lb.Left;
y2 = lb.Top;
}
//如果label為snake,將label的位置記錄
if (lb.Tag.ToString() == "0".ToString())
{
x1 = lb.Left;
y1 = lb.Top;
}
}
if (x2 == x1 && y2 == y1)
{
Snake_eat();
//將食物移位
foreach (Label lb in this.Controls)
{
if (lb.Tag.ToString() == "food".ToString())
{
lb.Top = R.Next(1, 20) * 20;
lb.Left = R.Next(1, 20) * 20;
}
}
}
}
/// <summary>
/// 蛇觸碰到食物的事件
/// </summary>
private void Snake_eat()
{
int i = 0;
//遍歷到蛇尾
for (; Snake_Boby[i] != null; i++) ;
//蛇觸碰到food蛇段加一,定義蛇段
Label Snake_Boby_content = new Label();
Snake_Boby_content.Width = 10;
Snake_Boby_content.Height = 10;
Snake_Boby_content.Top = Snake_Boby_content_y;
Snake_Boby_content.Left = Snake_Boby_content_x;
Snake_Boby_content.BackColor = Color.White;
Snake_Boby_content.Text = "▉";
Snake_Boby_content.Tag = i;
Snake_Boby[i] = Snake_Boby_content;
Snake_Boby_content.BackColor = Color.Black;
this.Controls.Add(Snake_Boby_content);
}
效果
最後
我們的乞丐版貪吃蛇就完成了!
如果你按照我的步驟一步一步來,就會體驗到你的Snake,
從From_Load出現到你的螢幕上,然後Snake_move它開始單調得向右移動,
Form1_KeyDown and Timer_Tick 它開始按照你的意思開始移動,上下左右,來回穿梭
Snake_food你的螢幕上出現一個愛心形狀的食物,但是你吃不到它
Eat_time and Snake_eat 終於它變成了你期待的樣子
可是它似乎又缺點啥?
程式設計總是這樣,它誘惑我們去得到我們期待的東西,我們一步步接近我們的期待,這個過程可能充滿曲折,但卻是充滿的驚喜,當我們似乎得到我們想要的後,卻又發現好像還有那麼一段距離
GitHub