利用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 = 0;
                }
                _x = value;
            }
        }
        float _y;
        /// <summary>
        /// Y轴坐标不能大于300或小于0
        /// </summary>
        public float Y
        {
            get { return _y; }
            set
            {
                if (value > 400)
                {
                    value = 400;
                }
                if (value < 0)
                {
                    value = 0;
                }
                _y = value;
            }
        }
        float _speed = 0;
        /// <summary>
        /// 坐标增减的速度
		/// 小鸟对象的初速度
        /// 正数为上升速度
        /// 负数为下降速度
        /// </summary>
        public float Speed
        {
            get { return _speed; }
            set { _speed = value; }
        }
        /// <summary>
        /// 改变X轴坐标
        /// </summary>
        public void ChangeX()
        {
            if (this.X == 0)//每次X轴为0时宽度减1
            {
                this.Width -= 1;
            }
            else
            {
                this.X -= 1;
            }
        }
        /// <summary>
        /// 改变Y轴坐标
		/// 控制小鸟对象的上升与下降速度
        /// </summary>
        public void ChangeY()
        {
            //改变Y轴的速度先减速降低后加速增加
            this.Y -= this.Speed;
            this.Speed -= 0.2f;
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="heigth"></param>
        public Diamonds(float x, float y, int heigth)
        {
            this.X = x;
            this.Y = y;
            this.Heigth = heigth;
     }

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

接下来开始写游戏过程:

一、绘制游戏图

利用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;
        }

利用GDI+制作Flappy Bird

时间: 2024-08-24 09:19:33

利用GDI+制作Flappy Bird的相关文章

【转】通过制作Flappy Bird了解Native 2D中的RigidBody2D和Collider

作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 引子 在第一篇文章[Unity3D基础教程]给初学者看的Unity教程(一):GameObject,Compoent,Time,Input,Physics我已经讲过了一些关于刚体和碰撞的关系,这次我们就通过Flappy Bird这个事例来讲解一下刚体和碰撞体在游戏中的具体应用.相关代码可以参考Flappy Bird的源码. 认识RigidBo

Unity3D基础教程】(四):通过制作Flappy Bird了解Native 2D...

[狗刨学习网] 引子 在第一篇文章[Unity3D基础教程]给初学者看的Unity教程(一):GameObject,Compoent,Time,Input,Physics我已经讲过了一些关于刚体和碰撞的关系,这次我们就通过Flappy Bird这个事例来讲解一下刚体和碰撞体在游戏中的具体应用.相关代码可以参考Flappy Bird的源码. 认识RigidBody 当RigidBody2D的质量属性被设置为0时,刚体的质量变为无限大,此时刚体相当于静态刚体,永远一动不动.但是在Unity中你是无法

【Unity3D基础教程】给初学者看的Unity教程(三):通过制作Flappy Bird了解Native 2D中的Sprite,Animation

作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 引子 上一次我们讲了MonoBehaviour的前世今生,了解了游戏中的每一个GameObjec都是由脚本控制的,这一次我们开始将Unity中Native 2D中的Sprite,并且使用Animation来让Sprite动起来. 在接下来的几篇博客里,我会通过做一个Flappy Bird来讲解Unity中各个组件的使用,项目的源代码在这里:U

通过制作Flappy Bird了解Native 2D中的RigidBody2D和Collider2D

欢迎来到unity学习.unity培训.unity企业培训教育专区,这里有很多U3D资源.U3D培训视频.U3D教程.U3D常见问题.U3D项目源码,[狗刨学习网]unity极致学院,致力于打造业内unity3d培训.学习第一品牌. 引子 这次我们就通过Flappy Bird这个事例来讲解一下刚体和碰撞体在游戏中的具体应用.相关代码可以参考Flappy Bird的源码. 认识RigidBody 当RigidBody2D的质量属性被设置为0时,刚体的质量变为无限大,此时刚体相当于静态刚体,永远一动

【Unity3D基础教程】给初学者看的Unity教程(四):通过制作Flappy Bird了解Native 2D中的RigidBody2D和Collider2D

作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 引子 在第一篇文章[Unity3D基础教程]给初学者看的Unity教程(一):GameObject,Compoent,Time,Input,Physics我已经讲过了一些关于刚体和碰撞的关系,这次我们就通过Flappy Bird这个事例来讲解一下刚体和碰撞体在游戏中的具体应用.相关代码可以参考Flappy Bird的源码. 认识RigidBo

【转】通过制作Flappy Bird了解Native 2D中的Sprite,Animation

作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 引子 上一次我们讲了MonoBehaviour的前世今生,了解了游戏中的每一个GameObjec都是由脚本控制的,这一次我们开始将Unity中Native 2D中的Sprite,并且使用Animation来让Sprite动起来. 在接下来的几篇博客里,我会通过做一个Flappy Bird来讲解Unity中各个组件的使用,项目的源代码在这里:U

【Unity3D基础教程】(三):通过制作Flappy Bird了解Native 2D

[狗刨学习网] 引子 上一次我们讲了MonoBehaviour的前世今生,了解了游戏中的每一个GameObjec都是由脚本控制的,这一次我们开始将Unity中Native 2D中的Sprite,并且使用Animation来让Sprite动起来. 在接下来的几篇博客里,我会通过做一个Flappy Bird来讲解Unity中各个组件的使用,项目的源代码在这里:Unity Flappy Bird.欢迎各位前去Fork和Star. 如何创建Sprite 创建一个Sprite可以遵循如下步骤 将一张图片拖

通过制作Flappy Bird了解Native 2D中的Sprite,Animation

欢迎来到unity学习.unity培训.unity企业培训教育专区,这里有很多U3D资源.U3D培训视频.U3D教程.U3D常见问题.U3D项目源码,[狗刨学习网]unity极致学院,致力于打造业内unity3d培训.学习第一品牌. 引子 这一次我们开始将Unity中Native 2D中的Sprite,并且使用Animation来让Sprite动起来. 在接下来的几篇博客里,我会通过做一个Flappy Bird来讲解Unity中各个组件的使用,项目的源代码在这里:Unity Flappy Bir

如何制作flappy bird resume版本

参考:https://www.cnblogs.com/wuhaozhou/p/5800788.html javascript 学习:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain 为了写简历:https://medium.com/free-code-camp/writing-a-killer-software-engineering-resume-b11c91e