学习了杨中科版的C#射击游戏视频,大家可参考
准备素材,一张飞机图片,一个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); } }}