• Unity客户端框架笔记二(组件实体开发模式的思考)转


    Unity的Entity-Component-System实现的非常漂亮,非常灵活。很多文章也对这种组件实体的开发模式倍加推崇。因为它契合这么一条规则:优先使用组合而不是继承。

            但是实际开发过程中,限制于我的个人能力,想实现一个同样漂亮的基于组件的MMO框架是非常困难的一件事情。

            这篇文章是个人开发过程中的一些思考,实际上,所谓漂亮的框架是因人而异的,并且不一定是必须的,能够用自己熟悉的方式快速的完成项目的开发就足够了。只要开发过程不会感觉别扭,代码也不会把自己或其他人恶心到,策划修改需求的时候不会骂娘,后期不会出现各种难以调试的Bug,那么就是漂亮的框架。

            从理论上说,所谓ECS就是一个Entity,持有一组Component,然后通过一系列的System来维护调度组件之间的逻辑。组件之间是相对独立的,最理想的方式是通过Event来进行消息传递。从这点来说Unity已经实现的非常漂亮了,GameObject可以绑定任意的MonoBehaviour,脚本组件有统一的入口,并且可以通过SendMessage发送消息,也可以通过GetComponent来获取一个具体的组件,直接调用其函数。

            我反编译了一大堆线上手游的源代码,几乎没有完全依赖组件模式进行开发的,更多的还是依赖一套继承体系来完成。这里我自己的感觉就是偏底层或者逻辑独立性非常强的功能适合组件模式,而逻辑交互非常复杂的情况,过分依赖组件模式想要达到“理想”的效果,反而会适得其反。

            比如,理论上ECS中,Entity应该像GameObject一样,只维护组件,不包含任何其他逻辑或者代码,所有需要调度的逻辑都应该放在System中,它会关注它负责的Component。 然而,在我看来,这样反而切割了逻辑,在实际项目中,要么很难做到这样的分离,要么会让代码变得很散,难以维护。当查Bug的时候,不会因为这样的代码分离变得轻松,反而会因为结构的散乱造成无从着手的情况。

            再说组件之间的消息通信,当游戏全部以组件方式来实现,并且组件之间通过消息来完成调用或者参数传递。这样的代码很难写,并且很难维护。事件从哪里抛出的,谁应该接受这个事件,持有哪些参数,这些都很不直观。虽然达到了灵活的效果,但是副作用也很明显,代码中充斥着各种各样的Event,很难通过简单的查看、跟踪、调试理清楚游戏的脉络。

           《Domination》是这样实现的,一个EntityController,里面包含全部的组件,并且提供对应的接口。它可以通过对应的配置文件决定创建哪个组件。而外部只维护一个EntityController,无论是Soldier还是Building,它都是一个Entity,只不过一个挂接的是SoldierAttackComponent,一个挂接的是BuildingUpgradeComponent,从而产生不同的行为。 这种实现方式给我一定的启发,因为它某种程度上说是符合ECS的。但是不得不说这种实现方式也很奇葩,EntityController非常庞大,虽然它没有维护具体的逻辑,但是单单是维护Component的接口就让它的代码达到几千行,更不要说它概念上的庞大了。

            《永恒战士3》的实现相对正统,是现阶段我可以接受的组件模式。不过严格说来这已经不是组件模式,而是组合取代继承的一种实现方式。它有一个ActionController,里面持有各种各样的Agent,如AIAgent  AttackAgent  MoveAgent等等,外部主要与ActionController进行交互,而内部则通过这些Agent分散代码和功能。

            Unity官方出的游戏《大天使》在我看来非常的Low。宣传视频很酷,但是实际游戏玩起来很渣,无论是画面表现,还是游戏可玩性。不得不说,专业做游戏的和专业做引擎的确实不是一个工种。就其代码来说,它作为Unity官方出品的游戏,竟然没有体现Unity最先进的生产力,这实在是Low爆了。它的寻路是A* Path Finding Pro,界面是NGUI,动画是老的动画系统Animation,代码组织上强烈依赖接口设计,一个Actor继承自IBuffable  IHealthable  ITakeDamage等等接口,很正统,但是也没有什么亮点。

           一些日韩排行榜霸榜的游戏,如《白猫》《钢铁骑士团》,其实代码结构一点也不漂亮,一个StageObj有几千行。从这点来说过分关注结构反而是没有意义的,那么多畅销游戏,其实实现的一点儿也不灵活。自己习惯,好用,就足够了。

            其他还有很多游戏,不过基本上大同小异。除去一些奇葩的实现外,基本上都是通过继承体系完成基础的对象抽象,然后通过组件将对象中比较大或者独立的功能抽离出来。如状态机组件、AI组件、动画组件、角色属性组件等等。

            另外,有一点是非常统一的,就是有限状态机的使用,基本上所有的游戏都是通过FSM来完成角色的状态流转的,ARPG尤其如此。少部分的游戏的AI部分可能用到行为树。几乎没有见过只通过行为树,而不依赖状态机控制角色的。在我想来,行为树每次都要进行整棵树的遍历,无论是从设计上说,还是效率上说都不适合游戏角色的行为描述。而行为树所擅长的AI方面,一般简单的游戏通过状态机来维护就足够了。

  • 相关阅读:
    21、Java并发性和多线程-Java中的锁
    20、Java并发性和多线程-Slipped Conditions
    19、Java并发性和多线程-嵌套管程锁死
    Java 架构师眼中的 HTTP 协议
    MonolithFirst
    【SpringMVC】从Fastjson迁移到Jackson,以及对技术选型的反思
    SpringMVC接口测试异常:Can not deserialize instance of int out of START_OBJECT token
    请不要盲目的进行横向扩展,优先考虑对单台服务器的性能优化,只有单台服务器的性能达到最优化之后,集群才会被最大的发挥作用
    Android Fragment中调用getActivity为null的问题
    Android 那些年,处理getActivity()为null的日子
  • 原文地址:https://www.cnblogs.com/bambomtan/p/5021649.html
Copyright © 2020-2023  润新知