目录
☝🤓前言
☝🤓一、实现思路
☝🤓二、实现
🤠2.1 定义红点组件
🤠2.2 定义Proto消息体
🤠2.3 RedPointComponentSystem
☝🤓难点
☝🤓前言
当我们闲来无事时打开农药想消磨一下时间的时候,进入游戏首先会有各种活动弹窗还有一大堆活动要领的物品;比如下面这张(网上找的网图)
这些要领的活动物品会通过红点来提示玩家领取,强迫症玩家进游戏会把所有红点都点完在开局(Doge.jpg)领完红点会消失。
现在策划把红点系统的任务交给我来做,我是怎么完成这个红点系统的呢?
☝🤓一、实现思路
先说一下思路:
- 当我们打开游戏时红点会有一个初始化 —— 我们要在玩家刚进游戏时把所有会出现红点的状态数据传给前端进行初始化,这样后边游戏过程中我们只传状态发生变化的就好了。
- 红点的状态是时刻都在变的,比如进游戏有红点提示你领取物品,领完红点会消失;完成对局达成某一项任务红点又会出现提示玩家领取物品。
- 红点状态只在玩家玩游戏时进行判断,不储存到数据库中。
初始化问题我们要和前端协商,由前端定义枚举类型,比如战令奖励红点我们商定为 —— type=1001,系统邮件商定为 —— type=2001,玩家邮件商定为 —— type=2002。
服务端选择用定时任务来监测红点时刻都会变化的这一特点。
- 玩家进入游戏红点系统的枚举就会进行初始化。
- 当服务端检测有红点状态发生变化时,由定时任务来筛选出变化的红点状态进行传递给前端展示。
☝🤓二、实现
2.1 定义红点组件
红点组件挂载在Unit身上
字典类型Key存储前端定义的枚举type,Value存储红点状态:0 —— 红点熄灭,1 —— 红点亮起
当红点状态发生变化时消息Message负责主动给前端发送变化的红点状态
namespace ET.Server
{
[ComponentOf(typeof(Unit))]
public class RedPointComponent: Entity, IAwake, IDestroy, IDeserialize, ITransfer, IUnitCache
{
[BsonIgnore]
public long Timer;
//红点状态
[BsonIgnore]
public Dictionary<int, int> RedPointStatus = new Dictionary<int, int>();
[BsonIgnore]
public M2C_RedPointNotice Message = new M2C_RedPointNotice();
}
}
2.2 定义Proto消息体
主动发消息通知前端变化了的红点状态:
message M2C_RedPointNotice //IActorMessage
{
map<int32,int32> RedPointStatus = 1;
}
2.3 RedPointComponentSystem
namespace ET.Server
{
public class RedPointComponentAwakeSystem: AwakeSystem<RedPointComponent>
{
protected override void Awake(RedPointComponent self)
{
self.Timer = TimerComponent.Instance.NewRepeatedTimer(10000, TimerInvokeType.RedPointUpadte, self);
}
}
public class RedPointComponentDestorySystem: DestroySystem<RedPointComponent>
{
protected override void Destroy(RedPointComponent self)
{
TimerComponent.Instance.Remove(ref self.Timer);
}
}
//定时任务每10秒执行一次
[Invoke(TimerInvokeType.RedPointUpadte)]
public class TimingSaveComponentTimer : ATimer<RedPointComponent>
{
protected override void Run(RedPointComponent self)
{
try
{
if ( self.IsDisposed || self.Parent == null )
{
return;
}
if ( self.DomainScene() == null)
{
return;
}
self?.RedPointUpdate();
}
catch (Exception e)
{
Log.Error(e.ToString());
}
}
}
[FriendOf(typeof (RedPointComponent))]
[FriendOf(typeof (Unit))]
[FriendOf(typeof (EmailComponent))]
public static class RedPointComponentSystem
{
/// <summary>
/// 初始化活动红点状态,在进游戏接口中调用执行
/// </summary>
/// <returns></returns>
public static async ETTask GetAllRedPointStatus(this RedPointComponent self)
{
Unit unit = self.GetParent<Unit>();
//......有红点的所有活动都添加到字典中来进行初始化
//拿邮件举例
EmailComponent emailComponent = unit.GetComponent<EmailComponent>();
emailComponent.EmailRedPoint();
foreach (var item in emailComponent.RedPointStatus)
{
//将邮件红点的状态加入字典中
self.RedPointStatus.Add(item.Key,item.Value);
}
}
/// <summary>
/// 更新红点状态,由定时任务执行,也可以在完成支付、完成对局、退出房间等重要节点也执行一次
/// </summary>
/// <param name="self"></param>
public static async ETTask RedPointUpdate(this RedPointComponent self)
{
self.RedPointStatus.Clear();
Unit unit = self.GetParent<Unit>();
//......有红点的所有活动都进行判断变化与否
//依然拿邮件举例
EmailComponent emailComponent = unit.GetComponent<EmailComponent>();
emailComponent.GetEmailManagerNews().Coroutine();
// != null说明邮件红点发生变化,需要通知前端
if (emailComponent.EmailRedPoint(1) != null)
{
//只有当红点变化时才会添加到字典
self.RedPointStatus.Add(item.Key,item.Value);
}
if(self.RedPointStatus.Count == 0) return;
//服务器主动发消息通知前端红点状态的变化
UnitGateComponent unitGateComponent = unit.GetComponent<UnitGateComponent>();
self.Message.FishRedPointStatus = self.RedPointStatus;
ActorMessageSenderComponent.Instance.Send(unitGateComponent.GateSessionActorId, self.Message);
}
}
}
这样前端处理消息时只需遍历一次 RedPointStatus ,然后根据定义的枚举对应具体活动控制红点的显示与消失就可以了。
☝🤓总结
其实红点系统的实现并不难,难的是众多活动红点的判断是比较繁琐的,要具体到每个活动中去判断在集中到红点系统中去,是个体力活🤯。
补充:(小编目前也只做了这14个中的一个红点系统而已,红点系统前端也很麻烦,和我对接的前端好像用到了树结构来实现)