利用GDI+製作Flappy Bird
阿新 • • 發佈:2019-02-02
上次介紹用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;
}