簡易貪吃蛇

来源: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
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...