客户端随着项目推进,可能增加到`几十甚至上百种`从服务端发送给客户端的消息。每一种在前端做一个消息Handler进行消息处理即可,但是如何把消息内容分发给各界面或功能模块呢?
散乱的写,都通过GameManager中转,这样不但耦合的厉害,而且接收消息多的界面或模块,代码会很多很杂乱。
用单例构建Reciver,通过委托分发事件
Fantasy MMO 最佳实践项目中的泛型单例
Unity中构建Sender脚本,方便向服务器发消息
在具体接收消息的界面或模块注册事件即可。
这样不用多了GameMananger中转再插一杠子,不用再思考中转处有什么逻辑与参数需要修改,只关注遇到什么问题,到什么界面与模块去解决。
Reciver与Sender做分部类,这样只挂一个Sender脚本就行了。
\Unity\Assets\Scripts\Network\Sender\Reciver.cs
using UnityEngine;
using System.Collections.Generic;
using Fantasy;
public partial class Sender : SingletonMono<Sender>
{
// 使用字典存储不同消息类型对应的处理方法
private Dictionary<ReciveType, MessageHandler> messageHandlers = new Dictionary<ReciveType, MessageHandler>();
private Dictionary<ReciveType, AddressableHandler> addressableHandlers = new Dictionary<ReciveType, AddressableHandler>();
public void Recive(ReciveType reciveType,IMessage message){
// 检查是否有注册过该消息类型的处理方法
if (messageHandlers.TryGetValue(reciveType, out var handler))
{
// 调用处理方法
handler.Invoke(message);
}
}
public void Recive(ReciveType reciveType,IAddressableRouteMessage message){
// 检查是否有注册过该消息类型的处理方法
if (addressableHandlers.TryGetValue(reciveType, out var handler))
{
// 调用处理方法
handler.Invoke(message);
}
}
// 注册消息处理方法
public void RegisterMessageHandler(ReciveType reciveType, MessageHandler handler)
{
if (messageHandlers.ContainsKey(reciveType))
messageHandlers[reciveType] = handler;
else
messageHandlers.Add(reciveType, handler);
}
public void RegisterMessageHandler(ReciveType reciveType, AddressableHandler handler)
{
if (addressableHandlers.ContainsKey(reciveType))
addressableHandlers[reciveType] = handler;
else
addressableHandlers.Add(reciveType, handler);
}
}
在功能模块注册事件
\Unity\Assets\Scripts\MMORPG\Game\Unit\PlayerUnits.cs
using UnityEngine;
using Fantasy;
using BestGame;
public class PlayerUnits : BaseUnits
{
protected override void Awake() {
base.Awake();
unitViewer.isMulti = true;
Sender.Ins.RegisterMessageHandler(ReciveType.CreateUnits,AddUnit2Scene);
}
// 添加角色unit到场景
public void AddUnit2Scene(IAddressableRouteMessage message)
{
var messageInfo = message as M2C_NoticeUnitAdd;
foreach (var unit in messageInfo.RoleInfos)
{
var temp = new GameObject();
temp.transform.position = MessageInfoHelper.Vector3(unit.LastMoveInfo);
temp.transform.rotation = MessageInfoHelper.Quaternion(unit.LastMoveInfo);
// 添加unitViewer动态内容
var go = unitViewer.ViewUnit(unit.ClassName,unit.RoleId.ToString(),temp.transform);
// CameraMMO激活,设置目标为本地玩家
if(GameManager.Ins.RoleId == unit.RoleId)
UIFacade.Ins.SetMMOCamera(go.transform);
GameObject.Destroy(temp);
}
}
public override void ExitScene()
{
base.ExitScene();
// 移除unitViewer动态内容
unitViewer.ClearPreview();
}
}
消息Handler中如何调用
\Assets\Scripts\Network\Handler\M2C_UnitHelperHandler.cs
using UnityEngine;
using Fantasy;
namespace BestGame
{
public class M2C_CreateUnitsHandler : Message<M2C_NoticeUnitAdd>
{
protected override async FTask Run(Session session, M2C_NoticeUnitAdd message)
{
Sender.Ins.Recive(ReciveType.CreateUnits,message);
await FTask.CompletedTask;
}
}
}