#Unity中最重要的一个概念就是组件,在Unity中--万物皆组件
在传统的设计中,我们一般会使用“派生”来描述对象之间的关系。子类通过派生父类,来获得父类的功能。在设计游戏对象时,会根据游戏本身的需要而为游戏对象添加各种功能支持,比如渲染,碰撞,刚体,粒子系统等等。这些通用功能为了能够为各种派生类提供服务,都必须实现到基类中。这样就导致了游戏对象基类变得非常庞大臃肿,即难使用,又难维护。
OOP的继承思想
上图1的整个关系变成了
- Player is a A
- Player is a B
- Player is a C
举个实际的例子:一个静态的敌人,并不能够很好地通过继承实现出来。
#那么到底什么是“基于组件”的对象模型?它又能够解决什么问题?
”基于组件“的对象模型就是把所有需要提供给游戏对象的基础功能都独立成单独的组件模块(Component),一个具体的游戏对象可以将它需要的功能模块组合到一起使用。所有”功能“不再是父类中的接口,而变成子对象实例,为游戏对象提供服务。这样既保证了功能代码的可重用性,又增加了整个对象体系的模块化和灵活度。
OOP的组合思想
相比图1,图2的关系更加合理
Player have a A
Player have a B
Player have a C
还是同样的案例,用组合的思想来实现(如下图),相比继承的方式,更加灵活,耦合度也更低
#组件模型在UNITY中是如何运用的
另外,在Unity中,GameObject除了作为Component的容器之外,基本上没有其他功能。所有需要的功能都要通过组合Component来实现。脚本本身也是Component,用来在GameObject上通过控制其他Component来实现自定义的功能。虽然这些Component在物理上是完全并列的关系,但是他们之间还是会有一定的层次关系的。在设计一个游戏对象的具体功能时,组件一般会被分为三个层次。
-
引擎的基础组件
Unity本身提供的各种内部功能组件。比如渲染组件,物理组件,声音组件等等。这些组件实现了所有引擎提供的基础功能,会被脚本使用来组合高级功能。
-
模块功能脚本组件
通过脚本实现的一些相对独立的通用模块功能的组件。这类组件的设计是脚本可重用的关键,需要仔细分析游戏对象中哪些功能可以被独立出来成为一个可重用的功能模块组件,并且在实现上应该尽量降低与其他组件的耦合性。
-
实体
实体在代码上就是一个组件的列表。由于实体的结构实在是太简单了,所以很多实现都没有专门的设计一个实体的数据结构。相反的,一个实体就是一个ID,所有组成这个实体的组件将会被这个ID给标记,从而明确的知道哪些组件是属于哪个实体的。如果你想的话,你可以在运行时,动态的将组件从实体中移除或者增加一个或多个你感兴趣的组件。比如说,如果玩家发出了一个冰系魔法,将敌人冻住,你只要简单的将它的速度组件移除,那么敌人就静止住了。
引申到楼主最近项目里的CharacterBase类,是以面向对象的思想来设计的,随着属性和方法越来越多,这个类变的难以维护,如果以组件的思想来重新设计,血量、位置、碰撞等等都拎出来做为基础组件,而一个对象只是通过组合基础组件来实现的,这样结构会更加清晰,而且要生成一个拥有其他特性的对象也很简单,再挂载一特性组件即可。
总结:
如果你接触过《软件架构》的编程思想就会知道,UNITY的组件模型其实遵循的就是优秀设计的准则:“组合优于继承”