zoukankan      html  css  js  c++  java
  • 《Genesis-3D开源游戏引擎完整实例教程-2D射击游戏篇08:弹幕系统》本系列完结

    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开源游戏引擎:游戏起源,皆因有我!!!

     


     

  • 相关阅读:
    2021-06-22 总结
    【每日一题】13. 罗马数字转整数
    【每日一题】12. 整数转罗马数字
    【每日一题】1269. 停在原地的方案数
    【每日一题】1310. 子数组异或查询
    【每日一题】1734. 解码异或后的排列
    【每日一题】872. 叶子相似的树
    【每日一题】1482. 制作 m 束花所需的最少天数
    【每日一题】1723. 完成所有工作的最短时间
    【每日一题】1486. 数组异或操作
  • 原文地址:https://www.cnblogs.com/G-3D/p/3526721.html
Copyright © 2011-2022 走看看