1. 程式人生 > >C#winform 經典小遊戲貪吃蛇V1.0(一)

C#winform 經典小遊戲貪吃蛇V1.0(一)

關於V1.0

  為什麼我給這個版本定義為V1.0嘞,因為在這個版本中僅僅實現了蛇的自動行進,按鍵對蛇的行進方向的操作和吃掉食物蛇身的增長等操作。
但是任何事情都必須一步一步來,當我們完成這個乞丐版的貪吃蛇,就為我們版本的更新打下了基礎。

思路

首先我們生成一個空白的的窗體,然後再放一個timer控制元件,好了我們的遊戲介面就建好了。
直接寫後臺程式碼。
沒錯就是這麼簡陋,
你可能會問:”蛇喃?“,
別急,別急,
我們的蛇體和食物為在後臺生成的label控制元件,
我們通過控制label控制元件在介面的顯示來表示蛇的移動和生長!
這裡寫圖片描述

開整

生成成員變數

程式碼中Key_Name

為記錄鍵盤狀態的變數,初始為start
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

為蛇的移動事件,既每隔一次timer.Tick執行一次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