class Reward:Entity
{
public int StnTimes { get; set; }
public int Counter { get; set; }
public Reward(string name, int x, int y, int width, int height, int speedX, int speedY, int stnTimes, Bitmap bmp)
{
this.Name = name;
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
this.SpeedX = speedX;
this.SpeedY = speedY;
this.StnTimes = stnTimes;
this.Image = bmp;
this.Counter = 0;
}
}
5.爆炸效果类,即在子弹击破敌军飞机位置处绘制一个爆炸效果。参数偏差较多,没继承Entity。
class Explosion
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public int StnTimes { get; set; }
public int Counter { get; set; }
public System.Drawing.Bitmap[] Images { get; set; }
public Explosion(int x, int y, int stnTimes, System.Drawing.Bitmap[] bmp)
{
this.X = x;
this.Y = y;
this.StnTimes = stnTimes;
this.Images = bmp;
this.Counter = 0;
}
}
6.实体构建的工厂类,重量级类出现了:求赐教
//解释下细节:image_item是图片集合,分别是不同的物体图像,详见文件resource/plane.xml。需要一个标识ImgItem来表示不同图片的名字。工厂类在使用前需要初始化这些图片,所以写了个InitFactory(string xmlPath)方法,剩下的方法就是生产不同实体的静态方法了
,因为参数实在太多
,所以参数大多数在这里直接设置定值/或者随机数。
class EntityFactory
{
enum ImgItem { boom_add = 1, bomb_icon = 2, bullet_0 = 3, bullet_1 = 4, bullet_add = 5, enemy_b = 6, enemy_m = 7, enemy_s = 8, explosion_01 = 9, explosion_02 = 10, explosion_03 = 11, hero_1 = 12, hero_2 = 13, pause_button = 14, resume_button = 15, smoke_01 = 16, smoke_02 = 17 };
static Bitmap[] image_item = new Bitmap[18];
public static void InitFactory(string xmlPath)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlPath);
XmlNode parent = xmlDoc.SelectSingleNode("TextureAtlas");
Bitmap bmp = new Bitmap(Bitmap.FromFile(System.IO.Path.GetDirectoryName(xmlPath) + "/" + ((XmlElement)parent).GetAttribute("imagePath")));
XmlNodeList nodes = parent.ChildNodes;
int i = 1;
foreach (XmlNode xn in nodes)
{
XmlElement xe = (XmlElement)xn;
string name = xe.GetAttribute("name");
int x = int.Parse(xe.GetAttribute("x"));
int y = int.Parse(xe.GetAttribute("y"));
int width = int.Parse(xe.GetAttribute("width"));
int height = int.Parse(xe.GetAttribute("height"));
Bitmap subBmp = new Bitmap(width, height);
Graphics g = Graphics.FromImage(subBmp);
g.DrawImage(bmp, new Rectangle(0, 0, width, height), new Rectangle(x, y, width, height), GraphicsUnit.Pixel);
image_item[i] = subBmp;
i++;
}
}
public static Plane GenPlane(string style)
{
if ("normal".Equals(style))
{
Bitmap tempBmp = image_item[(int)ImgItem.hero_1];
return new Plane("small", 250,500, tempBmp.Width, tempBmp.Height,0, 0, tempBmp);
}
else if ("super".Equals(style))
{
Bitmap tempBmp = image_item[(int)ImgItem.hero_2];
return new Plane("mid", 350, 700, tempBmp.Width, tempBmp.Height, 0,0, tempBmp);
}
return null;
}
public static Enemy GenEnemy(string size,int speedBase)
{
if ("small".Equals(size))
{
Bitmap tempBmp = image_item[(int)ImgItem.enemy_s];
return new Enemy("small", new Random().Next(450)+50, 0, tempBmp.Width, tempBmp.Height,new Random().Next(10000)%5-2, new Random().Next(10000)%4+2+speedBase,1,tempBmp);
}
else if ("mid".Equals(size))
{
Bitmap tempBmp = image_item[(int)ImgItem.enemy_m];
return new Enemy("mid", new Random().Next(450) + 50, 0, tempBmp.Width, tempBmp.Height, new Random().Next(10000) % 5 - 2, new Random().Next(10000) % 4 + 1+speedBase, 5, tempBmp);
}
else if ("big".Equals(size))
{
Bitmap tempBmp = image_item[(int)ImgItem.enemy_b];
return new Enemy("big", new Random().Next(450) + 50, 0, tempBmp.Width, tempBmp.Height, new Random().Next(10000) % 3 - 1, new Random().Next(10000) % 3 + 1+speedBase, 20, tempBmp);
}
return null;
}
public static Bullet GenBullet(string style,int p_x,int p_y)
{
if ("red".Equals(style))
{
Bitmap tempBmp = image_item[(int)ImgItem.bullet_0];
return new Bullet("small", p_x, p_y, tempBmp.Width, tempBmp.Height,0, 20, tempBmp);
}
else if ("blue".Equals(style))
{
Bitmap tempBmp = image_item[(int)ImgItem.bullet_1];
return new Bullet("mid", p_x, p_y, tempBmp.Width, tempBmp.Height,0, 20, tempBmp);
}
return null;
}
public static Reward GenReward(string style, int p_x, int p_y)
{
if ("bullet_add".Equals(style))
{
Bitmap tempBmp = image_item[(int)ImgItem.bullet_add];
return new Reward("bullet_add", p_x, p_y, tempBmp.Width, tempBmp.Height, new Random().Next(10000) % 5 - 2, 3, 5000, tempBmp);
}
else if ("boom_add".Equals(style))
{
Bitmap tempBmp = image_item[(int)ImgItem.boom_add];
return new Reward("boom_add", p_x, p_y, tempBmp.Width, tempBmp.Height, new Random().Next(10000) % 5 - 2, 3, 5000, tempBmp);
}
return null;
}
public static Bitmap GetBoomIcon()
{
return image_item[(int)ImgItem.bomb_icon];
}
public static Explosion GenExplosion(string style, int p_x, int p_y)
{
if ("small".Equals(style))
{
Bitmap[] tempBmp = { image_item[(int)ImgItem.explosion_01],
image_item[(int)ImgItem.explosion_02], image_item[(int)ImgItem.explosion_03] ,
image_item[(int)ImgItem.explosion_02],image_item[(int)ImgItem.explosion_01]};
return new Explosion(p_x, p_y, 300, tempBmp);
}
else if ("mid".Equals(style))
{
Bitmap[] tempBmp = { image_item[(int)ImgItem.explosion_01] };
return new Explosion(p_x, p_y, 500, tempBmp);
}
else if ("big".Equals(style))
{
Bitmap[] tempBmp = { image_item[(int)ImgItem.explosion_01] };
return new Explosion(p_x, p_y, 500, tempBmp);
}
return null;
}
}
7.音效播放类,封装在DXPlay中,用到DirectX和DirectSound,在Windows下找到引用就行了。很好地解决了异步同时播放多个音频。
class DXPlay
{
private string musicPath;
Form1 form;
public DXPlay(Form1 form,string musicPath)
{
this.form = form;
this.musicPath = musicPath;
}
public void Play()
{
SecondaryBuffer secBuffer;//缓冲区对象
Device secDev;//设备对象
secDev = new Device();
secDev.SetCooperativeLevel(form, CooperativeLevel.Normal);//设置设备协作级别 ,当窗体失去焦点时,音频停止播放。
secBuffer = new SecondaryBuffer(musicPath, secDev);//创建辅助缓冲区
secBuffer.Play(0, BufferPlayFlags.Default);//设置缓冲区为默认播放
}
delegate void DelegatePlay();
public void ThreadPlay()
{
Thread t = new Thread(new ThreadStart(CorssThreadPlay));
t.Start();
}
public void CorssThreadPlay()//异步播放
{
if (form.InvokeRequired)
{
DelegatePlay dp = new DelegatePlay(CorssThreadPlay);
form.Invoke(dp);
}
else
{
SecondaryBuffer secBuffer;//缓冲区对象
Device secDev;//设备对象
secDev = new Device();
secDev.SetCooperativeLevel(form, CooperativeLevel.Normal);//设置设备协作级别 ,当窗体失去焦点时,音频停止播放。
secBuffer = new SecondaryBuffer(musicPath, secDev);//创建辅助缓冲区
secBuffer.Play(0, BufferPlayFlags.Default);//设置缓冲区为默认播放
}
}
}
8.主窗体Form,所有显示窗体效果,鼠标键盘事件监听+处理,实体物体生成,各种条件检测(碰撞检测),图形绘制(50 fps不知道为什么全屏会卡,而且光绘图就耗费了十几毫秒,网上有说用硬件加速,不解!),各种参数控制(时间控制,游戏中各种物体生成速度控制,界面大小,积分,难度,等级,等等)。参数值我就不一个一个解释了,因为都是些实际运行后反复改正的最后得到合适的值。以上就是该程序的所有代码,共计700+行代码。游戏挺占CPU的,可能是帧率问题。或者说是绘图问题,并且全屏情况下会卡顿,硬件加速正在研究。有好的意见请不吝提出。
public partial class Form1 : Form
{
Plane plane;
Timer t_draw;
List enemy_lsit = new List();
List bullet_lsit = new List();
List explosion_list = new List();
List reward_list = new List();
int score = 0;
int boom_count = 5;
bool pause = false;
Bitmap background;
public Form1()
{
//this.SetStyle(ControlStyles.UserPaint, true);//没搞懂这个双缓冲区绘图有什么作用,加不加没效果
//this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
//this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); // 双缓冲
this.StartPosition = FormStartPosition.CenterScreen;
this.Load += new System.EventHandler(this.Form1_Load);
this.MouseMove += new MouseEventHandler(Form1_MouseMove);
this.MouseClick += new MouseEventHandler(Form1_MouseClick);
this.KeyPress += new KeyPressEventHandler(Form1_KeyPress);
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
EntityFactory.InitFactory("resource/plane.xml");
background = new Bitmap(Image.FromFile(@"resource/bg_02.jpg"));
plane = EntityFactory.GenPlane("normal");
this.Cursor.Dispose();
Cursor.Position = new Point(plane.X + this.Location.X, plane.Y + this.Location.Y);
t_draw = new Timer();
t_draw.Interval = 20;
send_interval = 100 / t_draw.Interval;
block_interval = 260 / t_draw.Interval;
reward_interval = 5000 / t_draw.Interval;
t_draw.Tick += new EventHandler(t_draw_Tick);
t_draw.Start();
}
void Form1_MouseClick(object sender, MouseEventArgs e)
{
if (!pause && e.Button == MouseButtons.Right)
{
if (boom_count > 0)
{
boom_count--;
for (int i = 0; i < enemy_lsit.Count; i++)
{
//socre ++
if (enemy_lsit[i].Name == "small") score += 1000;
else if (enemy_lsit[i].Name == "mid") score += 6000;
else if (enemy_lsit[i].Name == "big") score += 25000;
//add to explosion
explosion_list.Add(EntityFactory.GenExplosion("small", enemy_lsit[i].X, enemy_lsit[i].Y));
}
new DXPlay(this, @"resource/BOMB3.wav").ThreadPlay();
enemy_lsit.Clear();
}
}
}
void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (!pause)
{
plane.X = e.X;
plane.Y = e.Y;
}
}
void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == ' ')
{
pause = !pause;
if (pause)
{
this.Cursor = new Cursor (Cursors.Arrow.CopyHandle());
}
else
{
this.Cursor.Dispose();
Cursor.Position = new Point(plane.X + this.Location.X, plane.Y + this.Location.Y);
}
}
/*else if (e.KeyChar == 27)
{
this.WindowState = FormWindowState.Normal;
}
else if (e.KeyChar == '\r')
{
this.WindowState = FormWindowState.Maximized;
}*/
}
int block_time = 1;
int block_interval = 0;
int send_time = 0;
int send_interval = 0;
int reward_time = 1;
int reward_interval = 0;
int rwd_bullet_stnTime = 0;
int backY = 800;
//DateTime dis = DateTime.Now;
private void t_draw_Tick(object sender, EventArgs e)
{
//Console.Write("\n ALLTime--->" + (DateTime.Now - dis));
if (pause)
{
this.CreateGraphics().DrawString("暂 停", new Font("微软雅黑", 22), Brushes.Red, new PointF(this.Width / 2 - 30, this.Height / 2 - 50));
return;
}
//////////////////////////////////////////////////////////////////
/////////////////// /////////////////////////////
////////////////// Create //////////////////////////////
///////////////// ///////////////////////////////
//////////////////////////////////////////////////////////////////
/*------send bullets-----*/
if (send_time > send_interval)
{
if (rwd_bullet_stnTime > 0)
{
bullet_lsit.Add(EntityFactory.GenBullet("blue", plane.X - 6, plane.Y - 50));
bullet_lsit.Add(EntityFactory.GenBullet("blue", plane.X + 6, plane.Y - 50));
rwd_bullet_stnTime -= t_draw.Interval * send_interval;
}
else
{
bullet_lsit.Add(EntityFactory.GenBullet("red", plane.X, plane.Y - 50));
}
new DXPlay(this, @"resource/shoot.wav").ThreadPlay();
send_time = 0;
}
/*------generate enemy-----*/
if (block_time % block_interval == 0)
{
int speedBase = 0;
if (block_interval < 2)
speedBase = 1;
if (block_interval < 5)
speedBase = 2;
else if (block_interval < 10)
speedBase = 1;
if (block_time % (block_interval * 20) == 0)
{
enemy_lsit.Add(EntityFactory.GenEnemy("big",speedBase));
}
else if (block_time % (block_interval * 10) == 0)
{
enemy_lsit.Add(EntityFactory.GenEnemy("mid", speedBase));
}
else
{
enemy_lsit.Add(EntityFactory.GenEnemy("small", speedBase));
}
}
/*-----reward-----*/
if (reward_time == reward_interval)
{
if (new Random().Next(10000) % 2 == 0)
{
reward_list.Add(EntityFactory.GenReward("bullet_add", new Random().Next(50, this.Width - 50), 0));
}
else
{
reward_list.Add(EntityFactory.GenReward("boom_add", new Random().Next(50, this.Width - 50), 0));
}
reward_time = 0;
}
send_time++;
block_time++;
reward_time++;
//////////////////////////////////////////////////////////////////
/////////////////// /////////////////////////////
////////////////// Judge //////////////////////////////
///////////////// ///////////////////////////////
//////////////////////////////////////////////////////////////////
/*-----plane level up-----*/
if (send_interval>0&&score > plane.Level * plane.Level * 50000)
{
plane.LevelUp();]
send_interval--;
}
/*-----enemy lv up-----*/
if (block_interval > 1 && block_time % 300 == 300-1)
{
block_interval--;
}
/*-----enemy crash-----*/
for (int i = 0; i < enemy_lsit.Count; i++)
{
for (int j = 0; j < bullet_lsit.Count; j++)
{
if (Math.Abs(bullet_lsit[j].X - enemy_lsit[i].X) < (bullet_lsit[j].Width + enemy_lsit[i].Width) / 2 && Math.Abs(bullet_lsit[j].Y - enemy_lsit[i].Y) < (bullet_lsit[j].Height + enemy_lsit[i].Height) / 2)
{
enemy_lsit[i].HP--;
if (enemy_lsit[i].HP == 0)//explose
{
//socre ++
if (enemy_lsit[i].Name == "small") score += 1000;
else if (enemy_lsit[i].Name == "mid") score += 6000;
else if (enemy_lsit[i].Name == "big") score += 25000;
//add to explosion
explosion_list.Add(EntityFactory.GenExplosion("small", enemy_lsit[i].X, enemy_lsit[i].Y));
new DXPlay(this, @"resource/explosion.wav").ThreadPlay();
//remove both
enemy_lsit.Remove(enemy_lsit[i]);
bullet_lsit.Remove(bullet_lsit[j]);
}
else
{
//g.FillRectangle(Brushes.Red,new Rectangle(bullet_lsit[j].X,bullet_lsit[j].Y-bullet_lsit[j].Width/2,30,5));
bullet_lsit.Remove(bullet_lsit[j]);
}
break;
}
}
}
/*-----get reward-----*/
for (int i = 0; i < reward_list.Count; i++)
{
if (Math.Abs(plane.X - reward_list[i].X) < (plane.Width + reward_list[i].Width) / 2 && Math.Abs(plane.Y - reward_list[i].Y) < (plane.Height + reward_list[i].Height) / 2)
{
if (reward_list[i].Name == "bullet_add")
{
rwd_bullet_stnTime += reward_list[i].StnTimes;
}
else if (reward_list[i].Name == "boom_add")
{
boom_count++;
}
reward_list.Remove(reward_list[i]);
}
}
/*-----plane crash-----*/
for (int i = 0; i < enemy_lsit.Count; i++)
{
bool isCrashed = false;
if (Math.Abs(plane.X - enemy_lsit[i].X) < (plane.Width / 4 + enemy_lsit[i].Width) / 2 && Math.Abs(plane.Y - enemy_lsit[i].Y) < (plane.Height - 30 + enemy_lsit[i].Height) / 2)
{
isCrashed = true;
}
if (isCrashed)
{
t_draw.Stop();
this.CreateGraphics().DrawString("Game Over", new Font("微软雅黑", 22), Brushes.Red, new PointF(this.Width / 2 - 100, this.Height / 2 - 50));
//enemy_lsit.Remove(enemy_lsit[i]);
return;
}
}
//////////////////////////////////////////////////////////////////
/////////////////// /////////////////////////////
////////////////// Draw //////////////////////////////
///////////////// ///////////////////////////////
//////////////////////////////////////////////////////////////////
Bitmap bmp = new Bitmap(this.Width, this.Height);
Graphics g = Graphics.FromImage(bmp);
/*-----clear panel-----*/
g.Clear(this.BackColor);
/*-----background-----*/
int img_count = 0;
if (background.Width < this.Width)
{
Bitmap tempBg = new Bitmap(this.Width, 1600);
while (background.Width * (img_count) < this.Width)
{
Graphics g_tempBg = Graphics.FromImage(tempBg);
g_tempBg.DrawImage(background, background.Width * img_count, 0);
g_tempBg.DrawImage(background, background.Width * img_count, 800);
img_count++;
}
background = tempBg;
}
g.DrawImage(background, new Rectangle(0, 0, this.Width, this.Height), new Rectangle(0, backY, this.Width, this.Height), GraphicsUnit.Pixel);
backY -= 2;
if (backY < 0)
backY = 800;
/*------plane------*/
g.DrawImage(plane.Image, new Point(plane.X - plane.Width / 2, plane.Y - plane.Height / 2));
/*-----bullets-----*/
for (int i = 0; i < bullet_lsit.Count; i++)
{
g.DrawImage(bullet_lsit[i].Image, new Point(bullet_lsit[i].X - bullet_lsit[i].Width / 2, bullet_lsit[i].Y - bullet_lsit[i].Height / 2));
bullet_lsit[i].Y -= bullet_lsit[i].SpeedY;
if (bullet_lsit[i].Y < -40)
{
bullet_lsit.Remove(bullet_lsit[i]);
}
}
/*-----draw reward-----*/
for (int i = 0; i < reward_list.Count; i++)
{
g.DrawImage(reward_list[i].Image, new Point(reward_list[i].X - reward_list[i].Width / 2, reward_list[i].Y - reward_list[i].Height / 2));
reward_list[i].Y += reward_list[i].SpeedY;
reward_list[i].X += reward_list[i].SpeedX;
if (reward_list[i].Y > this.Height + 20)
{
reward_list.Remove(reward_list[i]);
}
}
/*-----draw boom icon-----*/
Bitmap boom_icon = EntityFactory.GetBoomIcon();
if (boom_count > 0)
{
g.DrawImage(boom_icon, new Point(10, this.Height - 40 - boom_icon.Height));
g.DrawString("×" + boom_count, new Font("微软雅黑", 18), Brushes.RosyBrown, new Point(10 + boom_icon.Width, this.Height - 40 - boom_icon.Height));
}
/*-----enemy-----*/
for (int i = 0; i < enemy_lsit.Count; i++)
{
g.DrawImage(enemy_lsit[i].Image, new Point(enemy_lsit[i].X - enemy_lsit[i].Width / 2, enemy_lsit[i].Y - enemy_lsit[i].Height / 2));
enemy_lsit[i].Y += enemy_lsit[i].SpeedY;
enemy_lsit[i].X += enemy_lsit[i].SpeedX;
if (enemy_lsit[i].X > this.Width || enemy_lsit[i].X < 0)
{
enemy_lsit[i].SpeedX = -enemy_lsit[i].SpeedX;
}
if (enemy_lsit[i].Y > this.Width + 20)
{
enemy_lsit.Remove(enemy_lsit[i]);
}
}
/*-----draw explose-----*/
for (int i = 0; i < explosion_list.Count; i++)
{
Bitmap temp_explose = explosion_list[i].Images[explosion_list[i].Counter / (explosion_list[i].StnTimes / explosion_list[i].Images.Length)];
g.DrawImage(temp_explose, new Point(explosion_list[i].X - temp_explose.Width / 2, explosion_list[i].Y - temp_explose.Height / 2));
explosion_list[i].Counter += 24;
if (explosion_list[i].Counter > explosion_list[i].StnTimes)
explosion_list.Remove(explosion_list[i]);
}
/*-----score panel-----*/
g.DrawString("分数:" + score, new Font("微软雅黑", 14), Brushes.Green, new PointF(10, 10));
/*-----level panel-----*/
g.DrawString("等级:" + (send_interval == 1 ? "满级" : plane.Level.ToString()), new Font("微软雅黑", 14), Brushes.Green, new PointF(this.Width - 120, 10));
g.Dispose();
this.CreateGraphics().DrawImage(bmp, 0, 0);
bmp.Dispose();
//dis = DateTime.Now;
}
}
就到此结束吧!以下是 游戏+源码 下载链接。
游戏: http://download.csdn.net/detail/y85171642/6527087
源码: http://download.csdn.net/detail/y85171642/6527099