c#版flappybird 未完全实现

这些天开始在深圳找工作,想着把从前有些淡忘的技术再温故下。看到尊敬的《传智播客》有一期公开课,讲的是用c#编写flappybird小游戏,也就自己搜了下游戏资源,也来试试看。

其实用到的技术就是传智播客讲的。只不过项目结构和一些逻辑稍微修改了下,更加符合原游戏的特点。

————————再次声明:非本人独创方案————————————

导入资源

窗体背景设置为background图片382*681,然后在窗体上加个picturebox,放入road图片,大小拉伸.

而后加三个timer,依次设置100ms,10ms,10ms

如此,游戏界面搭建完成。

下面是代码结构,所有游戏元素的父类,抽象类:public abstract class GameObj

小鸟类:public class Bird : GameObj

管道类:public class Pipe : GameObj

重力类:public static class Gravity

GameObj类:添加两个抽象方法void Move()  和 void Draw(Graphics g)

下面是整个类的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace flappybird
{
    /// <summary>
    /// 游戏对象的父类
    /// </summary>
    public abstract class GameObj
    {
        public int X { get; set; }
        public int Y { get; set; }
        public int Height { get; set; }
        public int Width { get; set; }

        public GameObj(int x,int y,int height,int width)
        {
            this.X = x;
            this.Y = y;
            this.Height = height;
            this.Width = width;
        }
        public abstract void Move();
        public abstract void Draw(Graphics g);
    }
}
 

下面是Bird类源码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using flappybird.Properties;

namespace flappybird
{
    public class Bird : GameObj
    {
        /// <summary>
        /// 各种小鸟形态数组
        /// </summary>
        private static Image[] imgs ={
                         Properties.Resources.bird_blue_0,
                         Properties.Resources.bird_blue_1,
                         Properties.Resources.bird_blue_2
                     };
        /// <summary>
        /// 当前绘制的小鸟形态的索引
        /// </summary>
        public int BirdIndex { get; set; }
        /// <summary>
        /// 存储当前下落速度
        /// </summary>
        public float Speed { get; set; }
        /// <summary>
        /// 存储已下落持续时间
        /// </summary>
        public float Time { get; set; }

        private static Bird bird = null;
        /// <summary>
        /// 单例模式,确保只实例化一个Bird对象
        /// </summary>
        /// <returns></returns>
        public static Bird GetSingleBird()
        {
            if (bird == null)
            {
                bird = new Bird(100, 200, 0);
            }
            return bird;
        }
        /// <summary>
        /// 调用父类的构造函数
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="birdIndex"></param>
        private Bird(int x, int y, int birdIndex)
            : base(x, y, imgs[0].Height, imgs[0].Width)
        {
            this.BirdIndex = birdIndex;
            this.Time = 10f;
            this.Speed = 0f;
        }

        /// <summary>
        /// 重写父类的抽象Draw方法
        /// </summary>
        public override void Draw(Graphics g)
        {
            switch (this.BirdIndex)
            {
                case 0:
                    g.DrawImage(imgs[0], this.X, this.Y);
                    break;
                case 1:
                    g.DrawImage(imgs[1], this.X, this.Y);
                    break;
                case 2:
                    g.DrawImage(imgs[2], this.X, this.Y);
                    break;
                default:
                    break;
            }
            this.BirdIndex++;
            this.BirdIndex %= 3;
        }
        /// <summary>
        /// 重写父类的抽象Move方法
        /// </summary>
        public override void Move()
        {
            this.Y = this.Y <= 60 ? 0 : this.Y - 60;
            //this.Y -= 30;
        }
        /// <summary>
        /// 获取图形区域,用于碰撞检测
        /// </summary>
        /// <returns></returns>
        public static Rectangle GetRectangle()
        {
            return new Rectangle(bird.X, bird.Y, Resources.bird_blue_0.Width, Resources.bird_blue_0.Height);
        }
    }
}

结合注释,相信大家都能搞懂。。。

Pipe类:

此类中,我定义了一个pipes数组,用来向画面中呈现3列水管(每列包含上下两个水管)

然后用InitPipes()函数初始化。此函数中,用了一种比较讨巧的方法,就是先判断数组中最后一个元素是否为null,类似Bird类中使用的单例模式。

具体代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using flappybird.Properties;
namespace flappybird
{
    public class Pipe : GameObj
    {
        public override void Move()
        {
            for (int i = 0; i < 3; i++)
            {
                pipes[i, 0].X -= 1;
                pipes[i, 1].X -= 1;
            }
            // this.X -= 1;
        }
        public override void Draw(System.Drawing.Graphics g)
        {
            for (int i = 0; i < 3; i++)
            {
                //画出上水管
                g.DrawImage(Resources.bound_up, pipes[i, 0].X, pipes[i, 0].Y);
                //画出下水管
                g.DrawImage(Resources.bound_down, pipes[i, 1].X, pipes[i, 1].Y);
            }

        }
        private Pipe(int x, int y)
            : base(x, y, Resources.bound_down.Height, Resources.bound_down.Width)
        {

        }

        private static Pipe[,] pipes = new Pipe[3, 2];
        private static void InitPipes()
        {
            if (pipes[2, 1] == null)
            {
                Random rand = new Random(DateTime.Now.Millisecond);
                for (int i = 0; i < 3; i++)
                {
                    int y = rand.Next(80, 380);
                    //上水管
                    pipes[i, 0] = new Pipe(300 + i * 200, -y);
                    //下水管
                    pipes[i, 1] = new Pipe(300 + i * 200, -y + Resources.bound_up.Height + 170);
                }
            }
        }
        public static Pipe GetPipes(int row, int col)
        {
            if (row > 1 || col > 2)
            {
                return null;
            }
            InitPipes();
            return pipes[col, row];
        }
        public static Rectangle GetRectangle(int row,int col)
        {
            return new Rectangle(pipes[col, row].X, pipes[col, row].Y,
                Resources.bound_up.Width, Resources.bound_up.Height);
        }
    }
}

然后Gravity类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace flappybird
{
    public static class Gravity
    {
        private const float g=9.8f;
        private const float a = 40f;
        /// <summary>
        /// 获取下落的距离
        /// </summary>
        /// <param name="time"></param>
        /// <param name="speed"></param>
        /// <returns></returns>
        public static int GetDropHeight(float time,float speed)
        {

            if (speed<0)
            {
                return (int)(0.5f * a * time * time + speed * time);

            }
            return (int)(0.5f * g * time * time + speed * time);

        }
        /// <summary>
        /// 获取下落后的速度
        /// </summary>
        /// <param name="time"></param>
        /// <param name="speed"></param>
        /// <returns></returns>
        public static float GetDropSpeed(float time,float speed)
        {
            if (speed<0)
            {
                return speed + a * time;
            }
            return speed + g * time;
        }
    }
}

定义一个 float a;这个表示小鸟向上飞的时候受到的向下的加速度。之所以这样设计,是为了小鸟向上飞的时候,不是一下就跳到某个高度,让它连续上升,但是减速特快的那种效果。

我看传智播客里赵老师是直接设置个上升高度,给人的感觉是小鸟一下就”飞“上去了,这样设计会简单些,缺点是没有连续效果。

大餐来了,Form1代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using flappybird.Properties;
namespace flappybird
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private bool IsGameOver = false;
        private void Form1_Load(object sender, EventArgs e)
        {
            timer1.Enabled = true;
            timer2.Enabled = true;
            timer3.Enabled = true;

        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            if (IsGameOver)
            {
                return;
            }
            Bird.GetSingleBird().Draw(e.Graphics);
            Pipe.GetPipes(0, 0).Draw(e.Graphics);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (IsGameOver)
            {
                return;
            }
            this.Invalidate();
        }

        private void Form1_MouseClick(object sender, MouseEventArgs e)
        {
            if (IsGameOver)
            {
                return;
            }
            //Bird.GetSingleBird().Move();
            Bird.GetSingleBird().Speed = -80f;
        }

        private void Form1_KeyPress(object sender, KeyPressEventArgs e)
        {

        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (IsGameOver)
            {
                return;
            }
            if (e.KeyCode == Keys.Space)
            {
                //Bird.GetSingleBird().Move();
                Bird.GetSingleBird().Speed = -80f;
            }
        }
        /// <summary>
        /// 计算重力影响
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer2_Tick(object sender, EventArgs e)
        {
            if (IsGameOver)
            {
                return;
            }
            int dropHeight = Gravity.GetDropHeight(Bird.GetSingleBird().Time * 0.01f, Bird.GetSingleBird().Speed);

            int currentY = Bird.GetSingleBird().Y + dropHeight;
            int maxY = ClientRectangle.Height - pictureBox1.Height - Bird.GetSingleBird().Height;
            if (currentY >= maxY)
            {
                Bird.GetSingleBird().Y = maxY;
            }
            else if (currentY < 0)
            {
                Bird.GetSingleBird().Y = 0;
            }
            else
            {
                Bird.GetSingleBird().Y = currentY;
            }
            Bird.GetSingleBird().Speed = Gravity.GetDropSpeed(Bird.GetSingleBird().Time * 0.01f, Bird.GetSingleBird().Speed);
        }

        Random rand = new Random(DateTime.Now.Millisecond);

        private void timer3_Tick(object sender, EventArgs e)
        {
            if (IsGameOver)
            {
                return;
            }
            Pipe.GetPipes(0, 0).Move();
            //最靠近左边的管道列,为了下面的碰撞检测做准备。
            //因为只有最左边的管道才需要碰撞检测。避免不必要的操作。
            int left = 0;
            for (int i = 0; i < 3; i++)
            {
                //若某一列管道左移出了屏幕范围,则把其放到屏幕右端外
                //然后再进行左移
                if (Pipe.GetPipes(0, i).X < -90)
                {
                    //若i列移出了屏幕,则现在是(i + 1) % 3列在最左侧
                    left = (i + 1) % 3;
                    Console.WriteLine(left);
                    int y = rand.Next(80, 380);
                    //上面的管道
                    Pipe.GetPipes(0, i).X = 500;
                    Pipe.GetPipes(0, i).Y = -y;
                    //下面的管道
                    Pipe.GetPipes(1, i).X = 500;
                    Pipe.GetPipes(1, i).Y = -y + Resources.bound_up.Height + 170;
                }
            }
            bool isInterUp = Bird.GetRectangle().IntersectsWith(Pipe.GetRectangle(0, left));
            bool isInterDown = Bird.GetRectangle().IntersectsWith(Pipe.GetRectangle(1, left));
            bool isInterGround = Bird.GetRectangle().IntersectsWith(new Rectangle(pictureBox1.Location, pictureBox1.Size));
            if (isInterUp||isInterDown||isInterGround)
            {
                timer1.Enabled = false;
                timer2.Enabled = false;
                timer3.Enabled = false;
                IsGameOver = true;
            }

        }
    }
}

结合前面的几个类,这里就留给大家自己体会吧。(绝不是我懒得写说明。哈哈哈)

传送门:http://download.csdn.net/detail/geeking/8255401

时间: 2024-08-05 13:09:19

c#版flappybird 未完全实现的相关文章

Cocos2d-x 2.3.3版 FlappyBird

Cocos2d-x 2.3.3版 FlappyBird 本篇博客基于Cocos2d-x 2.3.3, 介绍如何开发一款之前很火的一款游戏FlappyBird.本篇博客内容大纲如下: 1. 如何创建Cocos2d-x 2.3.3 项目 2. 初始化Box2d物理世界,并模拟物理世界 3. 如何添加小鸟到物理世界 4. 如何添加地板 5. 添加水管 6. 碰撞检测 7. 本文总结 效果图: 1. 如何创建Cocos2d-x 2.3.3 本篇博客是基于Cocos2d-x 2.3.3,初学者可以选择这个

Filesystem-Hierarchy-Standard(FHS) 文件系统层次结构标准2.3中英对照版(未完待续)

本想把原文翻译一遍,一来学习学习Linux的文件系统结构,二来熟悉下专业英语.经历了一个月之久,才翻译到一半.再也没有空闲时间待在学校了,不知道什么时间才能翻译完.先在这里发表一下,给有需要的同志们方便学习,也给自己一个提醒,告诉自己这里还有一件未完成的事..感謝大家支持 --------------------------------------以下是FHS-2.3正文内容----------------------------------------------- Filesystem Hi

那些年我们踩到过的坑(二):3.1 版 MultiThreadedHttpConnectionManager 未releaseConnection导致应用服务器宕机

昨天短信服务又宕机了,jstack打出线程信息发现 所有线程池的线程都在wait,栈信息如下: at java.lang.Object.wait(Native Method) - waiting on [0x000000070754fb60] (a org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$ConnectionPool) at org.apache.commons.httpclient.MultiThread

再谈git的http服务-权限控制gitweb版(未成功)

截至目前,对gitweb的掌握还没达到最终目标,仅仅实现了通过浏览器来浏览项目,通过git命令仍然未能clone项目.但仍然要记录下来,主要是因为打算暂时放弃这条路,而所收获的一些经验还是要记录下来.说不定哪天又捡起来了呢. 首先描述下目标:可以按照项目.人员来分别控制项目的读写权限.方法应该很多,之前通过git-http-backend的hook可以搞定,gitlab也应该可以搞定.根据已有的资料,gitweb也应该可以搞定.思路之一应该是scriptalias,把git命令的申请路由到git

大数四则运算之加法运算--------C语言版(未考虑负数)

/* 声明两个字符数组,用于存储大数,声明两个整数型数组便于计算,将字符数组中的元素转换为对应整数存于整数数组中,将低位放在整数数组低位,便于对齐计算 判断是否有进位,计算结果高位先输出,从数组后往前找,找到第一个不为0的数,可以设置一个标志位.*/ #include<stdio.h>#include<string.h> int main(){ int num1[1000],num2[1000],i,j,max; char ch1[1000],ch2[1000]; int flag

面向对象 初级版 (Preview) 未完

概述: 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数里,日后使用无需重复编写,直接调用韩顺即可. 面向对象: 对函数进行分类和封装,让开发'更快更强' 面向对象和面向过程的通俗易懂的例子 ''' 如何大象装进冰箱? 面向过程: 为了把大象装进冰箱,需要3个过程. 1) 把冰箱门打开(得到打开门的冰箱) 2) 把大象装进去(打开门后,得到里面装着大象的冰箱) 3) 把冰箱门关上(打开门.装好大象后,获得关好门的冰箱) 每个过程有一个阶段性的目标,依次完成这些过程,就能把大

.NET(C#)实现桌面背景切换(控制台应用程序,windows服务版的未实现成功)

AdvancedBackgroundJimmy.Program.cs using AdvancedBackground; using Microsoft.Win32; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.ServiceProcess; using System.Th

XP,32/64位Win7,32/64位Win8,32/64位Win10系统 【春节版】

本系统是10月5日最新完整版本的Windows10 安装版镜像,win10正式版,更新了重要补丁,提升应用加载速度,微软和百度今天宣布达成合作,百度成为win10 Edge浏览器中国默认主页和搜索引擎,系统增加了搜狗输入法,安装过程需要用户手动创建个人账户等步骤,为保证系统的稳定性,win10为未激活版本,如需激活可通过微软官方购买,另外用户可以通过激活工具在线激活. 更新情况:+更新-万能驱动助理至V6.5+更新-虚拟内存智能转移至D盘+更新-winRAR V5.21+更新-我的文档转移至D盘

【分享】初音岛(D.C.)系列(包括D.C.III RX初音岛3) 汉化硬盘版游戏

游戏内容: [040528][CIRCUS]D.C.P.C-ダ?カーポ-プラスコミュニケーション [汉化硬盘版].rar(2.7GB)[060415][CIRCUS]D.C.II 春风のアルティメットバトル! [汉化硬盘版].rar(321.9MB)[060526][CIRCUS]D.C.II-ダ?カーポII- [汉化硬盘版].rar(1.9GB)[061107][CIRCUS]D.C.II -featuring Yun2- [汉化硬盘版].rar(335MB)[070427][CIRCUS]D