基于C#弹幕类射击游戏的实现——(十)整合
2017-09-19 本文已影响0人
UnSkyToo
先看实现的效果
剩下部分代码,首先是入口,MainForm
public partial class MainForm : Form
{
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//
// TODO: Add constructor code after the InitializeComponent() call.
//
this.ClientSize = new Size(Config.ScreenWidth, Config.ScreenHeight);
this.StartPosition = FormStartPosition.CenterScreen;
this.pictureBox1.Location = new Point(0, 0);
this.pictureBox1.ClientSize = new Size(Config.ScreenWidth, Config.ScreenHeight);
this.DoubleBuffered = true;
}
private Game.GameScene scene;
private void RenderOver(object sender)
{
this.pictureBox1.Image = scene.Surface;
this.Text = "FPS:" + scene.FPS.ToString();
}
void MainFormLoad(object sender, EventArgs e)
{
Resources.Load("Bullets.png");
Resources.Load("Background.bmp");
Resources.Load("Res.bmp");
Resources.Load("BulletsAll.png");
Resources.Load("Player.png");
Resources.Load("Bomb.png");
Resources.Load("Enemy.png");
Resources.Load("Boss1.png");
Resources.Load("PlayerPoint.png");
Resources.Load("Hp.png");
for ( int i = 0; i < Config.BulletTypeCount; i++ )
{
Resources.Load("Bullet" + i.ToString() + ".png");
}
Data.BulletSource = Resources.Get("Bullets");
Data.BackgroundSource = Resources.Get("Background");
Data.BulletAllSource = Resources.Get("BulletsAll");
Data.PlayerSource = Resources.Get("Player");
Data.PlayerPointSource =Resources.Get("PlayerPoint");
Data.BombSource = Resources.Get("Bomb");
Data.EnemySource = Resources.Get("Enemy");
Data.Boss1Source = Resources.Get("Boss1");
Data.HpSource = Resources.Get("Hp");
Data.BulletsSource = new Bitmap[Config.BulletTypeCount];
for ( int i = 0; i < Config.BulletTypeCount; i++ )
{
Data.BulletsSource[i] = Resources.Get("Bullet" + i.ToString());
}
Data.BulletAllSource.MakeTransparent(Color.FromArgb(255, 0, 255));
Data.PlayerSource.MakeTransparent(Color.FromArgb(255, 0, 255));
Data.BombSource.MakeTransparent(Color.FromArgb(255, 0, 255));
Data.EnemySource.MakeTransparent(Color.FromArgb(255, 0, 255));
Data.Boss1Source.MakeTransparent(Color.FromArgb(255, 0, 255));
scene = new STG.Game.GameScene();
scene.RenderOver += RenderOver;
}
void MainFormKeyDown(object sender, KeyEventArgs e)
{
Input.KeyDown(e.KeyCode);
}
void MainFormKeyUp(object sender, KeyEventArgs e)
{
Input.KeyUp(e.KeyCode);
}
}
这里面用到了Resource和Data。
Resource用来管理资源,其实最开始打算是这样的,后来。。。没写,就成下面这样了
public static class Resources
{
private static Hashtable mRes;
static Resources()
{
mRes = new Hashtable();
}
public static void Load(string path)
{
Bitmap res = new Bitmap(System.Windows.Forms.Application.StartupPath + @"\Resources\" + path);
if ( res == null )
{
Log.Error("Can't load : " + System.Windows.Forms.Application.StartupPath + @"\Resources\" + path);
return;
}
string name = string.Empty;
int start = path.LastIndexOf('\\');
int end = path.LastIndexOf('.');
if ( start == -1 )
{
start = 0;
}
name = path.Substring(start, end);
mRes.Add(name, res);
}
public static Bitmap Get(string name)
{
return mRes[name] as Bitmap;
}
}
完全是多此一举的感觉啊。。哈哈
然后是Data,保存一些大家共用的图片啊,数据啊
public static class Data
{
public static Bitmap BulletSource = null;
public static Bitmap BackgroundSource = null;
public static Bitmap BulletAllSource = null;
public static Bitmap PlayerSource = null;
public static Bitmap PlayerPointSource = null;
public static Bitmap HpSource = null;
public static Bitmap BombSource = null;
public static Bitmap EnemySource = null;
public static Bitmap Boss1Source = null;
public static Bitmap [] BulletsSource = null;
public static Font NormalFont = new Font("Arial", 12);
public static Random Rnd = new Random(DateTime.Now.Millisecond);
/// <summary>
/// 2 * PI
/// </summary>
public static float TwoPI = (float)Math.PI * 2.0f;
/// <summary>
/// 弧度单位
/// </summary>
public static float Radian = (float)Math.PI / 180.0f;
/// <summary>
/// 不同类型的敌人位图在图库中的位置
/// </summary>
public static Rectangle[] EnemySourceRectangle = new Rectangle[]
{
new Rectangle(0, 0, 34, 31), // (1, 1) Enemy 第1排 第1个
new Rectangle(35, 0, 31, 33), // (1, 2)
new Rectangle(0, 33, 33, 27), // (2, 1)
new Rectangle(67, 0, 36, 32), // (1, 3)
new Rectangle(104, 0, 30, 36), // (1, 4)
new Rectangle(133, 54, 38, 22), // (2, 4)
new Rectangle(39, 34, 42, 39), // (2, 2)
new Rectangle(82, 39, 48, 34), // (2, 3)
new Rectangle(135, 0, 64, 53) // (1, 5)
};
/// <summary>
/// 不同类型的敌人的碰撞盒子(X,Y相对于位图中心点的便宜,W,H大小)
/// </summary>
public static Rectangle[] EnemyBoxColliderRectangle = new Rectangle[]
{
new Rectangle(0, 0, 34, 31), // (1, 1) Enemy 第1排 第1个
new Rectangle(0, 0, 31, 33), // (1, 2)
new Rectangle(0, 0, 33, 27), // (2, 1)
new Rectangle(0, 0, 36, 32), // (1, 3)
new Rectangle(0, 0, 30, 36), // (1, 4)
new Rectangle(0, 0, 38, 22), // (2, 4)
new Rectangle(0, 0, 23, 39), // (2, 2)
new Rectangle(0, -5, 48, 24), // (2, 3)
new Rectangle(0, -10, 64, 37) // (1, 5)
};
/// <summary>
/// 不同子弹类型的大小
/// </summary>
public static Size[] BulletsSize = new Size[]
{
new Size(10, 10),
new Size(16, 14),
new Size(18, 18),
new Size(18, 18),
new Size(9, 17),
new Size(9, 17),
new Size(7, 44)
};
public enum MouseButton
{
Left,
Right,
Middle
}
/// <summary>
/// 方向
/// </summary>
public enum Direction
{
None,
Up,
Down,
Left,
Right,
LeftUp,
LeftDown,
RightUp,
RightDown
}
}
/// <summary>
/// Bottom : 0
/// Background : 10
/// Floor : 20
/// Map : 30
/// Object : 40
/// Effect : 50
/// Sky : 80
/// UI : 90
/// Top : 100
/// </summary>
public static class DepthLayer
{
public const int Bottom = 0;
public const int Background = 10; // 背景层
public const int Map = 20; // 地表层
public const int Bullet = 30; // 子弹层
public const int Object = 40; // 单位层
public const int Effect = 50; // 特效层
public const int UI = 90; // UI层
public const int Top = 100;
}
然后是播放声音,网上找的一个类
public class GameSound
{
protected const int SND_SYNC = 0x0;
protected const int SND_ASYNC = 0x1;
protected const int SND_NODEFAULT = 0x2;
protected const int SND_MEMORY = 0x4;
protected const int SND_LOOP = 0x8;
protected const int SND_NOSTOP = 0x10;
protected const int SND_NOWAIT = 0x2000;
protected const int SND_ALIAS = 0x10000;
protected const int SND_ALIAS_ID = 0x110000;
protected const int SND_FILENAME = 0x20000;
protected const int SND_RESOURCE = 0x40004;
protected const int SND_PURGE = 0x40;
protected const int SND_APPLICATION = 0x80;
[DllImport("Winmm.dll", CharSet=CharSet.Auto)]
protected extern static bool PlaySound(string strFile, IntPtr hMod, int flag );
//播放声音函数
//strSoundFile --- 声音文件
//bSynch --- 是否同步,如果为True,则播放声音完毕再执行后面的操作,为False,则播放声音的同时继续执行后面的操作
public static bool PlaySoundFile(string strSoundFile, bool bSynch)
{
if(!System.IO.File.Exists(strSoundFile))
return false;
int Flags;
if(bSynch)
Flags = SND_FILENAME | SND_SYNC;
else
Flags = SND_FILENAME | SND_ASYNC;
return PlaySound(strSoundFile, IntPtr.Zero, Flags);
}
剩下的一些Log啊,GPoint啊~~都是无关紧要的,自己实现或者不要都行
整个游戏就这么完成了。勉强算是半成品
对了,差点忘了,载入地图资源的函数没给出
private void LoadMapInfo(string path)
{
try
{
StreamReader fp = new StreamReader(path, Encoding.Default);
int timeIndex = 0;
while ( fp.EndOfStream == false )
{
string line = fp.ReadLine();
if ( line.StartsWith("[") && line.EndsWith("]") )
{
timeIndex = int.Parse(line.Substring(1, line.Length - 2));
continue;
}
if ( timeIndex >= Config.OneMapTime )
{
Log.Error("索引超出地图最大限制");
fp.Close();
return;
}
mMapInfo[timeIndex].Add(line);
}
fp.Close();
}
catch(Exception ce)
{
Log.Error(ce.Message);
}
}
private void DealMapInfo(int index)
{
if ( index < 0 || index >= Config.OneMapTime )
{
return;
}
if ( mMapInfo[index].Count == 0 )
{
return;
}
foreach ( string line in mMapInfo[index] )
{
string [] param = line.Split(',');
Vector2 pos = new Vector2(int.Parse(param[1]), int.Parse(param[2]));
if ( pos.X == -1 )
{
pos.X = Config.ScreenWidth / 2;
}
if ( pos.Y == -1 )
{
pos.Y = Config.ScreenHeight / 2;
}
switch ( param[0] )
{
case "Enemy1":
AddEnemy(new Enemy1(pos));
break;
case "Enemy2":
AddEnemy(new Enemy2(pos));
break;
case "Enemy3":
AddEnemy(new Enemy3(pos));
break;
case "Enemy4":
AddEnemy(new Enemy4(pos));
break;
case "Enemy5":
AddEnemy(new Enemy5(pos));
break;
case "Enemy6":
AddEnemy(new Enemy6(pos));
break;
case "Enemy7":
AddEnemy(new Enemy7(pos));
break;
case "Enemy8":
AddEnemy(new Enemy8(pos));
break;
case "Enemy9":
AddEnemy(new Enemy9(pos));
break;
case "Boss1":
AddBoss(new Boss1(mBarrage, pos));
break;
default:
break;
}
}
}
public bool InScreen(Box box)
{
if ( box.Left > Config.ScreenWidth )
{
return false;
}
if ( box.Right < 0 )
{
return false;
}
if ( box.Top > Config.ScreenHeight )
{
return false;
}
if ( box.Bottom < 0 )
{
return false;
}
return true;
}
这一部分用于从文件中载入配置,动态的生成敌人
好了,半成品完成了~~貌似我没讲什么啊。。。哎,不太会写博客啊,下面一个游戏学着多讲一些吧