ET是一个游戏框架,用的编程语言是C#,游戏引擎是Unity,框架作者:熊猫 ET社区
在游戏中我们通常都会看到有邮件系统,邮件系统的作用有给玩家通知、发放奖励等
下面小编使用ET框架带大家看一下邮件系统的一种实现方式。
一、实现思路
小编所理解的ECS编程是这样的:组件实体组件实体之间组装(类似于拼积木)
按照这个想法我们要实现一个邮件系统这就需要邮件的实体和组件了。
玩家的实体是Unit,邮件组件作为玩家的一部分挂到Unit上,那邮件的收发操作是怎么实现的呢?
看美剧一般小镇上每户人家家门口都会有一个小邮箱,邮递员会把邮件放到这个小邮箱里。家里人发现有邮件来了就到这个小邮箱查看并拿回家给具体的收件人。
实现邮件系统思路和拿邮件是类似的,这里我们就需要一个邮件管理组件EmailManagerComponent来作为小邮箱。
1、邮件管理组件EmailManagerComponent 和玩家组件处在同一层级(家门口的小邮箱可以存放不同人的邮件)
2、邮件组件EmailComponent 是玩家组件的子组件(邮件要给具体的收件人)
3、当系统或者其他玩家发送邮件时会先保存到邮件管理组件EmailManagerComponent中(邮递员把邮件放入小邮箱)
4、当玩家点击邮件按钮时会通过自身的Id标识到邮件管理组件去找自己的邮件
5、如果发现有自己的邮件则保存到玩家自己身上(邮件给到具体收件人)
6、保存好后邮件管理组件会将移除玩家已领取的邮件。(释放邮件管理组件资源)
7、发送邮件(收件人的Id作为唯一标识暂时保存到邮件管理组件中等待收件人领取)
二、编码
2.1 EmailInfo
邮件一般会有发送时间、发件人、收件人、标题、内容等等(根据实际情况自己定义)。
那这个邮件实体我们命名为EmailInfo
namespace ET.Server
{
[ChildOf(typeof(EmailComponent))]
public class EmailInfo: Entity, IAwake,IDestroy
{
//奖励
public List<int> ItemId; //奖励物品Id列表
public List<long> ItemValue; //奖励物品数量列表
//邮件领取状态 0:未领取,1:已领取
public int Status;
//发件人
public string Sender;
//收件人
public string Receiver;
//发送时间
public int SenderTime;
//标题
public string Title;
//内容
public string Text;
//邮件删除状态:1 删除,0 未删除
public int DelteType = 0;
}
}
2.2 EmailComponent
定义好实体后我们来定义邮件组件EmailComponent 来作为 EmailInfo 的载体挂到玩家身上
namespace ET.Server
{
[ComponentOf(typeof(Unit))]
public class EmailComponent : Entity, IAwake, IDestroy, IDeserialize, ITransfer, IUnitCache
{
//邮件Id
public int EmailId = 1;
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<int, EmailInfo> Emails = new Dictionary<int, EmailInfo>();
}
}
2.3 EmailManagerComponent
邮件管理组件挂载到Scene上和玩家组件处于同一层级
namespace ET.Server
{
[ComponentOf(typeof(Scene))]
public class EmailManagerComponent : Entity,IAwake,IDestroy
{
public long Timer;
// 玩家接收新的邮件 字典Key存储玩家ID,Value采用List是一个玩家可能会收到多封邮件
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<long, List<EmailInfo>> EmailUnitInfos = new Dictionary<long, List<EmailInfo>>();
}
}
2.4 EmailComponentSystem
邮件组件所实现的动作:EmailComponentSystem
using System.Collections.Generic;
using System.Linq;
namespace ET.Server
{
public class EmailInfoComponentDestroySystem: DestroySystem<EmailComponent>
{
protected override void Destroy(EmailComponent self)
{
self.Emails.Clear();
}
}
[FriendOf(typeof(EmailComponent))]
[FriendOf(typeof(EmailInfo))]
public static class EmailComponentSystem
{
//Status奖励领取状态 0:未领取,1:已领取
public static List<EmailProto> GetEmailList(this EmailComponent self,int SystemType)
{
List<EmailProto> emailProtos = new List<EmailProto>();
foreach (var item in self.Emails)
{
//DelteType == 0 未删除
if (item.Value.DelteType == 0)
{
int todayKey = (int)TimeHelper.ClientNowSeconds();
if (todayKey >= item.Value.StarAt && todayKey <= item.Value.EndAt)
{
emailProtos.Add(
new EmailProto()
{
ItemId = item.Value.ItemId,
ItemValue = item.Value.ItemValue,
Status = item.Value.Status,
Sender = item.Value.Sender,
Receiver = item.Value.Receiver,
SenderTime = (int)item.Value.StarAt,
Title = item.Value.Title,
Text = item.Value.Text,
EmailId = item.Key,
});
}
}
}
List<EmailProto> lists = emailProtos.OrderByDescending(e => e.SenderTime).ToList();
return lists;
}
//获取新邮件
public static void GetNewEmail(this EmailComponent self,List<EmailInfo> emailInfos)
{
if (emailInfos ==null || emailInfos.Count==0)
{
return;
}
for (int i = 0; i < emailInfos.Count; i++)
{
self.Emails.Add(self.EmailId+=1,new EmailInfo
{
ItemId = emailInfos[i].ItemId,
ItemValue = emailInfos[i].ItemValue,
Status = emailInfos[i].Status,
Sender = emailInfos[i].Sender,
Receiver = emailInfos[i].Receiver,
SenderTime = emailInfos[i].SenderTime,
Title = emailInfos[i].Title,
Text = emailInfos[i].Text,
StarAt = emailInfos[i].StarAt,
EndAt = emailInfos[i].EndAt,
SystemType = emailInfos[i].SystemType,
});
}
}
//删除邮件
public static string DeleteEmail(this EmailComponent self, int EmailId)
{
string resultMsg = "该邮件不存在";
if (self.Emails.ContainsKey(EmailId) && self.Emails[EmailId].Status == 1)
{
//self.Emails.Remove(EmailId);
self.Emails[EmailId].DelteType = 1;
resultMsg = "删除成功";
}
return resultMsg ;
}
}
}
2.5 EmailManagerComponentSystem
邮件管理组件所实现的动作:EmailManagerComponentSystem
namespace ET.Server
{
public class EmailManagerComponentDestroySystem: DestroySystem<EmailManagerComponent>
{
protected override void Destroy(EmailManagerComponent self)
{
TimerComponent.Instance.Remove(ref self.Timer);
}
}
public class EmailManagerComponentAwakeSystem: AwakeSystem<EmailManagerComponent>
{
protected override void Awake(EmailManagerComponent self)
{
self.Timer = TimerComponent.Instance.NewRepeatedTimer(10000, TimerInvokeType.EmailManagerUpdate, self);
}
}
//定时器 每隔10秒钟保存一次邮件信息
[Invoke(TimerInvokeType.EmailManagerUpdate)]
public class EmailManagerComponentTimer : ATimer<EmailManagerComponent>
{
protected override void Run(EmailManagerComponent self)
{
try
{
if ( self.IsDisposed || self.Parent == null )
{
return;
}
if ( self.DomainScene() == null || self.DomainScene().Name != "Map1")
{
return;
}
self?.SaveEmailManagerComponent();
}
catch (Exception e)
{
Log.Error(e.ToString());
}
}
}
[FriendOf(typeof(EmailManagerComponent))]
[FriendOf(typeof(DBManagerComponent))]
[FriendOf(typeof(EmailSystemInfo))]
[FriendOf(typeof(EmailInfo))]
public static class EmailManagerComponentSystem
{
//系统启动时从数据库加载邮件管理组件信息
public static async ETTask LoadEmailInfo(this EmailManagerComponent self)
{
var EmailManagerList = await DBManagerComponent.Instance.GetZoneDB(self.DomainZone()).Query<EmailManagerComponent>(d => true,collection:"EmailManagerComponent");
}
//玩家之间发送邮件
public static void SendNewEmail(this EmailManagerComponent self,long receiveId,EmailProto emailProto)
{
//如果邮件中有附件奖励设置可领取状态
if (emailProto.ItemValue == null && emailProto.ItemId == null)
{
emailProto.Status = 1;
}
else
{
emailProto.Status = 0;
}
EmailInfo emailInfo = new EmailInfo
{
ItemId = emailProto.ItemId,
ItemValue = emailProto.ItemValue,
Status = emailProto.Status,
Sender = emailProto.Sender,
Receiver = emailProto.Receiver,
SenderTime = (int) (TimeHelper.ServerNow()/1000),
Title = emailProto.Title,
Text = emailProto.Text,
};
if (!self.EmailUnitInfos.ContainsKey(receiveId))
{
List<EmailInfo> list = new List<EmailInfo>();
list.Add(emailInfo);
self.EmailUnitInfos.Add(receiveId,list);
}
else
{
self.EmailUnitInfos[receiveId].Add(emailInfo);
}
}
//获取玩家收到的新邮件
public static List<EmailInfo> ReceiveNewEmail(this EmailManagerComponent self,long unitId)
{
List<EmailInfo> list = new List<EmailInfo>();
if (!self.EmailUnitInfos.ContainsKey(unitId))
{
self.EmailUnitInfos.Add(unitId,list);
}
else
{
//玩家接收了此邮件,接收状态改为已接收
for (int i = 0; i < self.EmailUnitInfos[unitId].Count; i++)
{
list.Add(self.EmailUnitInfos[unitId][i]);
}
self.EmailUnitInfos.Remove(unitId);
}
//根据时间戳进行排序
list.OrderByDescending(l => l.SenderTime).ToList();
return list;
}
//获取玩家所有状态的邮件(已接收的和未接收的)
public static List<EmailInfo> ReceiveAllEmail(this EmailManagerComponent self, long unitId)
{
List<EmailInfo> list = new List<EmailInfo>();
if (!self.EmailUnitInfos.ContainsKey(unitId))
{
self.EmailUnitInfos.Add(unitId,list);
return list;
}
for (int i = 0; i < self.EmailUnitInfos[unitId].Count; i++)
{
list.Add(self.EmailUnitInfos[unitId][i]);
}
//根据时间戳进行排序
list.OrderByDescending(l => l.SenderTime).ToList();
return list;
}
//保存
public static void SaveEmailManagerComponent(this EmailManagerComponent self)
{
Log.Debug("---------------------------开始保存邮件信息");
DBManagerComponent.Instance.GetZoneDB(self.DomainZone()).Save(self,"EmailManagerComponent").Coroutine();
}
}
}
邮件系统的实现思路之一是这样,还要根据具体业务逻辑实现具体动作并写接口去调用组件所实现的这些动作。有不对的地方欢迎大家提出来一起讨论,本篇先介绍到这里,拜拜┏(^0^)┛