我们看下枪械系统要做的功能列表

  • 开枪
  • 填弹
  • 换枪
  • 捡枪
  • 弹药补给
  • 补给站补给

以上的功能列表还可以进一步拆分为如下

  • 开枪
    • 底层系统层
    • 表现层
  • 填弹
    • 底层系统层
    • 表现层
  • 换枪
    • 底层系统层
    • 表现层
  • 捡枪
    • 底层系统层
    • 表现层
  • 弹药补给
    • 底层系统层
    • 表现层
  • 补给站补给
    • 底层系统层
    • 表现层

我们先看一下填弹的功能实现图

开枪的填弹的功能实现图

按键填弹实现

我们先实现按下R键,发送ReloadCommand来填弹

我们在Command文件夹里新建ReloadCommand文件

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
using FrameWorkDesign;

namespace ShootingEditor2D
{
public class ReloadCommand : AbstractCommand
{
protected override void OnExecute()
{
var currentGun = this.GetSystem<IGunSystem>().CurrentGun;
var gunConfigItem = this.GetModel<IGunConfigModel>().GetItemByName(currentGun.Name.Value);
var needBulletCount = gunConfigItem.BulletMaxCount - currentGun.AmmoNumInGun.Value;

if (needBulletCount > 0)
{

currentGun.State.Value = GunState.Reload;

this.GetSystem<ITimeSystem>().AddTaskDelay(gunConfigItem.ReloadSeconds, () =>
{
if (currentGun.BulletCountOutGun.Value > 0)
{
if (currentGun.BulletCountOutGun.Value >= needBulletCount)
{
currentGun.AmmoNumInGun.Value += needBulletCount;
currentGun.BulletCountOutGun.Value -= needBulletCount;
}
else
{
currentGun.AmmoNumInGun.Value += currentGun.BulletCountOutGun.Value;
currentGun.BulletCountOutGun.Value = 0;
}
}
currentGun.State.Value = GunState.Idle;
});
}
}
}
}

接下来,我们修改Gun脚本,为它添加Reload方法

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
using UnityEngine;
using FrameWorkDesign;

namespace ShootingEditor2D
{
public class Gun : MonoBehaviour,IController
{
private Bullet m_Bullet;

private GunInfo m_GunInfo;

private int mMaxBulletCount;//

private void Awake()
{
m_Bullet = transform.Find("Bullet").GetComponent<Bullet>();

m_GunInfo = this.GetSystem<IGunSystem>().CurrentGun;

mMaxBulletCount = this.SendQuery(new MaxBulletCountQuery(m_GunInfo.Name.Value));//
}

//...
public void Reload()//
{
if (m_GunInfo.State.Value == GunState.Idle &&
m_GunInfo.AmmoNumInGun.Value != mMaxBulletCount &&
m_GunInfo.BulletCountOutGun.Value > 0)
{
this.SendCommand<ReloadCommand>();
}
}
}
}

修改Player脚本,添加R键的监听

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
using UnityEngine;

namespace ShootingEditor2D
{
public class Player : MonoBehaviour
{
//...

private void Update()
{
if(Input.GetButtonDown("Jump"))
m_JumpPressed = true;
if (Input.GetKeyDown(KeyCode.J))
{
m_Gun.Shoot();
}
if (Input.GetKeyDown(KeyCode.R))//
{
m_Gun.Reload();
}
}

//...
}
}

注意这里的编程实践,我们把大部分的按键监听都放在了Palyer脚本里,避免在其他脚本中(比如Gun脚本)调用Update生命周期函数(来监听按键等)。

自动填弹实现

我们直接按照功能实现图里设计的,在ShootCommand里面能够进行子弹判断并发送ReloadCommand,我们在每次子弹射击完之后加一个判断

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
using FrameWorkDesign;

namespace ShootingEditor2D
{
public class ShootCommand : AbstractCommand
{
public static readonly ShootCommand Instance = new ShootCommand();
protected override void OnExecute()
{
var gunSystem = this.GetSystem<IGunSystem>();
gunSystem.CurrentGun.AmmoNumInGun.Value--;
gunSystem.CurrentGun.State.Value = GunState.Shooting;

var gunConfigItem = this.GetModel<IGunConfigModel>().GetItemByName(gunSystem.CurrentGun.Name.Value);
var timeSystem = this.GetSystem<ITimeSystem>();
timeSystem.AddTaskDelay( 1/gunConfigItem.Frequency, () =>
{
gunSystem.CurrentGun.State.Value = GunState.Idle;

if (gunSystem.CurrentGun.AmmoNumInGun.Value == 0 && gunSystem.CurrentGun.BulletCountOutGun.Value > 0)//
{
this.SendCommand<ReloadCommand>();
}
});
}
}
}

Command嵌套复用和Query的嵌套复用是此框架的特色之一,要留意