c#控件弹幕效果_基于C#弹幕类射击游戏的实现——(六)爆炸效果

接下来就像填充积木一样,把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 mBombs = new List();

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

{

///

/// 粒子位置

///

public Vector2 Position;

///

/// 粒子速度

///

public Vector2 Velocity;

///

/// 重力加速度

///

public float Gravity;

///

/// 直线加速度(运动方向上的加速度)

///

public float RadialAccel;

///

/// 切线上的加速度(角速度)

///

public float TangentialAccel;

///

/// 粒子旋转角度

///

public float Spin;

///

/// 粒子旋转速度增量

///

public float SpinDelta;

///

/// 粒子大小

///

public float Size;

///

/// 粒子大小增量

///

public float SizeDelta;

///

/// 粒子生存时间

///

public float Age;

///

/// 粒子死亡时间

///

public float TerminalAge;

}

///

/// 粒子配置信息

///

public struct GameParticleSystemInfo

{

///

/// 粒子贴图

///

public Bitmap Texture;

///

/// 每秒发射的粒子数量

///

public int Emission;

///

/// 生命周期

///

public float LifeTime;

///

/// 粒子生命周期范围

///

public Range ParticleLife;

///

/// 方向

///

public float Direction;

///

/// 偏移角度

///

public float Spread;

///

/// 是否为绝对值(计算生成粒子的初始速度)

///

public bool IsRelative;

///

/// 速度范围

///

public Range Speed;

///

/// 重力加速度范围

///

public Range Gravity;

///

/// 直线加速度范围

///

public Range RadialAccel;

///

/// 切线角加速度范围

///

public Range TangentialAccel;

///

/// 起始大小

///

public float SizeStart;

///

/// 最终大小

///

public float SizeEnd;

///

/// 大小变化量

///

public float SizeVar;

///

/// 起始旋转角度

///

public float SpinStart;

///

/// 最终旋转角度

///

public float SpinEnd;

///

/// 角度变化值

///

public float SpinVar;

}

///

/// 粒子系统

///

public class GameParticleSystem

{

///

/// 粒子最大数量

///

public const int MaxParticles = 512;

///

/// 粒子系统未启动

///

public const float Particle_System_Not_Start = -2.0f;

///

/// 粒子发射器的配置信息

///

public GameParticleSystemInfo Info;

private GameParticle[] mParticles; // 粒子集合

///

/// 剩余时间

///

private float Age;

///

/// 剩余未发射粒子

///

private float EmissionResidue;

private Vector2 PrevPosition; // 上一个位置

private Vector2 Position; // 当前位置

private Vector2 Offset; // 偏移量

private float Scale; // 整体缩放系数

///

/// 活动粒子个数

///

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;

}

///

/// 移动粒子发射器到制动位置

///

/// 横坐标

/// 纵坐标

/// 是否移动活动粒子

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;

}

///

/// 启动粒子系统

///

public void Start()

{

if ( Info.LifeTime == -1.0f )

{

Age = -1.0f;

}

else

{

Age = 0;

}

}

///

/// 在指定位置启动粒子系统

///

/// 横坐标

/// 纵坐标

public void Start(float x, float y)

{

Stop(false);

MoveTo(x, y, false);

Start();

}

///

/// 停止粒子系统

///

/// 是否摧毁活动粒子

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);

}

}

}

///

/// 粒子管理器

///

public class GameParticleManager

{

///

/// 粒子系统最大个数

///

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);

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值