基于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<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);  
            }  
        }  
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容