基於C#開發的簡易貪吃蛇


最近一直忙着11月份軟考的復習,一直沒有練習C#。覺得對於一個新手,長時間不練肯定不行,所以覺得敲敲代碼練練手。剛好電腦磁盤里有以前Down的C#開源游戲,於是挑中了貪吃蛇,來練練手。

貪吃蛇游戲界面如下:

為了實現貪吃蛇,一共寫了四個類,分別是:

1)Bean:食物類,就是玩家要吃的那個食物,里面實現了兩個方法:食物的顯示與食物的消失(因為食物被吃了以后應該消失)

2)Block:蛇塊類,就是組成蛇的單元,玩家吃到食物,蛇的蛇塊增加一節。

3)Snake:蛇類,游戲中的主角,玩家通過上下左右四個鍵來控制蛇的運動。

4)Map:地圖類,用於畫出游戲主界面,通過定時器來控制,每個單元時間重新畫一幅地圖,用於動態顯示

以下是代碼的實現

 1 //食物類
 2     public class Bean
 3     {
 4         //用於畫食物的頂端坐標
 5         private Point _origin;
 6 
 7         public Point Origin
 8         {
 9             get { return _origin; }
10             set { _origin = value; }
11         }
12 
13         //顯示食物
14         public void ShowBean(Graphics g)
15         {
16             //定義紅色的畫筆
17             SolidBrush brush = new SolidBrush(Color.Red);
18             //畫實心矩形表示食物
19             g.FillRectangle(brush,Origin.X,Origin.Y,15,15);
20         }
21 
22         public void UnShowBean(Graphics g)
23         {
24             //定義系統背景顏色的畫筆
25             SolidBrush brush = new SolidBrush(Color.Silver);
26             //畫實心矩形顏色為系統背景顏色,相當於食物被吃掉了
27             g.FillRectangle(brush,Origin.X,Origin.Y,15,15);
28         }
29     }
//蛇身體的每一單元,簡稱塊
    public class Block
    {
        //是否為蛇頭
        private bool _isHead;

        public bool IsHead
        {
            get { return _isHead; }
            set { _isHead = value; }
        }
        //蛇塊的編號
        private int _blockNumber;

        public int BlockNumber
        {
            get { return _blockNumber; }
            set { _blockNumber = value; }
        }
        //蛇塊的左上角位置
        private Point _origin;

        public Point Origin
        {
            get { return _origin; }
            set { _origin = value; }
        }

        //根據指定位置畫蛇塊
        public void ShowBlock(Graphics g)
        {
            Bitmap bitMap;
            if (IsHead)
            {
                //蛇頭
                bitMap = new Bitmap(Image.FromFile("Blue.gif"));                
            }
            else
            {
                bitMap = new Bitmap(Image.FromFile("Yellow.gif"));
            }
            g.DrawImage(bitMap,Origin.X,Origin.Y,15,15);
        }

        //消除蛇塊
        public void UnShowBlock(Graphics g)
        {
            SolidBrush brush = new SolidBrush(Color.Silver);
            g.FillRectangle(brush,Origin.X,Origin.Y,15,15);
        }
    }
  1 public class Snake
  2     {
  3         //用於存放蛇的集合
  4         private List<Block> blocksList;
  5         //0-上,1-右,2-下,3-左
  6         private int direction = 1;
  7         //蛇頭的編號,蛇的長度
  8         private int headNumber;
  9         //蛇頭左上角坐標
 10         private Point headPoint;
 11         private Point mapLeft;
 12         //游戲開始時,初始的蛇
 13         public Snake(Point map, int count)
 14         {
 15             mapLeft = map;
 16             Block blockSnake;
 17             //定義蛇的起始位置(蛇尾)
 18             Point p = new Point(map.X + 15, map.Y + 15);
 19             blocksList = new List<Block>();
 20             //循環畫蛇塊用於填充蛇集合
 21             for (int i = 0; i < count; i++)
 22             {
 23                 //x坐標加15
 24                 p.X += 15;
 25                 //實例化蛇塊
 26                 blockSnake = new Block();
 27                 //定義蛇塊的左上角位置 
 28                 blockSnake.Origin = p;
 29                 //定義蛇塊的編號1,2,3...
 30                 blockSnake.BlockNumber = i + 1;
 31                 if (i == count - 1)
 32                 {
 33                     //蛇頭
 34                     //給蛇頭位置賦值
 35                     headPoint = blockSnake.Origin;
 36                     blockSnake.IsHead = true;
 37                 }
 38                 blocksList.Add(blockSnake);
 39 
 40             }
 41             //蛇的長度賦值
 42             headNumber = count;
 43         }
 44         //蛇頭坐標的只讀屬性
 45         public Point HeadPoint
 46         {
 47             get { return headPoint; }
 48         }
 49         //蛇的運動方向的屬性
 50         public int Direction
 51         {
 52             get { return direction; }
 53             set { direction = value; }
 54         }
 55         /// <summary>
 56         /// 蛇的轉換方向
 57         /// </summary>
 58         /// <param name="pDirection">想要改變的方向</param>
 59         public void TurnDirection(int pDirection)
 60         {
 61             switch (direction)
 62             {
 63                 //原來向上運動
 64                 case 0:
 65                     //希望向左運動
 66                     if (pDirection == 3)
 67                         direction = 3;
 68                     //希望向右運動
 69                     else if (pDirection == 1)
 70                         direction = 1;
 71                     break;
 72                 //原來向右運動
 73                 case 1:
 74                     //
 75                     if (pDirection == 2)
 76                         direction = 2;
 77                     //
 78                     else if (pDirection == 0)
 79                         direction = 0;
 80                     break;
 81                 case 2:
 82                     if (pDirection == 1)
 83                         direction = 1;
 84                     else if (pDirection == 3)
 85                         direction = 3;
 86                     break;
 87                 case 3:
 88                     if (pDirection == 0)
 89                         direction = 0;
 90                     else if (pDirection == 2)
 91                         direction = 2;
 92                     break;
 93 
 94 
 95             }
 96         }
 97 
 98         public Point getHeadPoint //只讀蛇頭位置屬性
 99         {
100             get { return headPoint; }
101         }
102         //蛇吃到食物后變長,蛇頭+1
103         public void SnakeGrowth()
104         { 
105             //找到蛇頭的坐標
106             Point head = blocksList[blocksList.Count - 1].Origin;
107             int x = head.X;
108             int y = head.Y;
109             //判斷蛇的運動方向,改變蛇頭的位置
110             switch (direction)
111             {
112                 case 0:
113                     //向上運動
114                     y -= 15;
115                     break;
116                 case 1:
117                     x += 15;
118                     break;
119                 case 2:
120                     y += 15;
121                     break;
122                 case 3:
123                     x -= 15;
124                     break;
125             }
126             //把原先蛇頭的塊變為普通塊
127             blocksList[blocksList.Count - 1].IsHead = false;
128             //實例化新蛇頭
129             Block headNew = new Block();
130             headNew.IsHead = true;
131             headNew.BlockNumber = blocksList.Count + 1;
132             headNew.Origin = new Point(x,y);
133             blocksList.Add(headNew);
134             headNumber++;
135             headPoint = headNew.Origin;
136         }
137 
138         //蛇向前運動(沒有吃到食物的情況),蛇尾移除,蛇頭移位+1
139         public void Go(Graphics g)
140         {
141             Block snakeTail = blocksList[0];
142             //消除蛇尾塊
143             snakeTail.UnShowBlock(g);
144             //集合中移除設為塊
145             blocksList.RemoveAt(0);
146             foreach (var item in blocksList)
147             {
148                 item.BlockNumber--;
149             }
150             //由於SnakeGrowth中僅僅使蛇頭+1,但是headNumber++了。但是此值並沒有改變,所以先--
151             headNumber--;
152             SnakeGrowth();
153         }
154 
155         //畫出蛇
156         public void ShowSnake(Graphics g)
157         {
158             foreach (var item in blocksList)
159             {
160                 item.ShowBlock(g);
161             }
162         }
163         //隱藏蛇
164         public void UnShowSnake(Graphics g)
165         {
166             foreach (var item in blocksList)
167             {
168                 item.UnShowBlock(g);
169             }
170         }
171         //重置蛇
172         public void Reset(Point map, int count)
173         {  
174             Block blockSnake;
175             //定義蛇的起始位置(蛇尾)
176             Point p = new Point(mapLeft.X + 15, mapLeft.Y + 15);
177             blocksList = new List<Block>();
178             //循環畫蛇塊用於填充蛇集合
179             for (int i = 0; i < count; i++)
180             {
181                 //x坐標加15
182                 p.X += 15;
183                 //實例化蛇塊
184                 blockSnake = new Block();
185                 //定義蛇塊的左上角位置 
186                 blockSnake.Origin = p;
187                 //定義蛇塊的編號1,2,3...
188                 blockSnake.BlockNumber = i + 1;
189                 if (i == count - 1)
190                 {
191                     //蛇頭
192                     //給蛇頭位置賦值
193                     headPoint = blockSnake.Origin;
194                     blockSnake.IsHead = true;
195                 }
196                 blocksList.Add(blockSnake);
197 
198             }
199             //蛇的長度賦值
200             headNumber = count;
201             direction = 1;
202         }
203         //是否碰到自己
204         public bool IsTouchMyself()
205         {
206             bool isTouched = false;
207             for (int i = 0; i < blocksList.Count-1; i++)
208             {
209                 if (headPoint == blocksList[i].Origin)
210                 {
211                     isTouched = true;
212                     break;
213                 }
214             }
215             return isTouched;
216         }
217     }
  1 public class Map
  2     {
  3         private Point mapLeft;
  4         private static int unit = 15;
  5         //定義地圖長,為28個蛇塊的長度
  6         private readonly int length = 30 * unit;
  7         //定義地圖寬,為20個蛇塊的寬度
  8         private readonly int width = 25 * unit;
  9         //定義分數
 10         public int score = 0;
 11         //定義蛇
 12         private readonly Snake snake;
 13         public bool victory = false;
 14         public Snake Snake
 15         {
 16             get { return snake; }
 17         } 
 18 
 19         Bean food;
 20         public Map(Point start)
 21         {
 22             //把地圖左上角的點的值賦值給全局變量
 23             mapLeft = start;
 24             //實例化蛇
 25             snake = new Snake(start,5);
 26             //實例化食物
 27             food = new Bean();
 28             food.Origin = new Point(start.X+30,start.Y+30);
 29         }
 30         //顯示新食物
 31         public void ShowNewFood(Graphics g)
 32         {
 33             //消除原先食物
 34             food.UnShowBean(g);
 35             //產生隨機位置的食物
 36             food = FoodRandom();
 37             //顯示食物
 38             food.ShowBean(g);
 39         }
 40         //隨機產生一個新食物
 41         private Bean FoodRandom()
 42         {
 43             Random d=new Random ();
 44             int x = d.Next(0, length / unit);
 45             int y = d.Next(0, width / unit);
 46             Point origin = new Point(mapLeft.X+x*15,mapLeft.Y+y*15);
 47             Bean food = new Bean();
 48             food.Origin = origin;
 49             return food;
 50         }
 51         //畫地圖
 52         public void ShowMap(Graphics g)
 53         {
 54             //創建一支紅筆
 55             Pen pen = new Pen(Color.Blue);
 56             //畫出地圖的框
 57             g.DrawRectangle(pen,mapLeft.X,mapLeft.Y,length,width);
 58             //顯示食物
 59             food.ShowBean(g);
 60             if (CheckBean())
 61             {
 62                 //吃到了食物
 63                 //顯示新食物
 64                 ShowNewFood(g);
 65                 //蛇變長
 66                 snake.SnakeGrowth();
 67                 //分數增加
 68                 score += 10;
 69                 //if (score >= 100)
 70                 //{
 71                 //    victory = true;
 72                 //}
 73                 //顯示蛇
 74                 snake.ShowSnake(g);
 75             }
 76             else
 77             {
 78                 snake.Go(g);
 79                 snake.ShowSnake(g);
 80             }
 81         }
 82         //判斷是否吃到了食物
 83         public bool CheckBean()
 84         {
 85             
 86             return food.Origin.Equals(snake.HeadPoint);
 87         }
 88 
 89         //檢查蛇是否撞牆
 90         public bool CheckSnake()
 91         {
 92             return !(snake.getHeadPoint.X > mapLeft.X-5 && snake.getHeadPoint.X < (mapLeft.X + length-5) && snake.getHeadPoint.Y > mapLeft.Y-5 && snake.getHeadPoint.Y < (mapLeft.Y + width -5));
 93         }
 94 
 95         //重新開始
 96         public void Reset(Graphics g)
 97         {
 98             snake.UnShowSnake(g);
 99             snake.Reset(mapLeft,5);
100         }
101     }
  1 這是窗體的代碼
  2 public frmMain()
  3         {
  4             InitializeComponent();
  5             //定義地圖
  6             map = new Map(new Point(50,50));
  7             BackColor = Color.Silver;
  8         }
  9         private readonly Map map;
 10         private int gradeNum = 100;
 11         private int pink;
 12         private void frmMain_Load(object sender, EventArgs e)
 13         {
 14             SetStyle(
 15                ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
 16             UpdateStyles();
 17         }
 18 
 19         private void timer1_Tick(object sender, EventArgs e)
 20         {
 21             //this.BackgroundImage = Image.FromFile(pink+".jpg");
 22             開始ToolStripMenuItem.Text = "重新開始";           
 23             lblScore.Text = map.score.ToString();
 24             if (map.score >= 500)
 25             {
 26                 timer1.Enabled = false;
 27                 MessageBox.Show("恭喜,成功!!!");
 28             }
 29             Bitmap bmp = new Bitmap(Width, Height);
 30             //Image face = Image.FromFile("1.jpg");
 31             BackgroundImage = bmp;
 32             Graphics g = Graphics.FromImage(bmp);
 33             map.ShowMap(g);
 34             if (map.CheckSnake()||map.Snake.IsTouchMyself())
 35             {
 36                 timer1.Enabled = false;
 37                 MessageBox.Show("很遺憾,失敗了!!!");
 38             }
 39             
 40         }
 41         //鍵盤響應事件
 42         private void frmMain_KeyDown(object sender, KeyEventArgs e)
 43         {
 44             int k, d = 0;
 45             k = e.KeyValue;
 46             if (k == 37) //
 47                 d = 3;
 48             else if (k == 40) //
 49                 d = 2;
 50             else if (k == 38) //
 51                 d = 0;
 52             else if (k == 39) //
 53                 d = 1;
 54             map.Snake.TurnDirection(d);
 55         }
 56 
 57         private void 開始ToolStripMenuItem_Click(object sender, EventArgs e)
 58         {
 59             if (lblGrade.Text == "")
 60             {
 61                 MessageBox.Show("請先選擇級別");
 62                 return;
 63             }
 64             if (開始ToolStripMenuItem.Text == "開始")
 65             {                
 66                 開始ToolStripMenuItem.Text = "重新開始";
 67                 timer1.Enabled = true;
 68             }
 69             else if (開始ToolStripMenuItem.Text == "重新開始")
 70             {
 71                 開始ToolStripMenuItem.Text = "開始";
 72                 繼續ToolStripMenuItem.Text = "暫停";
 73                 timer1.Enabled = true;
 74                 map.Reset(CreateGraphics());
 75                 map.score = 0;
 76             }
 77 
 78         }
 79 
 80         private void 繼續ToolStripMenuItem_Click(object sender, EventArgs e)
 81         {
 82             if (繼續ToolStripMenuItem.Text == "繼續")
 83             {
 84                 繼續ToolStripMenuItem.Text = "暫停";
 85                 timer1.Enabled = true;
 86             }
 87             else if(繼續ToolStripMenuItem.Text == "暫停")
 88             {
 89                 繼續ToolStripMenuItem.Text = "繼續";
 90                 timer1.Enabled = false;
 91             }
 92         }
 93 
 94         private void 低級ToolStripMenuItem_Click(object sender, EventArgs e)
 95         {
 96             gradeNum = 200;
 97             lblGrade.Text = "菜鳥";
 98             timer1.Interval = gradeNum;
 99         }
100 
101         private void 中級ToolStripMenuItem_Click(object sender, EventArgs e)
102         {
103             gradeNum = 150;
104             lblGrade.Text = "平民";
105             timer1.Interval = gradeNum;
106         }
107 
108         private void 高級ToolStripMenuItem_Click(object sender, EventArgs e)
109         {
110             gradeNum = 100;
111             lblGrade.Text = "高手";
112             timer1.Interval = gradeNum;
113         }
114 
115         private void 大神ToolStripMenuItem_Click(object sender, EventArgs e)
116         {
117             gradeNum = 50;
118             lblGrade.Text = "大神";
119             timer1.Interval = gradeNum;
120         }
121 
122         private void 膚色1ToolStripMenuItem_Click(object sender, EventArgs e)
123         {
124             this.BackgroundImage = Image.FromFile("1.jpg");
125             pink = 1;
126         }
127 
128         private void 膚色2ToolStripMenuItem_Click(object sender, EventArgs e)
129         {
130             this.BackgroundImage = Image.FromFile("2.jpg");
131             pink = 2;
132         }
133     }

編程過程借鑒了網路大神的幫忙。

還有一個問題,希望看到的大神可以幫忙解決:原本希望把選擇級別菜單下的幾個級別都注冊成一個點擊事件,再通過switch判斷點擊的級別的text屬性,再作出相應操作,但是不知道在代碼中怎么得到被點擊的級別的對象,所以方法實現不了。

也就是說,我想實現的效果是把菜單中的幾個按鈕的點擊事件注冊成一個事件,但是在寫代碼的過程中,不知道怎么才能得到被點擊按鈕(Button clickedBtn=sender as Button 不對,但也不知道還有什么其他的方法)的對象,也就無法確定點擊的是哪個按鈕。

膚色的單元還沒有實現,有待優化。

游戲方法:點擊菜單欄中的選擇級別,選擇一個級別,按F2開始游戲,游戲過程中可以按F4暫停,繼續游戲,每吃到一個食物加10分,達到500分成功。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM