上次介绍用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;
}