之前通过BulletMgrBullet脚本发射子弹复用性不高,我们需要重构一下这里的逻辑。

子弹的轨迹部分的逻辑也需要添加上。

子弹轨迹

添加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);
}
/// <summary>
/// 直线轨迹
/// </summary>
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());//+++
}