GunMayhem-工厂模式优化枪械创建

原先的设计

在原来的实现方案中,使用了一个空物体WeaponPoolObj挂载了WeaponPool脚本,该脚本中利用Dictionary实现对武器名称和武器GameObject的管理。

问题:

  • 每个地图场景都要有WeaponPoolObj这个物体
  • Unity中的Dictionary不支持序列化,无法在编辑界面中手动添加武器键值对,要用代码添加
  • 想实现Dictionary序列化,必须手动实现SerializableDictionary或第三方插件

优化:使用工厂模式优化枪械的创建

  • 创建继承自ScriptableObject的WeaponFactory,方便在Inspector中编辑
  • 在WeaponFactory中实现武器的创建GetWeapon
  • 在角色和敌人的脚本中Resources.Load<WeaponFactory>,并在需要的时候调用GetWeapon方法获取武器

UML类图

代码实现

PlayerBehavior

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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerBehave : MonoBehaviour
{
private WeaponFactory weaponFactory;

void Start()
{
weaponFactory = Resources.Load<WeaponFactory>("WeaponFactory");
setBaseWeapon();
}

/// <summary>
/// 设置武器
/// </summary>
/// <param name="name"></param>
public void setWeapon(string name)
{
if (transform.Find("weapon") != null)
Destroy(transform.Find("weapon").gameObject);

GameObject temp = weaponFactory.GetWeapon(name);
temp.transform.SetParent(transform);
temp.transform.position = weaponPoint.position;
temp.transform.localScale = Vector3.one; //修复武器反向的Bug
temp.name = "weapon";

//设置武器阵营
if (transform.Find("weapon") != null)
transform.Find("weapon").GetComponent<weapon>().setTeam(playerInfo.getTeam());
else Debug.Log(gameObject.name + " Weapon not found!");
}

/// <summary>
/// 设置初始武器
/// </summary>
public void setBaseWeapon()
{
setWeapon(firstWeapon);
}
}

WeaponFactory

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "WeaponFactory", menuName = "Factory/WeaponFactory")]
public class WeaponFactory : ScriptableObject
{
#region pistol
[SerializeField]
private GameObject bull;
[SerializeField]
private GameObject glock;
[SerializeField]
private GameObject gold;
[SerializeField]
private GameObject m1911;
#endregion

#region rifle
[SerializeField]
private GameObject ak47;
[SerializeField]
private GameObject bizon;
[SerializeField]
private GameObject m12;
[SerializeField]
private GameObject p90;
#endregion

#region shotGun
[SerializeField]
private GameObject ithaca;
[SerializeField]
private GameObject ksg;
[SerializeField]
private GameObject leaver;
[SerializeField]
private GameObject sawnOff;
#endregion

#region sniper
[SerializeField]
private GameObject sniper501;
[SerializeField]
private GameObject awn;
[SerializeField]
private GameObject hk;
[SerializeField]
private GameObject m95;
#endregion

public GameObject GetWeapon(string GameObjectName)
{
switch (GameObjectName)
{
case "bull":
return Instantiate(bull);
case "glock":
return Instantiate(glock);
case "gold":
return Instantiate(gold);
case "m1911":
return Instantiate(m1911);
case "ak47":
return Instantiate(ak47);
case "bizon":
return Instantiate(bizon);
case "m12":
return Instantiate(m12);
case "p90":
return Instantiate(p90);
case "ithaca":
return Instantiate(ithaca);
case "ksg":
return Instantiate(ksg);
case "leaver":
return Instantiate(leaver);
case "sawnOff":
return Instantiate(sawnOff);
case "501":
return Instantiate(sniper501);
case "awn":
return Instantiate(awn);
case "hk":
return Instantiate(hk);
case "m95":
return Instantiate(m95);
default:
Debug.LogWarning("GameObject:" + GameObjectName + "Not Found");
return Instantiate(bull);
}
}
}

可优化的地方

GetWeapon采用字符串作为参数来判断生成哪种武器,编码中输入字符串时容易出错,可以改用枚举