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. JRE下的rt.jar、tools.jar

    JRE下的rt.jar: 这个文件是极为重要的一个文件,rt是runtime的缩写,即运行时的意思.是java程序在运行时必不可少的文件. 里面包含了java程序员常用的包,如java.lang,ja ...

  2. java类的加载以及初始化顺序

    类的加载和初始化的了解对于我们对编程的理解有很大帮助,最近在看类的记载方面的问题.从网上查阅了若干文章,现总结如下: 我们通过一段代码来了解类加载和初始化的顺序: package com.classl ...

  3. python写的第一个简单小游戏-猜数字

    #Filename:game1.py guess=10 running=True while running: try: answer=int(raw_input('Guess what i thin ...

  4. 进程间通信的WM_COPYDATA的使用

    http://blog.csdn.net/ao929929fei/article/details/6316174 接收数据的一方 ON_WM_COPYDATA() afx_msg BOOL OnCop ...

  5. 12 Useful “df” Commands to Check Disk Space in Linux

    On the internet you will find plenty of tools for checking disk space utilization in Linux. However, ...

  6. 宏HASH_GET_NEXT

    /*******************************************************************//** Gets the next struct in a h ...

  7. 真正解决ASP.NET每一个页面首次访问超级慢的问题 (转载)

    原文:http://www.afuhao.com/article_articleId-219.shtml 摘要:ASP.NET页面首次打开很慢,但别的页面如果没有访问过,去访问也会慢.你也许认为它是在 ...

  8. lrj计算几何模板

    整理了一下大白书上的计算几何模板. #include <cstdio> #include <algorithm> #include <cmath> #include ...

  9. TIOBE 2015年5月编程语言排行榜 Visual Studio系列在上升

    TIOBE 编程语言社区排行榜是编程语言流行趋势的一个指标,每月更新,这份排行榜排名基于互联网上有经验的程序员. 课程和第三方厂商的数量.排名使用著名的搜索引擎(诸如 Google.MSN.Yahoo ...

  10. 继承在WCF中的问题和解决办法

    1. 问题 假设有代码如下: [ServiceContract] public interface IA { [OperationContract] string M1(); } [ServiceCo ...