之前通过BulletMgr
和Bullet
脚本发射子弹复用性不高,我们需要重构一下这里的逻辑。
子弹的轨迹部分的逻辑也需要添加上。
子弹轨迹
添加BulletConfig.json(它的Path略),并将GameConfig.json当中的子弹速度转移到这里来,然后添加子弹各个等级的偏移角度。
1 2 3 4 5 6 7 8 9 10 11
| { "Player": { "bulletSpeed": 5, "trajectory": { "0": [ 90 ], "1": [ -30, 30 ], "2": [ -30, 90, 30 ], "3": [ -30, -60, 90, 60, 30 ] } } }
|
ITrajectory
在Logic文件夹中新建Trajectory文件夹,并在其中新建ITrajectory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| using UnityEngine; public interface ITrajectory { void Init(float angle); float GetX(Vector2 startPos, float y); }
public class StraightTrajectory : ITrajectory { private float _k; public void Init(float angle) { _k = Mathf.Tan(angle * Mathf.Deg2Rad); }
public float GetX(Vector2 startPos, float y) { return (y - startPos.y) / _k + startPos.x; } }
|
直线轨迹的斜率k就是夹角θ的tan值,而Unity使用弧度计算tan,所以我们把配置文件中传入的角度值乘Mathf.Deg2Red
来转化为弧度值,从而计算出斜率k,然后套入直线公式来获取坐标。
重构发射逻辑
IBulletModel
发射的子弹五花八门,而且在运行时可能会修改它的属性,我们需要一个它的数据模型接口。这个接口包括了子弹的射击间隔、图片、移动速度、轨迹等信息。
在Logic文件夹中新建Model文件夹,并在其中新建BulletModel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| using LitJson; using System;
public interface IBulletModel { float FireTime { get; } void GetTrajectory(Action<ITrajectory[]> callback); string SpritePath(string name); void GetBulletSpeed(Action<float> callback);
} public class PlayerBulletModel : IBulletModel { public float FireTime { get { string key = KeysUtil.GetPropertyItemKey(PropertyItem.ItemKey.value, PlaneProperty.Property.fireRate.ToString()); var ratio = DataMgr.Instance.Get<int>(key); return Consts.FIRE_BASE_TIME / ratio; } } private ITrajectory[] _trajectory; public void GetTrajectory(Action<ITrajectory[]> callback) { var reader = ReaderMgr.Instance.GetReader(Pathes.BULLET_CONFIG); int level = GameStateModel.Instance.PlaneLevel;
reader["Player"]["trajectory"][level.ToString()].Get<JsonData>(data => { if (_trajectory == null) { if (!data.IsArray) { UnityEngine.Debug.LogError("当前数据不是一个数组,data:" + data); return; } InitTrajectory(data); } callback?.Invoke(_trajectory); }); } private void InitTrajectory(JsonData data) { _trajectory = new ITrajectory[data.Count]; for (int i = 0; i < data.Count; i++) { if (!float.TryParse(data[i].ToJson(), out float result)) { UnityEngine.Debug.LogError("JsonData转换错误,不是Array,请检查" + data[i]); } var trajectory = new StraightTrajectory(); trajectory.Init(result); _trajectory[i] = trajectory; } } public string SpritePath(string name) { return Pathes.PLAYER_BULLET_PICTURE_FOLDER + name; }
public void GetBulletSpeed(System.Action<float> callback) { var reader = ReaderMgr.Instance.GetReader(Pathes.GAME_CONFIG); reader["bulletSpeed"].Get<float>(value => { callback?.Invoke(value); }); } }
|
BulletMgr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| using System.Collections; using System.Collections.Generic; using UnityEngine;
public class BulletMgr : MonoBehaviour { public void Init(IBulletModel bulletModel) { CoroutineMgr.Instance.ExecuteOnce(Fire(bulletModel)); } private IEnumerator Fire(IBulletModel bulletModel) { float startTime = Time.time; while (true) { yield return new WaitForSeconds(bulletModel.FireTime); bulletModel.GetTrajectory(trajectories => { for (int i = 0; i < trajectories.Length; i++) { SpawnBullet(bulletModel, trajectories[i]); } });
if (Time.time - startTime > Consts.FIRE_DURATION) { yield return new WaitForSeconds(Consts.FIRE_CD_TIME); startTime = Time.time; } } } private void SpawnBullet(IBulletModel bulletModel,ITrajectory trajectory) { var bulletGo = PoolMgr.Instance.Spawn(Pathes.PREFAB_BULLET); var bullet = bulletGo.AddOrGet<Bullet>(); bullet.Init(bulletModel,trajectory,transform.position); } }
|
使用Init
方法初始化BulletMgr
。
修改SpawnBullet
方法。
将GetFireTime
方法转移到PlayerBulletModel
当中的FireTime
属性中
Bullet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| using UnityEngine;
public class Bullet : MonoBehaviour, IUpdate { private float _speed; private MoveComponent _moveCo; private IBulletModel _bulletModel; private ITrajectory _trajectory; private Vector3 _spawnPos; private void Start() { int id = GameStateModel.Instance.SelectedPlaneId; Sprite sprite = LoadMgr.Instance.Load<Sprite>(_bulletModel.SpritePath(id.ToString())); GetComponent<SpriteRenderer>().sprite = sprite;
_bulletModel.GetBulletSpeed( value => { _speed = value; _moveCo = transform.AddCo<MoveComponent>(); _moveCo.Init(_speed); }); } public void Init(IBulletModel bulletModel,ITrajectory trajectory, Vector3 parentPos) { _bulletModel = bulletModel; _spawnPos = parentPos; _trajectory = trajectory; SetPos(parentPos); } private void OnEnable() { LifeCycleMgr.Instance.Add(LifeName.UPDATE, this); }
public void UpdateFun() { if (_moveCo != null) { _moveCo.Move(Vector2.up); ResetTrajectoryPos(); } } private void ResetTrajectoryPos() { var pos = transform.position; pos.x = _trajectory.GetX(_spawnPos,pos.y); transform.position = pos; } private void OnDisable() { LifeCycleMgr.Instance.Remove(LifeName.UPDATE, this); } public void SetPos(Vector3 pos) { transform.position = pos; } private void OnBecameInvisible() { PoolMgr.Instance.Despawn(gameObject); } }
|
使用Init
方法初始化Bullet
。
PlayerView
1 2 3 4 5 6
| private void InitComponent() { var bulletMgr = transform.AddCo<BulletMgr>("BulletRoot"); bulletMgr.Init(new PlayerBulletModel()); }
|