主要技术:泛型单例模式,观察者模式,接口,游戏管理器

Singleton 泛型单例模式

单例模式:Manager变量需要实例化才能使用,使用单例模式所有 Manager 变量都可以做 T ,不需要在每个Manager脚本里面实例化

  • protected virtual void Awake() 子类继承访问可重载

    protected override void Awake() 子类继承重载

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
# Singleton
// 泛型类创建<T> 继承于MonoBehaviour T:Singleton<T> T为singleton类型
public class Singleton<T> : MonoBehaviour where T:Singleton<T>
{
// 所有Manager变量都可以做T
private static T instance;

// 属性将变量看做函数,外部访问可读,返回实例本身
public static T Instance
{
get { return instance; }
}

// 继承这个泛型类的其他类都可以更改Awake方法
// protected 只允许继承类(子类)访问,virtual允许继承类重载
protected virtual void Awake()
{
// 重新加载场景manager不删除
if (instance != null)
Destroy(gameObject);
else
instance = (T)this; // 不同类this 加上当前类<T>
}

// 是否初始化
public static bool IsInitialized
{
get { return instance != null; } // 不为空则生成过,注册订阅后面操作
}

// 多个单例模式校徽
protected virtual void OnDestory()
{
if (instance == this) // 当前实例被销毁 设置为空
{
instance = null;
}
}
}
  • MouseManager 继承单例模式
1
2
3
4
5
6
7
8
9
10
11
# MouseManager
public class MouseManager : Singleton<MouseManager>
{
//public static MouseManager Instance; 不需要自己生成实例

protected override void Awake()
{
base.Awake(); // base基于原有父类方法加上的方法
//DontDestroyOnLoad(this);
}
}
  • GameManager 继承单例模式
1
2
3
4
5
6
7
8
9
10
# GameManager
public class GameManager : Singleton<GameManager>
{
public CharacterStates playStats;

public void RigisterPlay(CharacterStates player)
{
playStats = player; // CharacterStates 类型的 player传到 playStates;
}
}
  • 在 PlayerController 注册 GameManager
1
2
3
4
5
6
7
# PlayerController
void Start()
{
// 可以直接使用Manager 单例模式
// 注册 GameManager
GameManager.Instance.RigisterPlay(characterStates);
}

Observer Pattern 接口实现观察者模式订阅广播

  • 接口 Interface:用于跨多个互不相关的类定义通用功能(继承同一父类没有意义,用接口销毁所有更有效)

    通常大写 I 开头作为接口名字

    直接调用实现 不能生成实例,类要声明接口中的函数等

  • 广播过程

    1. 声明 EndNotify() 广播接口
    2. 观察者 EnemyController 调用实现接口效果
    3. GameManager 新建 IEndGameObserver 类型列表 增减观察者 对每一观察者执行广播NotifyObserver()
    4. EnemyController 根据场景需要增减观察者
    5. PlayerController Player 死亡时通过 GameManager 的执行广播方法 NotifyObserver() 通知列表的每一个观察者
    6. 观察者接收广播,执行 EndNotify() 结束
  • 声明接口,接口中只写函数定义,具体实现写在调用的类中

1
2
3
4
5
6
# IEndGameObserver
public interface IEndGameObserver // I接口 EndGame结束游戏 Observer观察者模式
{
// 结束游戏广播
void EndNotify();
}
  • 调用接口,具体实现写在调用的类中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# EnemyController
public class EnemyController : MonoBehaviour, IEndGameObserver
{
// 接口函数实现写在调用的类中
public void EndNotify()
{
// player死了所有其他角色执行
// 获胜
// 停止所有移动
// 停止agent
anim.SetBool("Win", true);
playDead = true;
isChase = false;
isWalk = false;
attackTarget = null; // 追击目标死了
}
}
  • 观察者添加和移除
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
# GameManager
public class GameManager : Singleton<GameManager>
{
public CharacterStates playStats;

// 创建一个IEndGameObserver类型的列表,观察者为角色死亡游戏结束时需要销毁的对象
List<IEndGameObserver> endGameObservers = new List<IEndGameObserver>();
public void RigisterPlay(CharacterStates player)
{
playStats = player; // CharacterStates 类型的 player传到 playStates;
// 单例模式方便访问 泛型单例模式
}

// 添加到列表中 list.add 加入列表
public void AddObserver(IEndGameObserver observer)
{
endGameObservers.Add(observer);
}

// 列表中移除 list.remove 列表删除
public void RemoveObserver(IEndGameObserver observer)
{
endGameObservers.Remove(observer);
}

// 向观察者广播 执行
public void NotifyObserver()
{
foreach(var observer in endGameObservers)
{
observer.EndNotify();
}
}
}
  • Enemy 调用观察者修改函数
1
2
3
4
5
6
7
8
9
10
11
12
# EnemyController
// 切换场景启用
void OnEnable()
{
GameManager.Instance.AddObserver(this); // 观察者加到列表
}
// 人物消失和游戏停止
void OnDisable()
{
if (!GameManager.IsInitialized) return;
GameManager.Instance.RemoveObserver(this); // 观察者移除列表
}
  • PlayerController 发布广播
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# PlayerController
public class PlayerController : MonoBehaviour
{
void Update()
{
isDead = characterStates.CurrentHealth == 0; // 简写

// 角色死亡就广播,观察者执行
// Player状态为死亡,调用GameManager的广播函数,广播函数通知观察者调用自己的接口 EndNotify()
if (isDead)
{
GameManager.Instance.NotifyObserver();
}
}
}