学习了杨中科版的C#射击游戏视频,大家可参考http://player.youku.com/player.php/sid/XMTUyNjQ3NjQ0/v.swf
准备素材,一张飞机图片,一个WAV的飞机遇到子弹爆炸音效。
1.创建一个WinForm应用程序
Form窗体,拖一个panel控件,相当于战场。拖一个Timer控件,操纵飞机与子弹运行。
panel控件中用到会三个事件,一个是Paint事件,用来触发调用画飞机和子弹。第一个是MouseClick事件,主要用来任意点击panel区域时,发射子弹。还有一个是Timer的Tick事件,用来控制飞机与子弹的移动。
2.创建抽象类GameObject,用于子弹类,飞机类继承。子弹和飞机,共同拥有的属性,在panel上的X,Y的坐标,以及Draw()画子弹/飞机和Move()移动的方法。
3.创建子弹Bullut与飞机Plane的类继承于抽象类GameObject;同时添加子弹自己的特有的属性和方法,例如,Bullet类自己的属性有bool isFired,判断是否发射子弹(子弹是当鼠标点击时才需要发射),Bullet类自己的方法有判断子弹是否击中飞机bool IsHit();
Panel类自己有属性有HitTime子弹击中的次数,本游戏中子弹需击中两次方可爆炸,并发出爆炸音。
bool IsVisble属性用于当子弹第一次击中飞机时,飞机开始闪烁,(闪烁实现的效果就是一会让飞机画在panel上,一会又把它隐藏掉),Panel类中自己的方法有Resart,当飞机飞到边界时或击碎时,飞机需从左边重新出现。
4.新建一个GamePanel类,让它继承于Panel控件,解决游戏中在运行中飞机不停闪烁的问题(不是击中第一次后飞机闪烁)。应用了双缓冲。
具体代码如下:
Form1.cs
using System;
using System.Windows.Forms;
using System.Drawing;
using Game.Properties;
using System.Media;
namespace Game
{
public partial class Form1 : Form
{
Plane plane;
Bullet bullet;
public Form1()
{
InitializeComponent();
NewBullet();
NewPlane();
}
//实例化一个子弹
private void NewBullet()
{
bullet = new Bullet();
bullet.isFired = false;
bullet.rect = panelFiled.ClientRectangle;
bullet.Y = panelFiled.ClientRectangle.Height;
}
//实例化一个飞机
private void NewPlane()
{
plane = new Plane();
plane.Restart();
plane.rect= panelFiled.ClientRectangle;
Random rad = new Random();
plane.Y = rad.Next(0, 100)//飞机随机在左侧Y轴方向出现
}
private void panelFiled_Paint(object sender, PaintEventArgs e)
{
plane.Draw(e.Graphics);
bullet.Draw(e.Graphics);
}
private void timer1_Tick(object sender, EventArgs e)
{
bullet.Move();
plane.Move();
if (bullet.Ishit(plane) == true)//判断当子弹击中飞机时的情况
{
NewBullet();
plane.HitTime++;
if (plane.HitTime == 2)//当两次击中时,发出爆炸声音
{
NewPlane();
SoundPlayer player = new SoundPlayer(Resources.BOMB);
player.Play();
}
}
panelFiled.Invalidate();
}
private void panelFiled_MouseClick(object sender, MouseEventArgs e)
{
bullet.isFired = true; //当鼠标开始点击中,发射子弹
bullet.X = e.X;
bullet.Y = panelFiled.ClientRectangle.Height;
panelFiled.Invalidate();
}
}
}
//抽象类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace Game
{
abstract class GameObject
{
public int X { get; set; }
public int Y { get; set; }
public Rectangle rect { get; set; }
public abstract void Draw(Graphics e);
public abstract void Move();
}
}
//子弹类
using System.Drawing;
using System;
namespace Game
{
class Bullet:GameObject
{
public const int R = 5;//子弹的半径
public bool isFired { get; set; }
//画子弹
public override void Draw(Graphics e)
{
if (isFired == false) //用来判断是否开始点击,没有点击不可自动发射子弹
{
return;
}
e.FillEllipse(new SolidBrush(Color.Black), X, Y, R * 2, R * 2);
}
public override void Move()
{
if (isFired == false)
{
return;
}
Y=Y-3;//向上移动
}
//判断子弹是否击中飞机,求出两物体之间的距离,如果小于小物体的半径之各则判断其相撞
public bool Ishit(Plane plane)
{
int detalX = plane.X - X;
int detalY = plane.Y - Y;
double dist = Math.Sqrt(detalX * detalX + detalY * detalY);
if (dist > Bullet.R + Plane.R)
{
return false;
}
else
return true;
}
}
}
//飞机类
namespace Game
{
class Plane:GameObject
{
public const int R = 25;
public int HitTime { get; set; }
private bool isVisble;
public int speed { get; set; }
Random rad = new Random();
public override void Draw(Graphics e)
{
if (HitTime == 1) //判断击中一次时,飞机开始闪烁,让其时而可见,时而消失
{
isVisble = !isVisble;
if(!isVisble)
{
return;
}
}
e.DrawImage(Resources.plane, X, Y, R*2, R*2);
}
//飞机爆炸或都撞到右侧panel时,重新出现
public void Restart()
{
speed = rad.Next(1, 3);
Y = rad.Next(0, rect.Height);//重现出现的位置Y轴随机
X = 0;
HitTime = 0;//重现出现时击中次数为0
}
public override void Move()
{
//移动的速度
X = X + speed;//向右移动
if (X > rect.Width)
{
Restart();
}
}
}
}
//解决双缓冲的类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Game
{
class GamePanel:Panel
{
public GamePanel()
{
SetStyle(ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw |
ControlStyles.SupportsTransparentBackColor, true);
}
}
}