接下来就像填充积木一样,把GameScene里用到的东西一个个写完~~
先来个最简单的。GameBomb
一目了然
public class GameBomb : GameObject
{
public bool IsLive;
private int FrameIndex;
private int FrameMax;
private float FrameDelay;
private int FrameWidth;
private int FrameHeight;
private int FrameHalfWidth;
private int FrameHalfHeight;
private float time;
public GameBomb(Vector2 position, bool isBig, float duration)
{
this.Position = position;
this.FrameIndex = 0;
this.FrameMax = Config.BombSmallFrameMax;
this.FrameWidth = Config.BombSmallFrameWidth;
this.FrameHeight = Config.BombSmallFrameHeight;
this.FrameHalfWidth = this.FrameWidth / 2;
this.FrameHalfHeight = this.FrameHeight / 2;
this.FrameDelay = duration / (float)this.FrameMax;
this.IsLive = true;
}
public override void Update(float elapsedTime)
{
if ( IsLive == false )
{
return;
}
time += elapsedTime;
if ( time >= FrameDelay )
{
time -= FrameDelay;
FrameIndex++;
if ( FrameIndex >= FrameMax )
{
IsLive = false;
}
}
}
public override void Render(Graphics g)
{
if ( IsLive == false )
{
return;
}
g.DrawImage(Data.BombSource,
new Rectangle((int)Position.X - FrameHalfWidth, (int)Position.Y - FrameHalfHeight, FrameWidth, FrameHeight),
new Rectangle(FrameWidth * FrameIndex, 0, FrameWidth, FrameHeight),
GraphicsUnit.Pixel);
}
}
如果不熟悉的,估计是对2D类的精灵动画不太了解。。可以百度了解下。
或者简单讲解,就是按照时间,不断的绘制一样图片中不同位置的精灵~看起来就像动态的了。
接下来是它的管理类GameBombManager
public static class GameBombManager
{
private static List<GameBomb> mBombs = new List<GameBomb>();
public static void AddBomb(Vector2 position, bool isBig, float duration)
{
mBombs.Add(new GameBomb(position, isBig, duration));
}
public static void Update(float elapsedTime)
{
for ( int i = 0; i < mBombs.Count; i++ )
{
mBombs[i].Update(elapsedTime);
if ( mBombs[i].IsLive == false )
{
mBombs.RemoveAt(i);
i--;
continue;
}
}
}
public static void Render(Graphics g)
{
foreach ( GameBomb bomb in mBombs )
{
bomb.Render(g);
}
}
}
这个看起来就比我们之前见过的简单多了。
好,这章就这么结束了!!貌似有点少啊。。。
好吧,那接下来讲一个与本游戏无关的,粒子系统(其实粒子系统在游戏中很重要,只是这个游戏很简单,没有用到而已)
public struct GameParticle
{
/// <summary>
/// 粒子位置
/// </summary>
public Vector2 Position;
/// <summary>
/// 粒子速度
/// </summary>
public Vector2 Velocity;
/// <summary>
/// 重力加速度
/// </summary>
public float Gravity;
/// <summary>
/// 直线加速度(运动方向上的加速度)
/// </summary>
public float RadialAccel;
/// <summary>
/// 切线上的加速度(角速度)
/// </summary>
public float TangentialAccel;
/// <summary>
/// 粒子旋转角度
/// </summary>
public float Spin;
/// <summary>
/// 粒子旋转速度增量
/// </summary>
public float SpinDelta;
/// <summary>
/// 粒子大小
/// </summary>
public float Size;
/// <summary>
/// 粒子大小增量
/// </summary>
public float SizeDelta;
/// <summary>
/// 粒子生存时间
/// </summary>
public float Age;
/// <summary>
/// 粒子死亡时间
/// </summary>
public float TerminalAge;
}
/// <summary>
/// 粒子配置信息
/// </summary>
public struct GameParticleSystemInfo
{
/// <summary>
/// 粒子贴图
/// </summary>
public Bitmap Texture;
/// <summary>
/// 每秒发射的粒子数量
/// </summary>
public int Emission;
/// <summary>
/// 生命周期
/// </summary>
public float LifeTime;
/// <summary>
/// 粒子生命周期范围
/// </summary>
public Range ParticleLife;
/// <summary>
/// 方向
/// </summary>
public float Direction;
/// <summary>
/// 偏移角度
/// </summary>
public float Spread;
/// <summary>
/// 是否为绝对值(计算生成粒子的初始速度)
/// </summary>
public bool IsRelative;
/// <summary>
/// 速度范围
/// </summary>
public Range Speed;
/// <summary>
/// 重力加速度范围
/// </summary>
public Range Gravity;
/// <summary>
/// 直线加速度范围
/// </summary>
public Range RadialAccel;
/// <summary>
/// 切线角加速度范围
/// </summary>
public Range TangentialAccel;
/// <summary>
/// 起始大小
/// </summary>
public float SizeStart;
/// <summary>
/// 最终大小
/// </summary>
public float SizeEnd;
/// <summary>
/// 大小变化量
/// </summary>
public float SizeVar;
/// <summary>
/// 起始旋转角度
/// </summary>
public float SpinStart;
/// <summary>
/// 最终旋转角度
/// </summary>
public float SpinEnd;
/// <summary>
/// 角度变化值
/// </summary>
public float SpinVar;
}
/// <summary>
/// 粒子系统
/// </summary>
public class GameParticleSystem
{
/// <summary>
/// 粒子最大数量
/// </summary>
public const int MaxParticles = 512;
/// <summary>
/// 粒子系统未启动
/// </summary>
public const float Particle_System_Not_Start = -2.0f;
/// <summary>
/// 粒子发射器的配置信息
/// </summary>
public GameParticleSystemInfo Info;
private GameParticle[] mParticles; // 粒子集合
/// <summary>
/// 剩余时间
/// </summary>
private float Age;
/// <summary>
/// 剩余未发射粒子
/// </summary>
private float EmissionResidue;
private Vector2 PrevPosition; // 上一个位置
private Vector2 Position; // 当前位置
private Vector2 Offset; // 偏移量
private float Scale; // 整体缩放系数
/// <summary>
/// 活动粒子个数
/// </summary>
private int ParticlesAlive;
public GameParticleSystem(GameParticleSystemInfo info)
{
this.mParticles = new GameParticle[MaxParticles];
this.Info = info;
this.Position = new Vector2(0, 0);
this.PrevPosition = new Vector2(0, 0);
this.Offset = new Vector2(0, 0);
this.Scale = 1.0f;
this.EmissionResidue = 0;
this.ParticlesAlive = 0;
this.Age = Particle_System_Not_Start;
}
/// <summary>
/// 移动粒子发射器到制动位置
/// </summary>
/// <param name="x">横坐标</param>
/// <param name="y">纵坐标</param>
/// <param name="moveParticles">是否移动活动粒子</param>
public void MoveTo(float x, float y, bool moveParticles)
{
float dx = 0;
float dy = 0;
if ( moveParticles )
{
dx = x - Position.X;
dy = y - Position.Y;
for ( int i = 0; i < ParticlesAlive; i++ )
{
mParticles[i].Position.X += dx;
mParticles[i].Position.Y += dy;
}
PrevPosition.X = PrevPosition.X + dx;
PrevPosition.Y = PrevPosition.Y + dy;
}
else
{
if ( Age == Particle_System_Not_Start )
{
PrevPosition.X = x;
PrevPosition.Y = y;
}
else
{
PrevPosition.X = Position.X;
PrevPosition.Y = Position.Y;
}
}
Position.X = x;
Position.Y = y;
}
/// <summary>
/// 启动粒子系统
/// </summary>
public void Start()
{
if ( Info.LifeTime == -1.0f )
{
Age = -1.0f;
}
else
{
Age = 0;
}
}
/// <summary>
/// 在指定位置启动粒子系统
/// </summary>
/// <param name="x">横坐标</param>
/// <param name="y">纵坐标</param>
public void Start(float x, float y)
{
Stop(false);
MoveTo(x, y, false);
Start();
}
/// <summary>
/// 停止粒子系统
/// </summary>
/// <param name="killParticles">是否摧毁活动粒子</param>
public void Stop(bool killParticles)
{
Age = Particle_System_Not_Start;
if ( killParticles )
{
ParticlesAlive = 0;
}
}
public float GetAge()
{
return Age;
}
public void Update(float elapsedTime)
{
float ang = 0;
Vector2 accel1;
Vector2 accel2;
if ( Age >= 0 )
{
Age += elapsedTime;
if ( Age >= Info.LifeTime )
{
Age = Particle_System_Not_Start;
}
}
for ( int i = 0; i < ParticlesAlive; i++ )
{
mParticles[i].Age += elapsedTime;
if ( mParticles[i].Age >= mParticles[i].TerminalAge )
{
ParticlesAlive--;
mParticles[i] = mParticles[ParticlesAlive];
i--;
continue;
}
// 计算粒子直线加速度
accel1 = mParticles[i].Position - Position;
accel1.Normalize();
accel2 = accel1;
accel1 = accel1 * mParticles[i].RadialAccel;
// 计算粒子切线加速度
ang = accel2.X;
accel2.X = -accel2.Y;
accel2.Y = ang;
accel2 = accel2 * mParticles[i].TangentialAccel;
// 计算粒子速度
mParticles[i].Velocity += (accel1 + accel2) * elapsedTime;
mParticles[i].Velocity.Y += mParticles[i].Gravity * elapsedTime;
mParticles[i].Position += mParticles[i].Velocity * elapsedTime;
mParticles[i].Spin += mParticles[i].SpinDelta;
mParticles[i].Size += mParticles[i].SizeDelta;
}
if ( Age != Particle_System_Not_Start )
{
// 计算需要生成的粒子数量
float ParticlesNeeded = Info.Emission * elapsedTime + EmissionResidue;
int ParticlesCreated = (int)((uint)ParticlesNeeded);
EmissionResidue = ParticlesNeeded - ParticlesCreated;
int n = ParticlesAlive;
for ( int i = n; i < n + ParticlesCreated; i++ )
{
if ( ParticlesAlive >= MaxParticles )
{
break;
}
mParticles[i].Age = 0;
mParticles[i].TerminalAge = Info.ParticleLife.Get();
mParticles[i].Position = PrevPosition + (Position - PrevPosition) * Helper.GetRandomFloat(0, 1);
mParticles[i].Position.X += Helper.GetRandomFloat(-2.0f, 2.0f);
mParticles[i].Position.Y += Helper.GetRandomFloat(-2.0f, 2.0f);
ang = Info.Direction - Data.TwoPI + Helper.GetRandomFloat(0, Info.Spread) - Info.Spread / 2.0f;
if ( Info.IsRelative )
{
ang += (PrevPosition - Position).Angle() + Data.TwoPI;
}
mParticles[i].Velocity.X = (float)Math.Cos(ang);
mParticles[i].Velocity.Y = (float)Math.Sin(ang);
mParticles[i].Velocity *= Info.Speed.Get();
mParticles[i].Gravity = Info.Gravity.Get();
mParticles[i].RadialAccel = Info.RadialAccel.Get();
mParticles[i].TangentialAccel = Info.TangentialAccel.Get();
mParticles[i].Size = Helper.GetRandomFloat(Info.SizeStart, Info.SizeStart + (Info.SizeEnd - Info.SizeStart) * Info.SizeVar);
mParticles[i].SizeDelta = (Info.SizeEnd - mParticles[i].Size) / mParticles[i].TerminalAge;
mParticles[i].Spin = Helper.GetRandomFloat(Info.SpinStart, Info.SpinStart + (Info.SpinEnd - Info.SpinStart) * Info.SpinVar);
mParticles[i].SpinDelta = (Info.SpinEnd - mParticles[i].Spin) / mParticles[i].TerminalAge;
ParticlesAlive++;
}
}
PrevPosition = Position;
}
public void Render(Graphics g)
{
for ( int i = 0; i < ParticlesAlive; i++ )
{
g.DrawImage(Data.BulletSource,
new Rectangle((int)(mParticles[i].Position.X * Scale + Offset.X),
(int)(mParticles[i].Position.Y * Scale + Offset.Y),
(int)(16.0f * Scale),
(int)(16.0f * Scale)),
new Rectangle(0, 0, 16, 16),
GraphicsUnit.Pixel);
}
}
}
/// <summary>
/// 粒子管理器
/// </summary>
public class GameParticleManager
{
/// <summary>
/// 粒子系统最大个数
/// </summary>
public const int MaxParticleSystem = 10;
private GameParticleSystem[] mPSList;
private int mPSCount;
private Vector2 mOffset;
public Vector2 Offset
{
get
{
return mOffset;
}
set
{
mOffset = value;
for ( int i = 0; i < mPSCount; i++ )
{
mPSList[i].MoveTo(mOffset.X, mOffset.Y, false);
}
}
}
public GameParticleManager()
{
mPSList = new GameParticleSystem[MaxParticleSystem];
mOffset = new Vector2(0, 0);
mPSCount = 0;
}
public void Spwan(float x, float y, GameParticleSystemInfo info)
{
if ( mPSCount >= MaxParticleSystem )
{
return;
}
mPSList[mPSCount] = new GameParticleSystem(info);
mPSList[mPSCount].Start(x, y);
mPSCount++;
}
public bool IsAlive(GameParticleSystem psi)
{
for ( int i = 0; i < mPSCount; i++ )
{
if ( mPSList[i] == psi )
{
return true;
}
}
return false;
}
public void Kill(GameParticleSystem psi)
{
for ( int i = 0; i < mPSCount; i++ )
{
if ( mPSList[i] == psi )
{
mPSList[i] = mPSList[mPSCount - 1];
mPSCount--;
return;
}
}
}
public void KillAll()
{
mPSCount = 0;
}
public void Update(float elapsedTime)
{
for ( int i = 0; i < mPSCount; i++ )
{
mPSList[i].Update(elapsedTime);
if ( mPSList[i].GetAge() == GameParticleSystem.Particle_System_Not_Start )
{
mPSList[i] = mPSList[mPSCount - 1];
mPSCount--;
i--;
}
}
}
public void Render(Graphics g)
{
for ( int i = 0; i < mPSCount; i++ )
{
mPSList[i].Render(g);
}
}
}