游戏开发常用设计模式
2026/7/23 2:01:41 网站建设 项目流程

引言

游戏开发过程中,写项目越久,越发现一个问题:很多代码烂不是因为写的丑,而是因为架构没想清楚。一个功能改三遍就开始牵一发动全身,越改越想重写。

设计模式就是用来解决这个问题。接下来我将讲讲游戏开发常用的设计模式。

单例模式(Singleton)

  • 解决什么:

全局唯一的管理器,到处都能方便的调用。

  • 坑:

不要滥用,只有真正全局唯一的才用单例,玩家属性,背包这些别做单例,不然做成双人游戏欲哭无泪。还有一个容易被忽略的点,场景切换时用DontDestroyOnLoad保留的对象如果切换回主菜单再重新开始要注意清理旧状态。

  • 实现:
//继承MonoBehavior,需要挂载到场景,依赖Unity生命周期 public class SingletonMono<T> : MonoBehavior where T : MonoBehavior { private static T instance; private static bool applicationIsQuit = false; public static T Instance { get { if(applicationIsQuit) { Debug.LogWarning($"[Singleton] {typeof(T)} 已退出"); return null; } if(instance == null) { instance = FindObjectOfType<T>(); if(intance == null) { GameObject go = new GameObject(); instance = go.AddComponent<T>(); go.name = $"(Singleton) {typeof(T)}"; DontDestroyOnLoad(go); } } return instance; } } protected virtual void OnDestroy() { applicationIsQuit = ture; } }
//纯C#类,适用于纯逻辑的管理类 public class Singleton<T> : where T : class,new() { private static T instance; private static readonly object _lock = new object(); public static T Instance { get { if(instance == null) { lock(_lock) { if(instance == null) { instance = new T(); } } } return instance; } } }

对象池模式(ObjectPool)

  • 解决什么

游戏中频繁实例和销毁产生的GC卡顿,如子弹,特效等。

归还前需要将对象恢复到初始状态(位置,旋转等),池子容量要根据峰值调整,频繁扩容就失去池的意义了。

  • 实现
public class ObjectPool : MonoBehavior { [SerializeField] private GameObject prefab; [SerializeField] private int pool_Size = 20; private Queue<GameObject> pool = new Queue<GameObject>(); private void Awake() { for(int i = 0;i < pool_Size;i++) { GameObject obj = CreateNewObject(); obj.SetActive(false); pool.Enqueue(obj); } } private GameObject CreateNewObject() { GameObject obj = Instantiate(prefab,transform); return obj; } public GameObject Get() { if(pool.Count > 0) { GameObject obj = pool.Dequeue(); obj.SetActive(true); return obj; } return CreateNewObject(); //池子不够就扩容 } public void Return(GameObject obj) { obj.SetActive(false); obj.transform.SetParent(transform); pool.Enqueue(obj); } public void Clear() { while(pool.Count > 0) { GameObject obj = pool.Dequeue(); if(obj != null) { Destroy(obj); } } } public void Reset() { Clear(); for(int i = 0;i < pool_Size;i++) { GameObject obj = CreateNewObject(); obj.SetActive(false); pool.Enqueue(obj); } } }

观察者模式(Observer)

  • 解决什么

解耦事件触发者和响应者。观察者模式让玩家只管触发事件,谁关心谁自己去订阅。

如果订阅后忘了取消,被观察者销毁时可能报空引用。

  • 实现
//被观察者(玩家) public class Player : MonoBehavior { public event System.Action<int> OnLevelUp; //新等级 private int level = 1; private int exp = 0; public void AddExp(int value) { exp += value; if(exp >= level * 100) { level++; exp = 0; OnLevelUp?.Invoke(level); //触发事件 } } }
//观察者 : 成就系统 public class AchievementSystem : MonoBehavior { [SerializeField] private Player player; [SerializeField] private int targetLevel; private vodi Start() { player.OnLevelUp += OnLevelHandler; } private void OnLevelHandler(int newLevel) { if(newLevel == targetLevel) { Debug.Log($"解锁新成就,达到{targetLevel}级!"); } } private void OnDestroy() { player.OnLevelUp -= OnLevelUpHandler; } }

工厂模式(Factory)

  • 解决什么

把对象的创建逻辑集中管理,调用方不关心怎么创建。

不要过度设计,工厂里生成的对象要自己管理生命周期,不管销毁。

  • 实现
public enum EnemyType { Goblin, Dragon, Slime } public class EnemyFactory : MonoBehavior { [SerializeField] private GameObject prefab_Goblin; [SerializeField] private GameObject prefab_Dragon; [SerializeField] private GameObject prefab_Slime; public GameObject CreateEnemy(EnemyType type) { switch(type) { case EnemyType.Goblin : return Instantiate(prefab_Goblin); case EnemyType.Dragon : return Instantiate(prefab_Dragon); case EnemyType.Slime : return Instantiate(prefab_Slime); default : return null; } } }

策略模式(Strategy)

  • 解决什么:

消灭大量if-else和switch。策略模式把每种行为抽成独立的策略,运行时动态切换。

  • 坑:

策略类会膨胀,每种新闻都要创建新类。

  • 实现:
//定义策略接口 public interface IAtkStrategy { void Execute(Transform atker); }
//实现具体策略(做成ScriptObject配置表) [CreateAssetMenu(menuName = "Strategies/SwordAtk")] public class SwordAtk : ScriptObject,IAtkStrategy { [SerializeField] private float dmg = 10f; [SerializeField] private float range = 2f; public void Execute(Transform atker) { //近战判定逻辑 } }
//使用 public class Player : MonoBehavior { [SerializeField] private IAtkStrategy strategy; public void Atk() { strategy?.Execute(transform); } //运行时切换策略,如切换武器 public void SetStrategy(IAtkStrategy newStrategy) { strategy = newStrategy; } }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询