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);
}
}
}
c#控件弹幕效果_基于C#弹幕类射击游戏的实现——(六)爆炸效果相关推荐
- global 仪表控件 无人机地面站_基于GL Studio的无人机地面站天线控件设计与实现...
基于 GL Studio 的无人机地面站天线控件设计与实现 李兴岷 ; 陈怀民 ; 喻戈 ; 任伟 [期刊名称] <测控技术> [年 ( 卷 ), 期] 2011(030)009 [摘要] ...
- c#控件弹幕效果_基于C#弹幕类射击游戏的实现——(十)整合
先看实现的效果 剩下部分代码,首先是入口,MainForm public partial class MainForm : Form { public MainForm() { // // The I ...
- c#控件弹幕效果_基于C#弹幕类射击游戏的实现——(二)渲染
这个游戏打算是用C#+GDI做~所以渲染效率上还是要进行一些考虑的 public interface IRenderHandler { void Clear(Color backgroundColor ...
- HTML5游戏_基于DOM平台跳跃小游戏开发_9.按键监听
HTML5游戏_基于DOM平台跳跃小游戏开发 按键监听 视频讲解 HTML5游戏 效果图 本章知识点: 对象自定义名称属性,可以用变量来命名属性名称 //这段代码把多个属性(品牌, 型号, 排量)赋给 ...
- 太空射击第13课: 爆炸效果
太空射击第13课: 爆炸效果 在本课中,我们将在玩家射击流星时进行一些动画爆炸. 视频 您可以在此处观看本课程的视频: 自动开火 首先,让我们对玩家的射击方式进行一些小的改变.现在,我们必须为每次射击 ...
- vs mfc数据与控件绑定错了_如何进行数据趋势分析?VS扩展工具——C1迷你图控件了解一下...
点击"了解更多"获取ComponentOne 2020 v1正式版下载 迷你图 -- Sparklines是迷你的轻量级图表,有助于快速可视化数据. 它们是由数据可视化传奇人物Ed ...
- dev里timeedit控件如何赋值_抽奖程序里的字节跳动模式和时长控制,让抽奖更有仪式感!...
用excel的随机函数配合index函数可以很方便的实现从一组数据中随机抽取单个数据,常用于抽奖小程序.但若想让抽奖时数据跳动一段时间再出现最终的结果,就好像真正的抽奖一样,只用函数就不好实现了.今天 ...
- 控件尺寸规范_微信小程序设计规范你了解多少
正好最近我也要开发小程序,所以今天我就从设计方面聊一聊微信小程序设计规范,埋上设计中可能会出现的坑,让你能更好的完成你的小程序- 一.宏观角度 微信小程序设计的基本原则是微信设计中心针对在微信类上线的 ...
- gtk 控件内存回收_咱们从头到尾说一次 Java 垃圾回收
作者:聂晓龙(花名:率鸽) 来源:微信公众号,阿里巴巴中间件 之前上学的时候有这个一个梗,说在食堂里吃饭,吃完把餐盘端走清理的,是 C++ 程序员,吃完直接就走的,是 Java 程序员. 确实,在 J ...
最新文章
- 码农技术炒股之路——数据库管理器、正则表达式管理器
- js / jquery 零散收集
- 笑抽了!这个程序员正在坐电梯,被HR逮到偷偷出去面试!
- Vue Iview Tree插件的无限层
- Qracle学习:排序
- 思科模拟器,计算机网络实验三之:静态路由配置
- SAP Fiori Elements - bindComponent - binding property in XML view will trigger odata request
- python删除列表中的偶数_Python:从列表中删除奇数
- Java中的事务——JDBC事务和JTA事务
- String.getBytes(Unicode)的疑问 以及 SHIFT-JIS编码范围
- php 获取 js json数据类型,JS基础-JS的数据类型和访问/流程控制/JSON格式字符串和js对象相互转换...
- 在计算机领域提到的假说,量子力学中假说的发展及相关影响
- linux越狱时手机怎么进入dfu,通过软件恢复进入DFU刷机模式教程
- python 运行另一个py_如何在python中执行另一个py文件
- python计算微分方程组_如何使用python计算常微分方程?
- 二维码获取WIFI配置
- 虚拟机Oracle VM VirtualBox 共享文件夹放的文件打不开,找不到指定路径问题
- 数码相机图像处理原理
- oracle归档日志百分比,oracle归档日志过满清理
- 【经验分享】BMPR文件及其打开软件Balsamiq Wireframes的下载和安装