基于C#弹幕类射击游戏的实现——(七)弹幕类实现

如果只有这些子弹,那看起来必然是很一般的,想想看,只有几颗子弹,孤零零的从下面跑到上面。。。。。
GameBarrage弹幕类,用于创建一些酷炫叼的弹幕其实核心也就是通过一些数学公式,然后批量AddBullet而已
先来看看类型的定义

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

初步就这四种,其余的弹幕类型都可以通过这几种组合出来
然后就是弹幕的具体实现

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">中心点位置</param>  
        /// <param name="speed">子弹移动速度</param>  
        /// <param name="accel">子弹移动加速度</param>  
        /// <param name="interval">每颗子弹的角度间隔</param>  
        /// <param name="delay">延迟发射时间</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">中心点的位置</param>  
        /// <param name="startAngle">扇形的起始角度(向右为0°)</param>  
        /// <param name="endAngle">扇形的结束角度(顺时针)</param>  
        /// <param name="speed">子弹移动速度</param>  
        /// <param name="accel">子弹移动加速度</param>  
        /// <param name="interval">每颗子弹的角度间隔</param>  
        /// <param name="duration">发射持续时间(为0表示瞬间发射所有)</param>  
        /// <param name="delay">延迟发射时间</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">子弹数量</param>  
        /// <param name="beginPos1">开始地点一</param>  
        /// <param name="beginPos2">开始地点二</param>  
        /// <param name="crossPos">交叉点</param>  
        /// <param name="speed">子弹移动速度</param>  
        /// <param name="accel">子弹移动加速度</param>  
        /// <param name="duration">发射持续时间(为0表示瞬间发射所有)</param>  
        /// <param name="delay">延迟发射时间</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">子弹数量</param>  
        /// <param name="startPos">开始地点</param>  
        /// <param name="targetPos">目标地点(用于确定方向而已)</param>  
        /// <param name="speed">子弹移动速度</param>  
        /// <param name="accel">子弹移动加速度</param>  
        /// <param name="duration">发射持续时间</param>  
        /// <param name="delay">延迟发射时间</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>  
        /// 随机弹幕  
        /// </summary>  
        /// <param name="isOwn">是否为玩家子弹</param>  
        /// <param name="type">子弹类型</param>  
        /// <param name="color">子弹颜色</param>  
        /// <param name="spawnCount">子弹数量</param>  
        /// <param name="boundary">子弹范围</param>  
        /// <param name="speed">子弹速度(包括方向)</param>  
        /// <param name="accel">子弹加速度(包括方向)</param>  
        /// <param name="duration">发射持续时间(为0表示瞬间发射所有)</param>  
        /// <param name="delay">延迟发射时间</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++;  
            }  
        }  
    }

就来圆形弹幕来讲解吧。
首先大家可以看看前面GameBullet,有个字段是用于延迟显示的(就是说子弹已经添加了,只是必须要等到规定时间过去才能显示出来)
解析来看具体的实现

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

核心思想就是通过“极坐标公式”算出不同角度对应的坐标,然后生成子弹
具体的计算就是Helper.GetSpeedWithAngle,这个忘记的可以看前面章节,有写~
通过累加angle,循环360°,然后计算出不同角度的速度方向和延迟就能创建圆形弹幕了
再来一个用的最多的扇形弹幕

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

原理和上面类似,只是需要注意的是时间延迟传递的是 (startAngle-Count)*wait+delay
其实就是通过计算出需要产生的子弹数量已经总的延迟,然后算出每一个子弹的延迟时间。
这样的效果就是,瞬间产生了一堆子弹,但是看到的是一个个显示出来,有一种旋转着发射子弹的感觉。。。表达不好。。
有了这个东西,就可以看看 BOSS弹幕的生成了,其实就是用了这些函数而已

public static class BossBarrage  
    {  
        /// <summary>  
        /// 花瓣型弹幕  
        /// </summary>  
        /// <param name="barrage"></param>  
        /// <param name="position"></param>  
        /// <returns>弹幕持续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>弹幕持续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>  
        /// 连续两拨错开的扇形弹幕  
        /// </summary>  
        /// <param name="barrage"></param>  
        /// <param name="position"></param>  
        /// <returns>弹幕持续时间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>  
        /// 左右两边出现相反的漩涡型弹幕  
        /// </summary>  
        /// <param name="barrage"></param>  
        /// <param name="position"></param>  
        /// <returns>弹幕持续时间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>  
        /// 三个园型弹幕  
        /// </summary>  
        /// <param name="barrage"></param>  
        /// <param name="position"></param>  
        /// <returns>弹幕持续时间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;  
        }  
    }

代码很多,只是通过一些数学计算,产生不同效果而已大家可以自由发挥

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

推荐阅读更多精彩内容