基于C#彈幕類射擊游戲的實(shí)現(xiàn)——(七)彈幕類實(shí)現(xiàn)

如果只有這些子彈强品,那看起來(lái)必然是很一般的,想想看屈糊,只有幾顆子彈的榛,孤零零的從下面跑到上面。逻锐。夫晌。。昧诱。
GameBarrage彈幕類晓淀,用于創(chuàng)建一些酷炫叼的彈幕其實(shí)核心也就是通過(guò)一些數(shù)學(xué)公式,然后批量AddBullet而已
先來(lái)看看類型的定義

    public enum BarrageType  
        {  
            Line,  
            RotateAndShoot,  
            CrossLine,  
            Circle  
        }  

初步就這四種盏档,其余的彈幕類型都可以通過(guò)這幾種組合出來(lái)
然后就是彈幕的具體實(shí)現(xiàn)

public class GameBarrage  
    {  
        private GameScene mScene;  
  
        public GameBarrage(GameScene scene)  
        {  
            this.mScene = scene;  
        }  
  
        /// <summary>  
        /// 圓形彈幕  
        /// </summary>  
        /// <param name="isOwn">是否為玩家子彈</param>  
        /// <param name="type">子彈類型</param>  
        /// <param name="color">子彈顏色</param>  
        /// <param name="position">中心點(diǎn)位置</param>  
        /// <param name="speed">子彈移動(dòng)速度</param>  
        /// <param name="accel">子彈移動(dòng)加速度</param>  
        /// <param name="interval">每顆子彈的角度間隔</param>  
        /// <param name="delay">延遲發(fā)射時(shí)間</param>  
        public void CreateCircle(bool isOwn, int type, int color, Vector2 position, float speed, float accel, int interval, float delay)  
        {  
            int angle = 0;  
  
            while (angle < 360)  
            {  
                mScene.AddBullet(new GameBullet(isOwn, position, Helper.GetSpeedWithAngle(angle, speed), Helper.GetSpeedWithAngle(angle, accel), type, color, delay));  
                angle += interval;  
            }  
        }  
  
        /// <summary>  
        /// 扇形彈幕  
        /// </summary>  
        /// <param name="isOwn">是否為玩家子彈</param>  
        /// <param name="type">子彈類型</param>  
        /// <param name="color">子彈顏色</param>  
        /// <param name="position">中心點(diǎn)的位置</param>  
        /// <param name="startAngle">扇形的起始角度(向右為0°)</param>  
        /// <param name="endAngle">扇形的結(jié)束角度(順時(shí)針)</param>  
        /// <param name="speed">子彈移動(dòng)速度</param>  
        /// <param name="accel">子彈移動(dòng)加速度</param>  
        /// <param name="interval">每顆子彈的角度間隔</param>  
        /// <param name="duration">發(fā)射持續(xù)時(shí)間(為0表示瞬間發(fā)射所有)</param>  
        /// <param name="delay">延遲發(fā)射時(shí)間</param>  
        public void CreateRotateAndShoot(bool isOwn, int type, int color, Vector2 position, int startAngle, int endAngle, float speed, float accel, int interval, float duration, float delay)  
        {  
            int count = startAngle;  
            int angle = Math.Abs(endAngle - startAngle);  
            float wait = duration / (float)angle;  
              
            if ( endAngle > startAngle )  
            {  
                while (count < endAngle)  
                {  
                    mScene.AddBullet(new GameBullet(isOwn, position, Helper.GetSpeedWithAngle(count, speed), Helper.GetSpeedWithAngle(count, accel), type, color, (count - startAngle) * wait + delay ));  
                    count += interval;  
                }  
            }  
            else  
            {  
                while (count > endAngle)  
                {  
                    mScene.AddBullet(new GameBullet(isOwn, position, Helper.GetSpeedWithAngle(count, speed), Helper.GetSpeedWithAngle(count, accel), type, color, (startAngle - count) * wait + delay ));  
                    count += interval;  
                }  
            }  
        }  
  
        /// <summary>  
        /// 直線交叉彈幕  
        /// </summary>  
        /// <param name="isOwn">是否為玩家子彈</param>  
        /// <param name="type">子彈類型</param>  
        /// <param name="color">子彈顏色</param>  
        /// <param name="spawnCount">子彈數(shù)量</param>  
        /// <param name="beginPos1">開始地點(diǎn)一</param>  
        /// <param name="beginPos2">開始地點(diǎn)二</param>  
        /// <param name="crossPos">交叉點(diǎn)</param>  
        /// <param name="speed">子彈移動(dòng)速度</param>  
        /// <param name="accel">子彈移動(dòng)加速度</param>  
        /// <param name="duration">發(fā)射持續(xù)時(shí)間(為0表示瞬間發(fā)射所有)</param>  
        /// <param name="delay">延遲發(fā)射時(shí)間</param>  
        public void CreateCrossLine(bool isOwn, int type, int color, int spawnCount, Vector2 beginPos1, Vector2 beginPos2, Vector2 crossPos, float speed, float accel, float duration, float delay)  
        {  
            int count = 0;  
            float wait = duration / (float)spawnCount;  
  
            while (count < spawnCount)  
            {  
                mScene.AddBullet(new GameBullet(isOwn, beginPos1,  
                    Helper.GetSpeedWithPosition(beginPos1, crossPos, speed), Helper.GetSpeedWithPosition(beginPos1, crossPos, accel),  
                    type, color,  
                    wait * count + delay));  
                mScene.AddBullet(new GameBullet(isOwn, beginPos2,  
                    Helper.GetSpeedWithPosition(beginPos2, crossPos, speed), Helper.GetSpeedWithPosition(beginPos2, crossPos, accel),  
                    type, color,  
                    wait * count + delay));  
                count++;  
            }  
        }  
  
        /// <summary>  
        /// 直線彈幕  
        /// </summary>  
        /// <param name="isOwn">是否為玩家子彈</param>  
        /// <param name="type">子彈類型</param>  
        /// <param name="color">子彈顏色</param>  
        /// <param name="spawnCount">子彈數(shù)量</param>  
        /// <param name="startPos">開始地點(diǎn)</param>  
        /// <param name="targetPos">目標(biāo)地點(diǎn)(用于確定方向而已)</param>  
        /// <param name="speed">子彈移動(dòng)速度</param>  
        /// <param name="accel">子彈移動(dòng)加速度</param>  
        /// <param name="duration">發(fā)射持續(xù)時(shí)間</param>  
        /// <param name="delay">延遲發(fā)射時(shí)間</param>  
        public void CreateLine(bool isOwn, int type, int color, int spawnCount, Vector2 startPos, Vector2 targetPos, float speed, float accel, float duration, float delay)  
        {  
            int count = 0;  
            float wait = duration / (float)spawnCount;  
  
            while (count < spawnCount)  
            {  
                mScene.AddBullet(new GameBullet(isOwn, startPos,  
                    Helper.GetSpeedWithPosition(startPos, targetPos, speed), Helper.GetSpeedWithPosition(startPos, targetPos, accel),  
                    type, color,  
                    wait * count + delay));  
                count++;  
            }  
        }  
          
        /// <summary>  
        /// 隨機(jī)彈幕  
        /// </summary>  
        /// <param name="isOwn">是否為玩家子彈</param>  
        /// <param name="type">子彈類型</param>  
        /// <param name="color">子彈顏色</param>  
        /// <param name="spawnCount">子彈數(shù)量</param>  
        /// <param name="boundary">子彈范圍</param>  
        /// <param name="speed">子彈速度(包括方向)</param>  
        /// <param name="accel">子彈加速度(包括方向)</param>  
        /// <param name="duration">發(fā)射持續(xù)時(shí)間(為0表示瞬間發(fā)射所有)</param>  
        /// <param name="delay">延遲發(fā)射時(shí)間</param>  
        public void CreateRandom(bool isOwn, int type, int color, int spawnCount, RangeBox boundary, RangeVector speed, RangeVector accel, float duration, float delay)  
        {  
            int count = 0;  
            float wait = duration / (float)spawnCount;  
              
            while (count < spawnCount)  
            {  
                Vector2 sp = speed.Get();  
                Vector2 dir = sp;  
                dir.Normalize();  
                mScene.AddBullet(new GameBullet(isOwn, boundary.Get(), sp, dir * accel.Get(), type, color, count * wait + delay));  
                count++;  
            }  
        }  
    }

就來(lái)圓形彈幕來(lái)講解吧凶掰。
首先大家可以看看前面GameBullet,有個(gè)字段是用于延遲顯示的(就是說(shuō)子彈已經(jīng)添加了,只是必須要等到規(guī)定時(shí)間過(guò)去才能顯示出來(lái))
解析來(lái)看具體的實(shí)現(xiàn)

    public void CreateCircle(bool isOwn, int type, int color, Vector2 position, float speed, float accel, int interval, float delay)  
            {  
                int angle = 0;  
      
                while (angle < 360)  
                {  
                    mScene.AddBullet(new GameBullet(isOwn, position, Helper.GetSpeedWithAngle(angle, speed), Helper.GetSpeedWithAngle(angle, accel), type, color, delay));  
                    angle += interval;  
                }  
            }  

核心思想就是通過(guò)“極坐標(biāo)公式”算出不同角度對(duì)應(yīng)的坐標(biāo)懦窘,然后生成子彈
具體的計(jì)算就是Helper.GetSpeedWithAngle前翎,這個(gè)忘記的可以看前面章節(jié),有寫~
通過(guò)累加angle畅涂,循環(huán)360°港华,然后計(jì)算出不同角度的速度方向和延遲就能創(chuàng)建圓形彈幕了
再來(lái)一個(gè)用的最多的扇形彈幕

public void CreateRotateAndShoot(bool isOwn, int type, int color, Vector2 position, int startAngle, int endAngle, float speed, float accel, int interval, float duration, float delay)  
        {  
            int count = startAngle;  
            int angle = Math.Abs(endAngle - startAngle);  
            float wait = duration / (float)angle;  
              
            if ( endAngle > startAngle )  
            {  
                while (count < endAngle)  
                {  
                    mScene.AddBullet(new GameBullet(isOwn, position, Helper.GetSpeedWithAngle(count, speed), Helper.GetSpeedWithAngle(count, accel), type, color, (count - startAngle) * wait + delay ));  
                    count += interval;  
                }  
            }  
            else  
            {  
                while (count > endAngle)  
                {  
                    mScene.AddBullet(new GameBullet(isOwn, position, Helper.GetSpeedWithAngle(count, speed), Helper.GetSpeedWithAngle(count, accel), type, color, (startAngle - count) * wait + delay ));  
                    count += interval;  
                }  
            }  
        }

原理和上面類似,只是需要注意的是時(shí)間延遲傳遞的是 (startAngle-Count)*wait+delay
其實(shí)就是通過(guò)計(jì)算出需要產(chǎn)生的子彈數(shù)量已經(jīng)總的延遲午衰,然后算出每一個(gè)子彈的延遲時(shí)間立宜。
這樣的效果就是,瞬間產(chǎn)生了一堆子彈苇经,但是看到的是一個(gè)個(gè)顯示出來(lái)赘理,有一種旋轉(zhuǎn)著發(fā)射子彈的感覺宦言。扇单。。表達(dá)不好奠旺。蜘澜。
有了這個(gè)東西,就可以看看 BOSS彈幕的生成了响疚,其實(shí)就是用了這些函數(shù)而已

public static class BossBarrage  
    {  
        /// <summary>  
        /// 花瓣型彈幕  
        /// </summary>  
        /// <param name="barrage"></param>  
        /// <param name="position"></param>  
        /// <returns>彈幕持續(xù)8秒</returns>  
        public static int Petal(GameBarrage barrage, Vector2 position)  
        {  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 0, 300, 300, -350, 5, 8, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 30, 330, 300, -350, 5, 8, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 60, 360, 300, -350, 5, 8, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 90, 390, 300, -350, 5, 8, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 120, 420, 300, -350, 5, 8, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 150, 450, 300, -350, 5, 8, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 180, 480, 300, -350, 5, 8, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 210, 510, 300, -350, 5, 8, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 240, 540, 300, -350, 5, 8, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 270, 570, 300, -350, 5, 8, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 300, 600, 300, -350, 5, 8, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 330, 630, 300, -350, 5, 8, 0);  
              
            return 8;  
        }  
          
        /// <summary>  
        /// 直線型彈幕  
        /// </summary>  
        /// <param name="barrage"></param>  
        /// <returns>彈幕持續(xù)5秒</returns>  
        public static int Line(GameBarrage barrage)  
        {  
            barrage.CreateLine(false, 0, 0, 50, new Vector2(25, 0), new Vector2(25, 400), 100, 0, 15, 0);  
            barrage.CreateLine(false, 0, 1, 50, new Vector2(75, 0), new Vector2(75, 400), 100, 0, 15, 0);  
            barrage.CreateLine(false, 0, 2, 50, new Vector2(125, 0), new Vector2(125, 400), 100, 0, 15, 0);  
            barrage.CreateLine(false, 0, 3, 50, new Vector2(175, 0), new Vector2(175, 400), 100, 0, 15, 0);  
            barrage.CreateLine(false, 0, 4, 50, new Vector2(225, 0), new Vector2(225, 400), 100, 0, 15, 0);  
            barrage.CreateLine(false, 0, 5, 50, new Vector2(275, 0), new Vector2(275, 400), 100, 0, 15, 0);  
            barrage.CreateLine(false, 0, 6, 50, new Vector2(325, 0), new Vector2(325, 400), 100, 0, 15, 0);  
            barrage.CreateLine(false, 0, 0, 50, new Vector2(375, 0), new Vector2(375, 400), 100, 0, 15, 0);  
              
            return 5;  
        }  
          
        /// <summary>  
        /// 連續(xù)兩撥錯(cuò)開的扇形彈幕  
        /// </summary>  
        /// <param name="barrage"></param>  
        /// <param name="position"></param>  
        /// <returns>彈幕持續(xù)時(shí)間2秒</returns>  
        public static int TwoFans(GameBarrage barrage, Vector2 position)  
        {  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 45, 135, 300, 0, 5, 0, 0);  
            barrage.CreateRotateAndShoot(false, 0, 0, position, 43, 143, 300, 0, 5, 0, 0.1f);  
              
            return 2;  
        }  
          
        /// <summary>  
        /// 左右兩邊出現(xiàn)相反的漩渦型彈幕  
        /// </summary>  
        /// <param name="barrage"></param>  
        /// <param name="position"></param>  
        /// <returns>彈幕持續(xù)時(shí)間4秒</returns>  
        public static int TwoReverseRotate(GameBarrage barrage, Vector2 position)  
        {  
            barrage.CreateRotateAndShoot(false, 2, 0, new Vector2(50, position.Y), 0, 180, 350, -80, 8, 1, 0);  
            barrage.CreateRotateAndShoot(false, 2, 4, new Vector2(50, position.Y), 90, 270, 350, -80, 8, 1, 0);  
            barrage.CreateRotateAndShoot(false, 2, 0, new Vector2(50, position.Y), 180, 360, 350, -80, 8, 1, 0);  
            barrage.CreateRotateAndShoot(false, 2, 4, new Vector2(50, position.Y), 270, 450, 350, -80, 8, 1, 0);  
              
            barrage.CreateRotateAndShoot(false, 2, 0, new Vector2(350, position.Y), 180, 0, 350, -80, -8, 1, 0);  
            barrage.CreateRotateAndShoot(false, 2, 4, new Vector2(350, position.Y), 270, 90, 350, -80, -8, 1, 0);  
            barrage.CreateRotateAndShoot(false, 2, 0, new Vector2(350, position.Y), 360, 180, 350, -80, -8, 1, 0);  
            barrage.CreateRotateAndShoot(false, 2, 4, new Vector2(350, position.Y), 450, 270, 350, -80, -8, 1, 0);  
              
            return 4;  
        }  
          
        /// <summary>  
        /// 三個(gè)園型彈幕  
        /// </summary>  
        /// <param name="barrage"></param>  
        /// <param name="position"></param>  
        /// <returns>彈幕持續(xù)時(shí)間5秒</returns>  
        public static int ThreeCircle(GameBarrage barrage, Vector2 position)  
        {  
            barrage.CreateCircle(false, 0, 0, position, 250, 0, 10, 0);  
            barrage.CreateCircle(false, 0, 1, position + new Vector2(-100, 50), 250, 0, 10, 0);  
            barrage.CreateCircle(false, 0, 2, position + new Vector2(100, 50), 250, 0, 10, 0);  
              
            barrage.CreateCircle(false, 0, 3, position, 250, 0, 10, 0.5f);  
            barrage.CreateCircle(false, 0, 4, position + new Vector2(-100, 50), 250, 0, 10, 0.5f);  
            barrage.CreateCircle(false, 0, 5, position + new Vector2(100, 50), 250, 0, 10, 0.5f);  
              
            return 5;  
        }  
    }

代碼很多鄙信,只是通過(guò)一些數(shù)學(xué)計(jì)算,產(chǎn)生不同效果而已大家可以自由發(fā)揮

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末忿晕,一起剝皮案震驚了整個(gè)濱河市装诡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌践盼,老刑警劉巖鸦采,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異咕幻,居然都是意外死亡渔伯,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門肄程,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)锣吼,“玉大人,你說(shuō)我怎么就攤上這事蓝厌⌒” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵拓提,是天一觀的道長(zhǎng)读恃。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么狐粱? 我笑而不...
    開封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任舀寓,我火速辦了婚禮,結(jié)果婚禮上肌蜻,老公的妹妹穿的比我還像新娘互墓。我一直安慰自己,他們只是感情好蒋搜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開白布篡撵。 她就那樣靜靜地躺著,像睡著了一般豆挽。 火紅的嫁衣襯著肌膚如雪育谬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天帮哈,我揣著相機(jī)與錄音膛檀,去河邊找鬼。 笑死娘侍,一個(gè)胖子當(dāng)著我的面吹牛咖刃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播憾筏,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嚎杨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了氧腰?” 一聲冷哼從身側(cè)響起枫浙,我...
    開封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎古拴,沒想到半個(gè)月后箩帚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斤富,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年膏潮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片满力。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡焕参,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出油额,到底是詐尸還是另有隱情叠纷,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布潦嘶,位于F島的核電站涩嚣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜航厚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一顷歌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧幔睬,春花似錦眯漩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至辅肾,卻和暖如春队萤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背矫钓。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工要尔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人份汗。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓盈电,卻偏偏與公主長(zhǎng)得像蝴簇,于是被迫代替她去往敵國(guó)和親杯活。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

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