8.弹幕系统

弹幕系统概述:

弹幕系统的设计体现了射击游戏的基本要素,玩家要在敌人放出的大量子弹(弹幕)的细小空隙间闪避,能在玩家闪躲弹幕的时候给玩家带来快感,接近满屏的子弹,增加了对玩家的视觉冲击力。

弹幕系统原理:

每一个敌机都持有一个弹幕实例,每个弹幕实例中包含多个子弹实例,通过配置弹幕的属性,使每个子弹实例在轨迹管理器的作用下,形成一种有规律性的直线运动,在视觉上给玩家展现出弹幕的效果。如图8-1所示。


图8-1

实现方法:

步骤1:

子弹类,定义子弹的属性和借口。

01 public class Bullet
02 {
03     //从模板创建子弹Actor
04     public void CreateActor ()
05     {
06         _obj = ActorManager.CreateFromTemplate(@"asset:bullet01.template",false);
07  
08     }
09  
10     //激活,显示子弹
11     public void ActiveObj (Vector2 startPos)
12     {
13         _obj.Active();
14         if (_obj.GetChildCount()>0)
15         {
16             _obj.GetChild(0).Active();
17         }
18  
19         _obj.WorldPosition = new Vector3 (startPos.X,startPos.Y,2.0f);
20     }
21  
22     //隐藏子弹
23     public void DeactiveObj ()
24     {
25         _obj.Deactive();
26         if (_obj.GetChildCount()>0)
27         {
28             _obj.GetChild(0).Deactive();
29         }
30     }
31     private Actor _obj = new Actor();
32     private UInt32 _id; 
33     private UInt32 _target_id;
34     private Vector2 _startPos;
35     private bool _isShooted = false;
36 }

步骤2:

配置弹幕发射子弹的属性。

01 public class Barrage
02   {
03       //发射子弹
04       public void ShootBullet (float elapsedTime, Vector3 pos)
05       {
06           timer +=  elapsedTime;
07           if (timer >= _shoot_interval && _needshoot_id <= (Bullets.Count - 1))
08           {
09               Vector2 posV2 = new Vector2(pos.X,pos.Y);
10               Bullets[_needshoot_id].ActiveObj(posV2);
11               Bullets[_needshoot_id].SetShooted(true);
12               _needshoot_id ++;
13               timer = 0.0f;
14           }
15       private UInt32 _id;
16       private UInt32 _obj_id;                  
17       private float _start_speed;
18       private float _accel_speed;
19       private float _shoot_interval;
20       private float _shoot_direction;
21       private float _direction_offset;
22       private List< Bullet> Bullets; 
23       private TrajectoryType _tt ;
24       private float timer = 0.0f;
25       private int _needshoot_id = 0;
26       private Actor _owner;
27       }
28   }

步骤3:

设计弹幕管理器,管理每一个弹幕实例的发射。

01 public class BarrageMgr
02   {
03       //请求子弹
04       public bool AskForBullets (int count, List< Bullet> bullets, Actor owner)
05       {
06           if (ReloadBullet.Count == 0)
07           {
08               return false;
09           }
10  
11           if (count >= ReloadBullet.Count)
12           {
13               count = ReloadBullet.Count;
14           }
15  
16           for (int i = 0; i < count; i++)
17           {
18               ReloadBullet[i].DeactiveObj();
19               Vector2 pos = new Vector2(owner.WorldPosition.X,owner.WorldPosition.Y);
20  
21               ReloadBullet[i].setPos(pos);
22               bullets.Add(ReloadBullet[i]);
23  
24           }
25           ReloadBullet.RemoveRange(0,count);
26           return true;
27       }
28       //处理轨迹
29       public void DealTrajectory (Barrage barrage,float elapsedTime)
30       {
31           _trajectoryMgr.MoveBarrage(barrage,elapsedTime);   
32       }
33       //更新弹幕位置
34       public void Tick(float elapsedTime)
35       {
36           foreach (KeyValuePair< uint,Barrage> pair in _barrageDict)
37           {
38  
39               Barrage barrage = pair.Value;
40    
41               DealTrajectory(barrage,elapsedTime);
42               barrage.DestroyBullet();
43               if (!barrage.IsOwnerActive() && barrage.IsAllBulletsDeactive())
44               {
45                   barrage.Reload();
46               }
47           }
48           Debug.Dbgout( _barrageDict.Count.ToString() );
49       }
50  
51   }

步骤4:

设计轨迹管理器,使子弹形成一种有规律性的直线运动。

01 public class Trajectory
02 {
03     //直线轨迹算法
04     public static Vector2 GoStraight(Vector2 start_pos, float direction,
05                                      float start_speed, float accel_speed, float use_time, outVector2 pos)
06     {
07         float angle = direction * (float)Math.PI / 180.0f;
08         float seconds = (float)use_time;
09         float move_length = start_speed * seconds + accel_speed * seconds * seconds / 2.0f;
10         pos.X = move_length * (float)Math.Cos(angle) + start_pos.X;
11         pos.Y = move_length * (float)Math.Sin(angle) + start_pos.Y;
12         return pos;
13     }
14      
15     //这里的跟踪算法主要适用于匀速圆周运动类型的要跟踪,速率不变,一定的旋转角度
16     //追踪轨迹算法
17     public static Vector2 Tracking(Vector2 start_pos, ref float direction, Vector2 dest_pos,
18                                    float start_speed, float accel_speed, float track_degree,float use_time)
19     {
20         Vector2 newpos = new Vector2(0, 0);
21          
22         if (direction < 0)
23         {
24             direction += 360;
25         }
26         else
27         {
28             direction = direction % 360;
29         }
30          
31         //判断目标与飞行的夹角
32         float degree =(float) (Math.Atan2(dest_pos.Y - start_pos.Y,
33                                    dest_pos.X - start_pos.X) * 180 / Math.PI);
34         if (degree < 0)
35         {
36             degree += 360;
37         }
38          
39         //最小目标夹角
40         float dest_degree = (float)Math.Abs(degree - direction) % 360;
41         if (dest_degree > 180)
42         {
43             dest_degree = 360 - dest_degree;
44         }
45         if (dest_degree < 0.000001)
46         {
47             GoStraight(start_pos, direction, start_speed, accel_speed, use_time,out newpos);
48             return newpos;
49         }
50          
51         //计算最终旋转的夹角
52         float use_seconds = use_time / 1000.0f;
53         float rotate_degree = track_degree * use_seconds;
54         if (rotate_degree > dest_degree)
55         {
56             rotate_degree = dest_degree;
57         }
58         double inner_degree = degree - direction;
59         if (inner_degree > 180)
60         {
61             direction -= rotate_degree;
62         }
63         else if (inner_degree <= 180 && inner_degree >= 0)
64         {
65             direction += rotate_degree;
66         }
67         else if (inner_degree < -180)
68         {
69             direction += rotate_degree;
70         }
71         else if (inner_degree >= -180 && inner_degree <= 0)
72         {
73             direction -= rotate_degree;
74         }
75              
76         GoStraight(start_pos, direction, start_speed, accel_speed, use_time, out newpos);
77         return newpos;
78     }  
79  
80 }


引擎官方网站:http://www.genesis-3d.com.cn/

官方论坛:http://bbs.9tech.cn/genesis-3d/

官方千人大群:59113309   135439306

YY频道-游戏开发大讲堂(完全免费,定期开课):51735288

Genesis-3D开源游戏引擎:游戏起源,皆因有我!!!

 


《Genesis-3D开源游戏引擎完整实例教程-2D射击游戏篇08:弹幕系统》本系列完结的更多相关文章

  1. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程:简介及目录》(附上完整工程文件)

    介绍:讲述如何使用Genesis-3D来制作一个横版格斗游戏,涉及如何制作连招系统,如何使用包围盒实现碰撞检测,软键盘的制作,场景切换,技能读表,简单怪物AI等等,并为您提供这个框架的全套资源,源码以 ...

  2. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程04:技能的输入与检测》

    4.技能的输入与检测 概述: 技能系统的用户体验,制约着玩家对整个游戏的体验.游戏角色的技能华丽度,连招的顺利过渡,以及逼真的打击感,都作为一款游戏的卖点吸引着玩家的注意.开发者在开发游戏初期,会根据 ...

  3. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程01: 资源导入》

    1. 资源导入 概述: 制作一款游戏需要用到很多资源,比如:模型.纹理.声音和脚本等.通常都是用其它相关制作资源软件,完成前期资源的收集工作.比如通常用的三维美术资源,会在Max.MAYA等相应软件中 ...

  4. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程08:虚拟键盘实现》--本系列完结

    8.虚拟键盘实现 概述: 硬键盘就是物理键盘,平时敲的那种.软键盘是虚拟的键盘,不是在键盘上,而是在"屏幕"上.虚拟按键就是虚拟键盘的一部分,根据功能需求,提供部分按键效果的UI可 ...

  5. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程07:UI》

    概述: UI即User Interface(用户界面)的简称.UI设计是指对软件的燃机交互.操作逻辑.界面美观的整体设计.好的UI设计不仅可以让游戏变得更有品位,更吸引玩家,还能充分体现开发者对游戏整 ...

  6. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程06:技能播放的逻辑关系》

    6.技能播放的逻辑关系 技能播放概述: 当完成对技能输入与检测之后,程序就该对输入在缓存器中的按键操作与程序读取的技能表信息进行匹配,根据匹配结果播放相应的连招技能. 技能播放原理: 按键缓存器中内容 ...

  7. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程05:技能读表》

    5.技能读表 技能读表概述: 技能读表,作为实现技能系统更为快捷的一种方式,被广泛应用到游戏开发中.技能配表,作为桥梁连接着游戏策划者和开发者在技能实现上的关系.在游戏技能开发中,开发者只需要根据策划 ...

  8. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程03:碰撞检测》

    3.碰撞检测 碰撞检测的概述: 碰撞在物理学中表现为两粒子或物体间极端的相互作用.而在游戏世界中,游戏对象在游戏世界自身并不受物理左右,为了模拟真实世界的效果,需要开发者为其添加属性,以模拟真实事件的 ...

  9. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程02:关键帧动画导入与切割》

    2. 关键帧动画导入与切割 动画的分割与导入概述: 在游戏当中,游戏角色在不同状态下会有不同的动作,这些动作在引擎里相当于一段段的动画片段.当导入模型资源的时候,连同模型动画都会一并导入到引擎中.开发 ...

  10. Beat &#39;Em Up Game Starter Kit (横版格斗游戏) cocos2d-x游戏源代码

    浓缩精华.专注战斗! 游戏的本质是什么?界面?养成?NoNo!    游戏来源于对实战和比赛的模拟,所以它的本源就是对抗.就是战斗! 是挥洒热血的一种方式! 一个游戏最复杂最难做的是什么?UI?商城? ...

随机推荐

  1. The Introduction of Java Memory Leaks

    One of the most significant advantages of Java is its memory management. You simply create objects a ...

  2. OSSEC 安装执行./install.sh详细信息

    下载好ossec安装文件后解压得到如下目录 [root@localhost ~]# cd ossec-hids-/ [root@localhost ossec-hids-]# ll total drw ...

  3. xargs的- n1参数

    起因在对一堆*.tar.gz文件解压缩时,发现tar xvfz *.tar.gz不管用,一查,原来是tar xvfz *.tar.gz会被shell给拆成tar xvfz a.tar.gz b.tar ...

  4. UVa 1402 Runtime Error 伸展树

    Runtime Error 到现在连样例也跑不出来!!! 调试了一晚上快要死了…… 知道错在哪里但是不会改,代码先扔在这里吧.看来不能太依赖模板啊orz…… #include <cstdio&g ...

  5. Checked&Unchecked Exception

    Java 中定义了两类异常: 1) Checked exception: 这类异常都是Exception的子类 .异常的向上抛出机制进行处理,如果子类可能产生A异常,那么在父类中也必须throws A ...

  6. struct hw_module_t HAL_MODULE_INFO_SYM

    先开个头,准备这与一篇struct hw_module_t HAL_MODULE_INFO_SYM 相关的文章. Hal层的库文件是怎么被上层调用的?上层调用时的入口(相当于main)又是什么呢?它就 ...

  7. 【POJ】3523 The Morning after Halloween

    1. 题目描述$m \times n$的迷宫(最大为$16 \times 16$)包含最多3个点,这些点可以同时向相邻方向移动或保持停止,使用小写字母表示起始位置,使用大写字母表示中止位置.求最少经过 ...

  8. maven常用构建命令

    mvn -v 查看maven版本 compile   编译项目 install   将项目加入到本地仓库中 clean   删除target test    测试 package     打包

  9. BZOJ2226: [Spoj 5971] LCMSum

    题解: 考虑枚举gcd,然后问题转化为求<=n且与n互质的数的和. 这是有公式的f[i]=phi[i]*i/2 然后卡一卡时就可以过了. 代码: #include<cstdio> # ...

  10. 为apache单独编译mod_rewrite.so

    今天要把一个站点搬到一台Red Hat 4.1.2-42系统上,在配置rewrite的时候,发现apache没有mod_rewrite,可能是当初编译apache的时候没有带上 --enable-re ...