首页 > 代码库 > 基于C#开发的简易贪吃蛇

基于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分成功。

 

基于C#开发的简易贪吃蛇