前几天写了《开源分享 Unity3d客户端与C#分布式服务端游戏框架》,受到很多人关注,QQ群几天就加了80多个人。开源这个框架的主要目的也是分享自己设计ET的一些想法,所以我准备写一系列的文章,介绍下自己的思路跟设计,每篇一个主题,这次介绍的是组件设计。

在代码复用和组织数据方面,面向对象可能是大家第一反应。面向对象三大特性继承,封装,多态,在一定程度上能解决不少代码复用,数据复用的问题。不过面向对象不是万能的,它也有极大的缺陷:

1. 数据结构耦合性极强

一旦父类中增加或删除某个字段,可能要影响到所有子类,影响到所有子类相关的逻辑。这显得非常不灵活,在一套复杂的继承体系中,往父类中改变字段会变得越来越麻烦,比方说ABC是D的子类,某天发现需要增加一个AB都有的数据,但是C没有,那么这个数据肯定不好放到父类中,只能将AB抽象出来一个父类E,E继承于D,AB共有的字段加到E中,一旦继承结构发生了变化,可能接口也要改变,比方说之前有个接口传入参数类型是E,当AB不再需要共用的那个字段,那么需要调整继承关系,让AB重新继承D,那么这个接口的传入参数类型需要改成D,其中的逻辑代码很可能也要发生调整。更可怕的是游戏逻辑变化非常复杂,非常频繁,可能今天加了个字段,明天又删掉了,假如每次都要去调整继承结构,这简直就是噩梦。继承结构面对频繁的数据结构调整感觉很无力。

2. 难以热插拔

继承结构无法运行时增加删除字段,比如玩家Player平常是走路,使用坐骑后就骑马。问题是坐骑的相关信息就需要一直挂在Player对象上面。这就显得很不灵活,我不骑马的时候内存中为啥要有马的数据?接口也有同样的问题,一个类实现了一个接口,那么这个接口就永远粘在了这个类身上,你想甩掉她都不行,还是以骑马为例,玩家Player可以进行骑行,那么可能继承一个骑行的接口,问题是,当我这个Player从坐骑上下来时,玩家Player身上还是有骑行的接口,根本没法动态删掉这个接口!可能例子举得不是很对,但是道理表述的应该很清楚了。

使用面向对象可能导致灾难性后果,游戏开发中有新人有老人,有技术好的,有技术差的。人都是喜欢偷懒的,当你发现调整继承关系麻烦的时候,有可能AB中增加一个字段为了省事直接就放到父类D中去了。导致C莫名奇妙的多了一个无用的字段。关键还没法发现,最后导致父类D越来越大,到最后有可能干脆就不用ABC了,直接让所有对象都变成D,方便嘛!是的,很多游戏就是这么干的,开发到最后根本就不管继承关系了,因为想管也管不了了。

面向对象在面对复杂的游戏逻辑时很无力,所以很多游戏开发者又倒退了回去,使用面向过程进行开发游戏,面向过程,简单粗暴,不考虑复杂的继承,不考虑抽象,不考虑多态,是开发届的freestyle,挽起袖子就开撸,但同时,代码逻辑的复用性,数据的复用性也大大降低。面向过程也不是一种好的游戏开发模式。

组件模式很好的解决了面向对象以及面向过程的种种缺陷,在游戏客户端中使用非常广泛,Unity3d,虚幻4,等等都使用了组件模式。组件模式的特点:

1.高度模块化,一个组件就是一份数据加一段逻辑

2.组件可热插拔,需要就加上,不需要就删除

3.类型之间依赖极少,任何类型增加或删除组件不会影响到其它类型。

但是目前只有极少有服务端使用了组件的设计,守望先锋服务端应该是使用了组件的设计,守望先锋的开发人员称之为ECS架构,其实就是组件模式的一个变种,E就是Entity,C就是Component,S是System,其实就是将组件Component的逻辑与数据剥离,逻辑部分叫System,话题扯远了,还是回到ET框架来把。

ET框架使用了组件的设计。一切都是Entity和Component,任何类继承于Entity都可以挂载组件,例如玩家类:

public sealed class Player : Entity
{
public string Account { get; private set; }
public long UnitId { get; set; } public void Awake(string account)
{
this.Account = account;
} public override void Dispose()
{
if (this.Id == 0)
{
return;
}
base.Dispose();
}
}

给玩家对象挂载个移动组件MoveComponent,这样玩家就可以移动了,给玩家挂上一个背包组件,玩家就可以管理物品了,给玩家挂上技能组件,那么玩家就可以施放技能了,加上Buff组件就可以管理buff了。

player.AddComponent<MoveComponent>();
player.AddComponent<ItemsComponent>();
player.AddComponent<SpellComponent>();
player.AddComponent<BuffComponent>();

组件是高度可以复用的,比如一个NPC,他也可以移动,给NPC也挂上MoveComponent就行了,有的NPC也可以施放技能,那么给它挂上SpellComponent,NPC不需要背包,那么就不用挂ItemsComponent了

ET框架模块全部做成了组件的形式,一个进程也是由不同的组件拼接而成。比方说Loginserver需要对外连接也需要与服务器内部进行连接,那么login server挂上

// 内网网络组件NetInnerComponent,处理对内网连接
Game.Scene.AddComponent<NetInnerComponent, string, int>(innerConfig.Host, innerConfig.Port);
// 外网网络组件NetOuterComponent,处理与客户端连接
Game.Scene.AddComponent<NetOuterComponent, string, int>(outerConfig.Host, outerConfig.Port);

比如battle server就不需要对外网连接(外网消息由gateserver转发),那么很自然的只需要挂载一个内网组件即可。

类似Unity3d的组件,ET框架也提供了组件事件,例如Awake,Start,Update等。要给一个Component或者Entity加上这些事件,必须写一个辅助类。比如NetInnerComponent组件需要Awake跟Update方法,那么添加一个这样的类即可:

[ObjectEvent]
public class NetInnerComponentEvent : ObjectEvent<NetInnerComponent>, IAwake, IUpdate
{
public void Awake()
{
this.Get().Awake();
} public void Update()
{
this.Get().Update();
}
}

这样,NetInnerComponent在AddComponent之后会调用其Awake方法,并且每帧调用Update方法。

ET没有像Unity使用反射去实现这种功能,因为反射性能比较差,而且这样实现的好处是这个类可以放到热更dll中,这样组件的Awake Start,Update方法以及其它方法都可以放到热更层中。将Entity和Component做成没有方法的类,方法都放到热更层,方便热更修复逻辑bug。

组件式开发最大的好处就是不管菜鸟还是高手,开发一个功能都能很快的知道怎么组织数据怎么组织逻辑。可以完全放弃面向对象。使用面向对象开发最头疼的就是我该继承哪个类呢?之前做过最恐怖的就是虚幻三,虚幻三的继承结构非常多层,完全不知道自己需要从哪里开始继承。最后可能导致一个非常小的功能,继承了一个及其巨大的类,这在虚幻三开发中屡见不鲜。所以虚幻4改用了组件模式。组件模式的模块隔离性非常好,技术菜鸟某个组件写得非常差,也不会影响到其它模块,大不了重写这个组件就好了。

正是因为ET使用了可拆卸的组件模式,ET可以将所有服务器组件都装到同一个进程上,那么这一个进程就可以当作一组分布式服务器使用。从此用vs调试分布式服务器成为了可能。正因为这样,平常开发只使用一个进程,发布的时候发布成多个进程就行了。说实在的,不是吹牛,这是一个伟大的发明,这一发明解决了分布式游戏服务器开发中的大大大难题,极大的提高了开发效率。

代码地址:https://github.com/egametang/Egametang

QQ群:474643097

Unity3d&C#分布式游戏服务器ET框架介绍-组件式设计的更多相关文章

  1. Pomelo分布式游戏服务器框架

    Pomelo介绍&入门 目录 前言&介绍 安装Pomelo 创建项目并启动 创建项目 项目结构说明 启动 测试连接 聊天服务器 新建gate和chat服务器 配置master.json ...

  2. 游戏服务器h2engine架构优化和跨平台设计

    H2engine的GitHub星星不知不觉已经破百了,也没有特意推广过,但是慢慢的关注的人越来越多.因为事情多,好久没有写东西了,前一段时间有了一些想法,把h2engine又更新了一下,感觉h2eng ...

  3. GoWorld – 用Golang写一个分布式可扩展、可热更的游戏服务器

    GoWorld代码:https://github.com/xiaonanln/goworld Golang具有运行效率高.内存安全等优良特性,因此是非常适合用来进行服务器开发.使用Golang开发游戏 ...

  4. erlang 游戏服务器开发

    http://blog.csdn.net/slmeng2002/article/details/5532771 最近关注erlang游戏服务器开发  erlang大牛写的游戏服务器值得参考 介绍本文以 ...

  5. 深入浅出node.js游戏服务器开发1——基础架构与框架介绍

    2013年04月19日 14:09:37 MJiao 阅读数:4614   深入浅出node.js游戏服务器开发1——基础架构与框架介绍   游戏服务器概述 没开发过游戏的人会觉得游戏服务器是很神秘的 ...

  6. unity3d + photon + grpc + nodejs + postgis/postgresql 游戏服务器设计

    unity3d + photon + grpc + nodejs + postgis/postgresql 游戏服务器设计 最近做玩票性质的游戏项目,客户端技术是 unity3d 和 android. ...

  7. Scut游戏服务器免费开源框架-3

    Scut游戏服务器免费开源框架--快速开发(3) Scut快速开发(3) 1        开发环境 需要安装的软件 a)        消息队列 b)        数据库,Sql2005以上版本 ...

  8. 分布式服务框架介绍:最成熟的开源NIO框架Netty

    尽管JDK提供了丰富的NIO类库,网上也有很多NIO学习例程,但是直接使用Java NIO类库想要开发出稳定可靠的通信框架却并非易事,原因如下: 1)NIO的类库和API繁杂,使用麻烦,你需要熟练掌握 ...

  9. Leaf - 一个由 Go 语言编写的开发效率和执行效率并重的开源游戏服务器框架

    转自:https://toutiao.io/posts/0l7l7n/preview Leaf 游戏服务器框架简介 Leaf 是一个由 Go 语言(golang)编写的开发效率和执行效率并重的开源游戏 ...

随机推荐

  1. RSA简介(一)——数论原理

    RSA是最常用的非对称加密算法. 所谓非对称加密,就是说有两个密钥,一个密钥加密只可以用另外一个密钥解密,一般一个作为公钥,公开给所有人用来加密用,而另一个用来解密其他拥有公钥的加密结果,叫做私钥.另 ...

  2. [补档]vijos1883 月光的魔法

    vijos1883 月光的魔法 题目 传送门:https://www.vijos.org/p/1883 背景 影几欺哄了众生了 天以外-- 月儿何曾圆缺   描述 有些东西就如同月光的魔法一般. Lu ...

  3. 双向循环链表(C语言描述)(三)

    代码清单 // linkedlist.h #ifndef __LINKEDLIST_H__ #define __LINKEDLIST_H__ #include <assert.h> #in ...

  4. centos7安装mysql(yum)

    centos7安装mysql(yum) ----安装环境----依赖安装----检查mysql是否已安装----安装----验证是否添加成功----选择要启用的mysql版本----通过Yum安装my ...

  5. Linux的nginx环境的vue 部署

    1.使用WebStrom编程好的vue 进入到Terminal运行npm run build           2.使用WinSCP进入到nginx 目录配置文件下面,找到nginx.conf文件: ...

  6. Java 脚本引擎

    脚本引擎,就是一个编程语言的解释器,它的功能是解释执行用户的程序文本,将它译成计算机能执行的机器代码,完成一系列的功能. Java脚本引擎简单地说就是指Java提供的一组兼容操作各种脚本语言的的API ...

  7. 第一天的php体验

    第一次了解php.以前对于程序猿的认知是很片面的.因为没有了解过.今天通过一天的了解交流,有了新的认知.对于这个主要应用于前端的语言还是很有兴趣的.毕竟可以亲眼看到自己做出来的网页,心里的成就感肯定满 ...

  8. 一个项目经理对主流项目管理工具的对比:禅道VS华为软件开发云

    禅道与软件开发云对比分析报告 1. 产品介绍 禅道是易软天创出品的一款项目管理软件,集产品管理.项目管理.测试管理.文档管理.组织管理于一体,覆盖了项目管理和测试管理的核心流程. 华为软件开发云 (D ...

  9. cvpr2017:RSVP

    1.简单介绍 这个框架主要应用场景是更智能的视频监控.主要贡献是利用long term和short term的时序信息来预测当前帧.框架分割的主要对象是人,将图像中的人物分割成头发.脸.大衣.裤子.包 ...

  10. canvas图形处理和进阶用法

    前面的话 上一篇博客介绍了canvas基础用法,本文将更进一步,介绍canvas的图形处理和进阶用法 图形变换 图形变换是指用数学方法调整所绘形状的物理属性,其实质是坐标变形.所有的变换都依赖于后台的 ...