c#版flappybird 未完全實現

來源:互聯網
上載者:User

標籤:style   blog   http   io   ar   使用   sp   for   on   

這些天開始在深圳找工作,想著把從前有些淡忘的技術再溫故下。看到尊敬的《傳智播客》有一期公開課,講的是用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

c#版flappybird 未完全實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.