首页 > 代码库 > 利用GDI+制作Flappy Bird

利用GDI+制作Flappy Bird

上次介绍用GDI+写了个验证码图片生成器,这次再来介绍下用GDI+写之前流行过一段时间的小游戏:Flappy Bird。通过写这个游戏再来熟悉下GDI+的一些简单利用。

         这是一个粗糙的游戏画面,大家不要介意啊,毕竟这是美工做的事:


先来分析一下这个游戏要怎么写。游戏过程是:1、小鸟不停的往下掉,而且越掉越快;2、障碍物柱子不停地出现并往左移动;3、游戏一开始下面的前进条就不停地转动。

游戏规则:1、小鸟的身体不能触碰障碍物;2、小鸟的身体不能触及底部及上部;3、每当小鸟穿过一个障碍物时统计通过障碍物的数量加1。

知道了游戏过程和游戏规则,我们来编写游戏:


由于游戏中出现的障碍物高度不一,宽度统一。我们可以写一个障碍物类用于生成障碍物对象与小鸟对象。

class Diamonds
    {
        int _width = 40;
        /// <summary>
        /// 图形的宽,默认40
        /// </summary>
        public int Width
        {
            get { return _width; }
            set { _width = value; }
        }
        int _heigth;
        /// <summary>
        /// 图形高
        /// </summary>
        public int Heigth
        {
            get { return _heigth; }
            set { _heigth = value; }
        }
        float _x;
        /// <summary>
        /// X轴坐标
        /// </summary>
        public float X
        {
            get { return _x; }
            set//X轴坐标不能小于零
            {
                if (value < 0)
                {
                    value = http://www.mamicode.com/0;>

生成障碍物及小鸟的类已经写完了,并且有了左右移动和上下移动的方法。

接下来开始写游戏过程:

一、绘制游戏图

利用GDI+绘制游戏图,利用时间控件不停的重绘游戏图,以产生动态的效果。

首先申明全局变量及对象:

//设置障碍物之间的空隙高度
        static int width = 100;
        //判断绘制哪个前进条
        bool b = true;
        //统计当前通过障碍物的数量
        int count = 0;
        int _maxCount = 0;
        /// <summary>
        /// 记录最大通过数量
        /// </summary>
        public int MaxCount
        {
            get { return _maxCount; }
            set { _maxCount = value; }
        }
        //创建画布,大小为300*400
        static Bitmap bmp = new Bitmap(300, 400);
        static Bitmap bmp1 = new Bitmap(300, 20);
        //创建一只笔,画小鸟
        static Pen penOne = new Pen(Brushes.Red, 5);
		//创建一支笔,画前进条
        static Pen penTwo = new Pen(Color.Black, 2);
        //创建鸟
        static Diamonds bird = new Diamonds(100, 190, 15);
        //创建随机数产生器
        static Random r = new Random();
        //从画布bmp中创建GDI+对象
        static Graphics gp = Graphics.FromImage(bmp);
        static Graphics gp1 = Graphics.FromImage(bmp1);
        //创建两个障碍物的对象
        static int up1Height = r.Next(80, 241);
        Diamonds up1 = new Diamonds(300, 0, up1Height);
        Diamonds down1 = new Diamonds(300, width + up1Height, 400 - width - up1Height);
        static int up2Height = r.Next(80, 241);
        Diamonds up2 = new Diamonds(450, 0, up1Height);
        Diamonds down2 = new Diamonds(450, width + up1Height, 400 - width - up1Height);

绘制游戏图:
//小鸟飞
            bird.ChangeY();
            //障碍物移动
            up1.ChangeX();
            down1.ChangeX();
            up2.ChangeX();
            down2.ChangeX();
            //判断游戏是否结束
            IsEnd();
            //统计通过个数
            PassCount();
            //清除画面
            gp.Clear(Color.Blue);
            //如果一个障碍物消失,则新出现一个障碍物
            if (up1.Width == 0)
            {
                up1Height = r.Next(80, 241);
                up1 = new Diamonds(300, 0, up1Height);
                down1 = new Diamonds(300, width + up1Height, 400 - width - up1Height);
            }
            //如果一个障碍物消失,则新出现一个障碍物
            if (up2.Width == 0)
            {
                up2Height = r.Next(80, 241);
                up2 = new Diamonds(300, 0, up2Height);
                down2 = new Diamonds(300, width + up2Height, 400 - width - up2Height);
            }

            //画出各个对象
            //鸟
            gp.DrawRectangle(penOne, bird.X, bird.Y, bird.Width - 10, bird.Heigth);
            //障碍
            gp.FillRectangle(Brushes.Green, up1.X, up1.Y, up1.Width, up1.Heigth);
            gp.FillRectangle(Brushes.Green, down1.X, down1.Y, down1.Width, down1.Heigth);
            gp.FillRectangle(Brushes.Green, up2.X, up2.Y, up2.Width, up2.Heigth);
            gp.FillRectangle(Brushes.Green, down2.X, down2.Y, down2.Width, down2.Heigth);
            //将图片给图片框
            pbxImage.Image = bmp;
}
/// <summary>
        /// 画面前进条运转
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer2_Tick(object sender, EventArgs e)
        {
            gp1.Clear(Color.Blue);
            //画前进条
            gp1.DrawLine(penTwo, 0, 0, 300, 0);
            gp1.DrawLine(penTwo, 0, 20, 300, 20);
            if (b)
            {
                for (int i = 0; i < 300; i += 20)
                {
                    gp1.FillRectangle(Brushes.Green, i, 0, 10, 20);
                }
                b = false;
            }
            else
            {
                for (int i = 10; i < 300; i += 20)
                {
                    gp1.FillRectangle(Brushes.Green, i, 0, 10, 20);
                }
                b = true;
            }

            pbxLines.Image = bmp1;

        }
/// <summary>
        /// 游戏结束条件
        /// </summary>
        private void IsEnd()
        {
            //由于小鸟身体线条粗细问题,宽相应要增加5个像素左右,高增加2个像素
            if (((bird.X + 33 >= up1.X) && (bird.X <= up1.X + 40)) && ((bird.Y <= up1.Heigth + 5) || (bird.Y >= up1.Heigth + width - 20)))//当小鸟头部进入障碍物1则结束
            {
                GameOver();
            }
            else if (((bird.X + 33 >= up2.X) && (bird.X <= up2.X + 40)) && ((bird.Y <= up2.Heigth + 5) || (bird.Y >= up2.Heigth + width - 20)))//当小鸟头部进入障碍物2则结束
            {
                GameOver();
            }
            else if (bird.Y >= 375 || bird.Y <= 0)//当小鸟碰头或触地
            {
                GameOver();
            }

        }

        /// <summary>
        /// 游戏结束判断
        /// </summary>
        private void GameOver()
        {
            //显示控件
            timer1.Enabled = false;
            lblEnd.Visible = true;
            btnStart.Visible = true;
            lblMaxCount.Visible = true;
            label1.Visible = true;
            //得到最高分
            if (this.MaxCount < count)
            {
                this.MaxCount = count;
            }

            lblMaxCount.Text = this.MaxCount.ToString();
            return;
        }

        /// <summary>
        /// 计算通过的数量
        /// </summary>
        private void PassCount()
        {
            //当障碍物的末点X轴过了小鸟则通过一个
            if (up1.X == 65 || up2.X == 65)
            {
                count++;
            }
            lblCount.Text = count.ToString();
        }

        /// <summary>
        /// 开始游戏
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            //开始,结束控件不可见
            btnStart.Visible = false;
            lblEnd.Visible = false;
            lblMaxCount.Visible = false;
            label1.Visible = false;
            btnStart.Text = "重新开始";
            //当前数量归零
            count = 0;
            //重新初始化图片
            bird = new Diamonds(100, 190, 15);
            up1Height = r.Next(80, 241);
            up1 = new Diamonds(300, 0, up1Height);
            down1 = new Diamonds(300, width + up1Height, 400 - width - up1Height);
            up2Height = r.Next(80, 241);
            up2 = new Diamonds(450, 0, up1Height);
            down2 = new Diamonds(450, width + up1Height, 400 - width - up1Height);
            //激活
            timer1.Enabled = true;
        }

        /// <summary>
        /// 点击小鸟飞
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbxImage_Click(object sender, EventArgs e)
        {
            //经过调试,这个速度可玩性较高
            bird.Speed = 4.5f;
        }
/// <summary>
        /// 双击加速上升
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbxImage_DoubleClick(object sender, EventArgs e)
        {
            bird.Speed = 7;
        }