《Genesis-3D開源遊戲引擎完整實例教程-2D射擊遊戲篇08:彈幕系統》本系列完結

8.彈幕系統算法

彈幕系統概述:

彈幕系統的設計體現了射擊遊戲的基本要素,玩家要在敵人放出的大量子彈(彈幕)的細小空隙間閃避,能在玩家閃躲彈幕的時候給玩家帶來快感,接近滿屏的子彈,增長了對玩家的視覺衝擊力。網站

彈幕系統原理:

每個敵機都持有一個彈幕實例,每一個彈幕實例中包含多個子彈實例,經過配置彈幕的屬性,使每一個子彈實例在軌跡管理器的做用下,造成一種有規律性的直線運動,在視覺上給玩家展示出彈幕的效果。如圖8-1所示。ui


圖8-1

實現方法:

步驟1:spa

子彈類,定義子彈的屬性和藉口。設計

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:3d

配置彈幕發射子彈的屬性。code

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;
相關文章
相關標籤/搜索