基于C#彈幕類射擊游戲的實(shí)現(xiàn)——(六)爆炸效果

接下來就像填充積木一樣,把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類的精靈動畫不太了解。。可以百度了解下。
或者簡單講解,就是按照時間,不斷的繪制一樣圖片中不同位置的精靈~看起來就像動態(tài)的了。
接下來是它的管理類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);  
            }  
        }  
    } 

這個看起來就比我們之前見過的簡單多了。
好,這章就這么結(jié)束了!!貌似有點(diǎn)少啊。。。
好吧,那接下來講一個與本游戲無關(guān)的,粒子系統(tǒng)(其實(shí)粒子系統(tǒng)在游戲中很重要,只是這個游戲很簡單,沒有用到而已)

public struct GameParticle  
    {  
        /// <summary>  
        /// 粒子位置  
        /// </summary>  
        public Vector2 Position;  
        /// <summary>  
        /// 粒子速度  
        /// </summary>  
        public Vector2 Velocity;  
        /// <summary>  
        /// 重力加速度  
        /// </summary>  
        public float Gravity;  
        /// <summary>  
        /// 直線加速度(運(yùn)動方向上的加速度)  
        /// </summary>  
        public float RadialAccel;  
        /// <summary>  
        /// 切線上的加速度(角速度)  
        /// </summary>  
        public float TangentialAccel;  
        /// <summary>  
        /// 粒子旋轉(zhuǎn)角度  
        /// </summary>  
        public float Spin;  
        /// <summary>  
        /// 粒子旋轉(zhuǎn)速度增量  
        /// </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>  
        /// 每秒發(fā)射的粒子數(shù)量  
        /// </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>  
        /// 起始旋轉(zhuǎn)角度  
        /// </summary>  
        public float SpinStart;  
        /// <summary>  
        /// 最終旋轉(zhuǎn)角度  
        /// </summary>  
        public float SpinEnd;  
        /// <summary>  
        /// 角度變化值  
        /// </summary>  
        public float SpinVar;  
    }  
      
    /// <summary>  
    /// 粒子系統(tǒng)  
    /// </summary>  
    public class GameParticleSystem  
    {  
        /// <summary>  
        /// 粒子最大數(shù)量  
        /// </summary>  
        public const int MaxParticles = 512;  
          
        /// <summary>  
        /// 粒子系統(tǒng)未啟動  
        /// </summary>  
        public const float Particle_System_Not_Start = -2.0f;  
          
        /// <summary>  
        /// 粒子發(fā)射器的配置信息  
        /// </summary>  
        public GameParticleSystemInfo Info;  
          
        private GameParticle[] mParticles; // 粒子集合  
          
        /// <summary>  
        /// 剩余時間  
        /// </summary>  
        private float Age;  
          
        /// <summary>  
        /// 剩余未發(fā)射粒子  
        /// </summary>  
        private float EmissionResidue;  
        private Vector2 PrevPosition; // 上一個位置  
        private Vector2 Position; // 當(dāng)前位置  
        private Vector2 Offset; // 偏移量  
        private float Scale; // 整體縮放系數(shù)  
          
        /// <summary>  
        /// 活動粒子個數(shù)  
        /// </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>  
        /// 移動粒子發(fā)射器到制動位置  
        /// </summary>  
        /// <param name="x">橫坐標(biāo)</param>  
        /// <param name="y">縱坐標(biāo)</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>  
        /// 啟動粒子系統(tǒng)  
        /// </summary>  
        public void Start()  
        {  
            if ( Info.LifeTime == -1.0f )  
            {  
                Age = -1.0f;  
            }  
            else  
            {  
                Age = 0;  
            }  
        }  
          
        /// <summary>  
        /// 在指定位置啟動粒子系統(tǒng)  
        /// </summary>  
        /// <param name="x">橫坐標(biāo)</param>  
        /// <param name="y">縱坐標(biāo)</param>  
        public void Start(float x, float y)  
        {  
            Stop(false);  
            MoveTo(x, y, false);  
            Start();  
        }  
          
        /// <summary>  
        /// 停止粒子系統(tǒng)  
        /// </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 )  
            {  
                // 計算需要生成的粒子數(shù)量  
                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>  
        /// 粒子系統(tǒng)最大個數(shù)  
        /// </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);  
            }  
        }  
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內(nèi)容