一、架构设计原则
-
模块化分层
采用「MVC+事件总线」架构,将客户端划分为:- Model层:管理游戏数据(如角色属性、配置表)
- View层:UI界面与交互组件(推荐NGUI+MVC模式)
- Controller层:业务逻辑与网络交互
- EventBus:基于Advanced C# Messenger实现跨模块通信
// 示例:事件总线注册与触发 public class EventBus : MonoBehaviour { private static Dictionary<Type, List<Delegate>> _eventTable = new Dictionary<Type, List<Delegate>>(); public static void Subscribe<T>(Action<T> handler) where T : class { Type eventType = typeof(T); if (!_eventTable.ContainsKey(eventType)) { _eventTable[eventType] = new List<Delegate>(); } _eventTable[eventType].Add(handler); } public static void Publish<T>(T data) where T : class { Type eventType = typeof(T); if (_eventTable.TryGetValue(eventType, out var handlers)) { foreach (var handler in handlers) { ((Action<T>)handler)(data); } } } }
-
网络通信设计
- 协议选择:使用Protobuf定义数据包(
.proto
文件),压缩率提升60% - 传输层实现:基于UDP+可靠性封装,关键代码如下:
public class ReliableUDP { private Dictionary<ulong, Packet> _pendingPackets = new Dictionary<ulong, Packet>(); private const int MAX_RETRIES = 3; public void Send(Packet packet) { ulong seqId = ++_lastSeqId; packet.SeqId = seqId; byte[] data = ProtobufSerializer.Serialize(packet); _pendingPackets[seqId] = packet; for (int i = 0; i < MAX_RETRIES; i++) { SendRaw(data); if (IsAckReceived(seqId)) break; } } private void SendRaw(byte[] data) { // 实际UDP发送逻辑 } private bool IsAckReceived(ulong seqId) { // 确认机制实现 return false; } }
- 协议选择:使用Protobuf定义数据包(
二、核心系统实现
-
资源管理
- AssetBundle流水线:按场景/功能分包,支持动态加载与卸载
- 内存优化:使用对象池管理频繁创建的对象(如子弹、特效)
public class ObjectPool<T> where T : Component { private Queue<T> _pool = new Queue<T>(); public T Get() { if (_pool.Count > 0) { return _pool.Dequeue(); } return null; } public void Return(T obj) { obj.gameObject.SetActive(false); _pool.Enqueue(obj); } }
-
UI框架设计
- 动态加载:通过AssetBundle按需加载UI预制体
- 状态机管理:使用有限状态机(FSM)处理UI交互逻辑
public class UIManager : MonoBehaviour { private Dictionary<string, GameObject> _uiCache = new Dictionary<string, GameObject>(); public void ShowUI(string uiName) { if (!_uiCache.ContainsKey(uiName)) { GameObject prefab = LoadUIPrefab(uiName); _uiCache[uiName] = Instantiate(prefab); } _uiCache[uiName].SetActive(true); } private GameObject LoadUIPrefab(string uiName) { // 从AssetBundle加载预制体 return null; } }
三、性能优化策略
- 渲染优化
- Draw Call优化:使用图集合并相似材质的物体
- LOD技术:根据距离动态切换模型细节层级
- 物理与AI优化
- 固定时间步长更新:避免帧率波动导致的物理计算错误
- NavMeshAgent:实现AI路径规划与避障
public class PhysicsOptimizer : MonoBehaviour { private const int FIXEDUPDATE_INTERVAL = 16; // 60FPS时每0.266秒执行一次 private float _accumulator = 0f; void FixedUpdate() { _accumulator += Time.fixedDeltaTime; while (_accumulator >= FIXEDUPDATE_INTERVAL) { UpdatePhysics(); _accumulator -= FIXEDUPDATE_INTERVAL; } } private void UpdatePhysics() { // 物理引擎更新逻辑 } }
四、实战案例:MMO客户端架构
- 架构概览
[客户端] <--(Protobuf)--> [网关服务器] <--(内部协议)--> [逻辑服务器] <--(数据库)--> [存储系统]
- 关键技术点
- 状态同步:采用「帧同步+状态快照」混合方案,关键代码:
public class StateSynchronizer { private Queue<GameState> _stateQueue = new Queue<GameState>(); private Dictionary<ulong, PlayerState> _playerStates = new Dictionary<ulong, PlayerState>(); public void ApplyState(GameState state) { _stateQueue.Enqueue(state); while (_stateQueue.Count > 0) { var prevState = _stateQueue.Dequeue(); foreach (var playerState in prevState.Players) { if (!_playerStates.ContainsKey(playerState.Id)) { _playerStates[playerState.Id] = playerState; } else { _playerStates[playerState.Id].Update(playerState); } } } } }
- 热更新机制:通过LuaBridge实现脚本热更,核心流程:
- 下载AB包替换旧资源
- 通过Lua重新加载模块
五、架构演进与挑战
- 从单体到微服务
- 早期版本:所有功能集成在单个Unity项目中
- 迭代方向:按功能拆分为独立模块(如登录模块、战斗模块)
- 跨平台兼容性
- 使用IL2CPP编译为原生代码,支持iOS与Android
- 针对移动端优化:限制Draw Call数量、减少透明材质使用
参考资料
- 网络通信实现:
- 资源管理与热更新:
- 性能优化实践:
- 架构设计方法论:
- 实战案例参考: