簡易貪吃蛇

来源:http://www.cnblogs.com/rbzz/archive/2017/12/19/8068033.html
-Advertisement-
Play Games

關於貪吃蛇,一直都想做一個,但一直以來奈何總是沒有任何思路,經過這幾天的思索,總算是給弄出來了 主要用到的是 Graphics 現在來看這張圖,這張圖假定每一個單元格是10*10的,那麼在這張圖裡,蛇的每一節就是10*10的大小 可以看出當前蛇的長度是"3"節,假定這一個單元格是10像素的話, 這3 ...


關於貪吃蛇,一直都想做一個,但一直以來奈何總是沒有任何思路,經過這幾天的思索,總算是給弄出來了

主要用到的是 Graphics 

現在來看這張圖,這張圖假定每一個單元格是10*10的,那麼在這張圖裡,蛇的每一節就是10*10的大小

 

 

可以看出當前蛇的長度是"3"節,假定這一個單元格是10像素的話,

這3節蛇身的坐標分別是  0,0    10,0    20,0

預設情況下蛇應該是向右前進的,那麼怎麼模擬蛇身在運動呢?

思路是這樣的,首先在蛇頭也就是最右邊位置(坐標20,0) 的前面(坐標30,0)位置再畫一個藍色的單元格

就像這樣

然後擦掉最左邊的蛇尾(坐標0,0)

就變成這樣了

現在蛇身是不是向右前進一步了

其實就是將橫坐標每次+10,而縱坐標不變

然後一直重覆這個過程,就變成了蛇一直在向右前進

-----------------------------------------------------------頑皮的分割線--------------------------------------------------------

 

接著是上下左右的問題

首先來模擬向下

向下的話,就是在當前的蛇頭位置,例如當前是30,0 這個位置的下方再畫一個藍色單元格

就像這樣的

此時蛇頭的坐標就應該是(30,10),  其實就是將新加的蛇頭的縱坐標加了10

然後擦掉尾部的10,0坐標

然後一直重覆這個過程(也就是橫坐標不變,縱坐標一直加10),就模擬出蛇身向下運動了

 

然後向左的話,就是橫坐標-10 而縱坐標不變

向上的話就是,橫坐標不變,縱坐標-10

 

基本的思路就是這樣,在蛇身運動的過程中不變的增加蛇頭擦除蛇尾

而在更改方向的時候就改變其對應的橫縱坐標.

 

------------------------------------------------------------------------------------俏皮的分割線--------------------------------------------------------------

 

接著說下食物的投放

食物的話,採取隨機投放

但投放的區域是有講究的

例如項目的地圖是一個720*720的方框,蛇身一節是10*10的話,那麼食物的大小也應該是10*10

而食物的投放區域也不應該超出地圖,不然蛇根本吃不到怎麼搞是吧

我一剛開始想的是創建隨機器,然後隨機在0-720以內進行取值

可是,因為你是10*10的大小,如果隨機出來了的橫坐標是3,縱坐標是5的話

那麼這個食物就會出現不在蛇身的運動軌跡上

所以對於食物的投資區域我是( 0-720/食物寬度)*食物寬度,這樣出來的坐標總是能被他的寬度整除

例如如果隨機出來的兩個坐標數字是3和5

那麼經過以上處理出來的坐標就應該是30,50,蛇是肯定能完全吃到的

 

--------------------------------------------------沒用的分割線---------------------------------------------------------------------------

 

好了,現在開始製作代碼方面的事

新建一個窗體程式後,我是打算直接用一個圖片框當地圖的,圖片框的大小設置為720*720

而蛇身和食物的大小都設置為10*10

界面搭建

 

= =| 額,不會搭界面,就這樣吧

然後,直接貼全部的代碼

 

 1 /// <summary>
 2     /// 蛇身或食物的基本塊
 3     /// </summary>
 4     public class Cell
 5     {
 6         /// <summary>
 7         /// 塊的頂點X座標
 8         /// </summary>
 9         public int X { get; set; }
10 
11         /// <summary>
12         /// 塊的頂點Y座標
13         /// </summary>
14         public int Y { get; set; }
15 
16         /// <summary>
17         /// 塊的寬度
18         /// </summary>
19         public int Width { get; set; }
20 
21         /// <summary>
22         /// 塊的高度
23         /// </summary>
24         public int Height { get; set; }
25 
26         /// <summary>
27         /// 所在地圖寬度
28         /// </summary>
29         public int MapWidth { get; set; }
30 
31         /// <summary>
32         /// 所在地圖高度
33         /// </summary>
34         public int MapHeight { get; set; }
35 
36         public Cell() { }
37 
38         public Cell(int x,int y)
39         {
40             this.X = x;
41             this.Y = y;
42         }
43 
44         /// <summary>
45         /// 繪製單元格
46         /// </summary>
47         /// <param name="g"></param>
48         /// <param name="c"></param>
49         public virtual void Draw(Graphics g, Color c)
50         {
51             SolidBrush sb = new SolidBrush(c);
52             g.FillRectangle(sb, this.X, this.Y, this.Width, this.Height);
53 
54         }
55     }
View Code

 

 

 1 /// <summary>
 2     /// 食物類
 3     /// </summary>
 4     public class Food:Cell
 5     {
 6       
 7         public Food() { }
 8 
 9         public Food(int x, int y) : base(x, y)
10         {
11 
12         }
13 
14         /// <summary>
15         /// 創建食物
16         /// </summary>
17         /// <returns></returns>
18         public Food GetFood()
19         {
20 
21             Random r = new Random();
22 
23             ///-------------------------------------------------------
24             ///--因為本例中所使用的地圖是正方形,每一個食物都是在地圖的小正方形中
25             ///其生成的坐標點必須要能被整除,所以下麵才這樣獲取隨機數
26             int rX = (r.Next(0, this.MapWidth / Width)) * Width;
27             int rY = (r.Next(0, this.MapHeight / Width)) * Width;
28             
29 
30             Food Newfood = new Food(rX, rY);
31             Newfood.Width = this.Width;
32             Newfood.Height = this.Height;
33             return Newfood;
34 
35         }           
36     }
View Code

 

 

  1  /// <summary>
  2     /// 蛇類
  3     /// </summary>
  4     public class Snake: Cell
  5     {
  6         /// <summary>
  7         /// 創建食物對象
  8         /// </summary>
  9         Food food = new Food();
 10 
 11         /// <summary>
 12         /// 地圖邊界
 13         /// </summary>
 14       
 15 
 16 
 17         /// <summary>
 18         /// 創建蛇身集合
 19         /// </summary>
 20         public List<Snake> Snakes = new List<Snake>();
 21 
 22         /// <summary>
 23         /// 創建頭部坐標
 24         /// </summary>
 25         public Point Heade;
 26 
 27         public Snake() { }
 28 
 29       
 30 
 31         public Snake(int x, int y)
 32         {
 33             this.X = x;
 34             this.Y = y;
 35             
 36         }
 37 
 38 
 39         /// <summary>
 40         /// 畫形
 41         /// </summary>
 42         /// <param name="g"></param>
 43         /// <param name="c"></param>
 44         public override void Draw(Graphics g, Color c)
 45         {
 46             SolidBrush sb = new SolidBrush(c);
 47 
 48             foreach (var item in Snakes)
 49             {
 50                 //將蛇身每一節畫出來 
 51                 g.FillRectangle(sb, item.X, item.Y,this.Width,this.Height);
 52             }
 53         }
 54 
 55 
 56 
 57         /// <summary>
 58         /// 清除
 59         /// </summary>
 60         /// <param name="g"></param>
 61         /// <param name="c"></param>
 62         public void Clear(Graphics g, Color c)
 63         {
 64             //將尾部一個給塗掉
 65             Snake s = Snakes[0];
 66             SolidBrush sb = new SolidBrush(c);
 67             g.FillRectangle(sb, s.X, s.Y, Width, Height);
 68         }
 69 
 70 
 71         
 72 
 73         /// <summary>
 74         /// 蛇向右走
 75         /// </summary>
 76         /// <param name="g"></param>
 77         /// <param name="c"></param>
 78         public void MoveRight(Graphics g, Color c)
 79         {
 80             //改變橫坐標
 81             Heade.X += Width;       
 82             Snakes.Add(new Snake(Heade.X, Heade.Y));
 83         }
 84 
 85         /// <summary>
 86         /// 向下
 87         /// </summary>
 88         /// <param name="g"></param>
 89         /// <param name="c"></param>
 90         public void MoveDown(Graphics g, Color c)
 91         {
 92             //改變縱坐標
 93             Heade.Y += Height;
 94             Snakes.Add(new Snake(Heade.X, Heade.Y));
 95         }
 96 
 97         /// <summary>
 98         /// 向左
 99         /// </summary>
100         /// <param name="g"></param>
101         /// <param name="c"></param>
102         public void MoveLeft(Graphics g, Color c)
103         {
104             //改變橫坐標
105             Heade.X -= Width;
106             Snakes.Add(new Snake(Heade.X, Heade.Y));
107         }
108       
109         /// <summary>
110         /// 向上
111         /// </summary>
112         /// <param name="g"></param>
113         /// <param name="c"></param>
114         public void MoveUp(Graphics g, Color c)
115         {
116             //改變縱坐標
117             Heade.Y -= Height;
118             Snakes.Add(new Snake(Heade.X, Heade.Y));
119         }
120 
121         /// <summary>
122         /// 判斷當前是否吃到食物
123         /// </summary>
124         /// <param name="food"></param>
125         /// <returns></returns>
126         public bool EatFood(Food food)
127         {
128 
129             //拿到蛇頭所在
130             Snake end = Snakes.Last();
131 
132             //拿到蛇頭位置
133             Point snakeHead = new Point(end.X, end.Y);
134 
135             //拿到食物座標
136             Point foodPos = new Point(food.X, food.Y);
137 
138             //如果當前的蛇頭座標與當前的食物座標重疊
139             if (snakeHead.X == foodPos.X && snakeHead.Y == foodPos.Y)
140             {
141                 //已經吃到食物了
142                 return true;
143             }
144             else
145             {
146                 return false;
147             }
148 
149         }
150 
151 
152         /// <summary>
153         /// 判斷 是否蛇頭撞到了自己
154         /// </summary>
155         /// <returns>返回true則未撞到</returns>
156         public bool HitBOdy()
157         {
158             //蛇頭現在的位置是否在除蛇頭之外蛇身內
159             
160             //沒有撞到
161             bool falg = false;
162 
163             //拿到蛇頭所在
164             Snake end = Snakes.Last();
165 
166             //拿到蛇頭位置
167             Point snakeHead = new Point(end.X, end.Y);
168 
169             //判斷蛇頭是否在除蛇頭之外的蛇身內
170             for (int i = 0; i < Snakes.Count-1; i++)
171             {
172                 //如果在
173                 if (Snakes[i].X == snakeHead.X && Snakes[i].Y == snakeHead.Y)
174                 {
175                     //撞到自己
176                     falg = true;
177                     break;
178                 }
179                 else
180                 {
181                     falg = false;
182                 }
183             }
184             return falg;
185         }
186 
187         /// <summary>
188         /// 判斷是否跑出了地圖
189         /// </summary>
190         /// <returns></returns>
191         public bool HitMap()
192         {
193             ///判斷當前蛇頭位置是否在地圖外面
194             if (Heade.X < 0 || Heade.X > this.MapWidth || Heade.Y < 0 || Heade.Y > this.MapHeight)
195             {
196                 return true;
197             }
198             else
199             {
200                 return false;
201             }
202         }
203     }
View Code

 

 

 1  /// <summary>
 2     /// 等級增長類
 3     /// </summary>
 4     public static class Level
 5     {
 6         /// <summary>
 7         /// 等級增長,傳入蛇身的長度,每當增長的長度就減少時間間隔(增長蛇的行動速度)
 8         /// </summary>
 9         /// <param name="count">蛇身當前長度</param>
10         /// <param name="length">當增長到一定的節數</param>
11         /// <param name="time">當前計時器間隔時間</param>
12         /// <param name="speed">每次減去的速度</param>
13         /// <returns></returns>
14         public static int levelUp(int count,int length, int time,int speed)
15         {
16             if (count%length==0&&time>0)
17             {
18                 time -= speed;
19             }
20             return time;
21         }
22     }
View Code

 

 

public partial class 貪吃蛇 : Form
    {

        public 貪吃蛇()
        {
            InitializeComponent();

        }

        /// <summary>
        /// 蛇身朝向
        /// </summary>
        private enum Direction { left, right, up, down }

        /// <summary>
        /// 初始化朝向為右
        /// </summary>
        private Direction de = Direction.right;

        /// <summary>
        /// 初始化蛇
        /// </summary>
        Snake snake = new Snake();

        /// <summary>
        /// 創建食物
        /// </summary>
        Food food = null;



        private void 貪吃蛇_Paint(object sender, PaintEventArgs e)
        {
            //創建一張點陣圖,大小就為圖片框的大小
            Bitmap bitmap = new Bitmap(this.pictureBox1.ClientSize.Width, this.pictureBox1.ClientSize.Height);
            Graphics g = Graphics.FromImage(bitmap);

            //畫出初始蛇身
            snake.Draw(g, Color.White);

            //畫出初始食物
            food.Draw(g, Color.Red);

            this.pictureBox1.Image = bitmap;

        }

        /// <summary>
        ///  開始
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            timer1.Enabled = true;
        }

        /// <summary>
        /// 創建對象
        /// </summary>
        Graphics gp;


        private void timer1_Tick(object sender, EventArgs e)
        {
            ///邏輯為:
            ///  模擬蛇身在運動
            ///  即先讓蛇尾那一格塗成和背景色一樣,然後判斷方向,
            ///  在相應的方向增加蛇頭位置,之後再將新蛇頭畫出來

            ///創建畫板
            gp = pictureBox1.CreateGraphics();

            //取到當前的蛇頭座標以備後面的移動時提取
            snake.Heade = new Point(snake.Snakes.Last().X, snake.Snakes.Last().Y);

            //清除蛇尾
            snake.Clear(gp, pictureBox1.BackColor);

            //判斷是否吃到食物,吃到了就不再移除蛇尾,當做是吃了食物增長了一節
            if (snake.EatFood(food))
            {
                //假如已經吃了就再獲取一次食物
                food = food.GetFood();

                //將重新獲取到食物對象賦值
                food.MapHeight = pictureBox1.Height;
                food.MapWidth = pictureBox1.Width;

                //畫出重新獲取到的食物
                food.Draw(gp, Color.Red);

                //每增長5節數減10速度
                timer1.Interval = Level.levelUp(snake.Snakes.Count, 5, timer1.Interval, 10);

                lbSpeed.Text = timer1.Interval.ToString();
            }
            else
            {
                //移除蛇尾
                snake.Snakes.RemoveAt(0);
            }

            //判斷行進方向
            switch (de)
            {
                case Direction.left:
                    snake.MoveLeft(gp, Color.Red);
                    break;
                case Direction.right:
                    snake.MoveRight(gp, Color.Red);
                    break;
                case Direction.up:
                    snake.MoveUp(gp, Color.Red);
                    break;
                case Direction.down:
                    snake.MoveDown(gp, Color.Red);
                    break;
                default:
                    break;
            }

            //畫出整個蛇身
            snake.Draw(gp, Color.White);


            //判斷邊界
            if (snake.HitBOdy())
            {
                timer1.Stop();
                MessageBox.Show("撞到自己了,游戲結束");

                //將開始按鈕禁用
                btnStart.Enabled = false;
                return;
            }
            if (snake.HitMap())
            {
                timer1.Stop();
                MessageBox.Show("撞到牆了,游戲結束");

                //將開始按鈕禁用
                btnStart.Enabled = false;
                return;
            }

            lbSnakeCount.Text = snake.Snakes.Count.ToString();
        }

        /// <summary>
        /// 窗體初始化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 貪吃蛇_Load(object sender, EventArgs e)
        {
            timer1.Interval = hScrollBar1.Value;
            lbSpeed.Text = hScrollBar1.Value.ToString();
            lbSnakeCount.Text = snake.Snakes.Count.ToString();

            //--初始化蛇的各項數值
            snake.Width = 10;
            snake.Height = 10;
            snake.MapHeight = pictureBox1.Height;
            snake.MapWidth = pictureBox1.Width;

            //--增加蛇身
            snake.Snakes.Add(new Snake(0, 0));
            snake.Snakes.Add(new Snake(10, 0));
            snake.Snakes.Add(new Snake(20, 0));
            snake.Snakes.Add(new Snake(30, 0));

            //--初始化食物的各項數值
            food = new SnakeGame.Food(100, 100);
            food.Width = 10;
            food.Height = 10;
            food.MapWidth = pictureBox1.Width;
            food.MapHeight = pictureBox1.Height;
        }


        /// <summary>
        /// 判斷當前的按鍵
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_KeyDown(object sender, KeyEventArgs e)
        {
            //根據當前的按鍵將朝向對應起來
            switch (e.KeyCode)
            {
                case Keys.W:
                    de = Direction.up;
                    break;
                case Keys.S:
                    de = Direction.down;
                    break;
                case Keys.D:
                    de = Direction.right;
                    break;
                case Keys.A:
                    de = Direction.left;
                    break;
            }

        }

        /// <summary>
        /// 暫停按鈕
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnPause_Click(object sender, EventArgs e)
        {
            timer1.Enabled = false;
        }

        /// <summary>
        /// 重新開始
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            //重新開始,初始化各

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 想要爬取動態網頁,很莫名的click失效。被這個問題困擾了很久,基本上把網上提到的所有方法試遍了,最終終於有個方法成功了,在這裡總結一下。 這是我想要點擊的網頁,初始時實在0.5km上,它的class屬性是‘on’,想要點擊到2km 方法一:直接用webdriver的click方法,失效。 text ...
  • spring boot 裡面用攔截器好像比用過濾器多一點. 在過濾器中, 並不能獲取到action的相關信息, 會造成很多的麻煩和功能欠缺. 那, 這裡就用過濾器做一個小慄子, 實際使用過程中, 不會這麼做的. 用過濾器做一個不完善的登錄許可權判斷. 一. 過濾器 在這裡慄子里, 應該在過濾器裡面加個 ...
  • pycharm常用快捷鍵 1、編輯(Editing) Ctrl + Space 基本的代碼完成(類、方法、屬性)Ctrl + Alt + Space 快速導入任意類Ctrl + Shift + Enter 語句完成Ctrl + P 參數信息(在方法中調用參數) Ctrl + Q 快速查看文檔 F1 ...
  • let mview = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)) //獲取delegate let delegate = UIAp ...
  • 用JdbcTemplate的方法完成, 查詢資料庫表,把用戶表sw_user所有數據以List<User>集合返回 在JdbcTemplateDemo類中增加查詢返回所有對象集合的方法queryAllObject() 數據源DriverManagerDataSource不變 jdbcTemplate ...
  • 在EF 中使用mysql關聯取數據時,如果當前實體中包含另一個實體的list成員,而這個成員為空的話,在json序列化的時候就會報錯: '((System.Data.Entity.DynamicProxies.T_Module_FA775BC9946D7E533F86AFE9B59A3A33C411 ...
  • 1.中文亂碼問題 利用ef更新數據到mysql資料庫中,中文就會變成亂碼"???",就算把mysql的資料庫的編碼設置為"utf8"也會變成亂碼,從網上查詢了下, 在數據連接字元串後面加上:Character Set=utf8;即可,這樣插入mysql的中文就不會變成亂碼了。 2.HTML文本亂碼問 ...
  • 一.什麼是I/0流? 英文翻譯:Inout/Output,在程式里簡單的理解為讀寫數據操作數據的意思。流操作是為瞭解決體積大數據占用太多的記憶體,就是分段進行操作。就跟我們吃飯一樣,一口一口的吃,還沒見過誰直接一口吃完的。流就是細水長流。 在我們強大的Net中,就是微軟為了簡化我們的工作,為了我們能對 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...