我一直想知道电子游戏,尤其是大型3D项目在多大程度上使用了面向对象的技术。我认为这两者都是很酷的,troll
并且werewolf
从enemy
其中的某些属性继承并重写了它们的属性。但是,也许课程太重而无法进行实践,我不知道...
我一直想知道电子游戏,尤其是大型3D项目在多大程度上使用了面向对象的技术。我认为这两者都是很酷的,troll
并且werewolf
从enemy
其中的某些属性继承并重写了它们的属性。但是,也许课程太重而无法进行实践,我不知道...
Answers:
举一个例子,我将解释我对电子游戏中实体的想法。我不会讨论对象和类的一般优缺点,也不会讨论它们在电子游戏中的全部作用。
小型电子游戏中的实体通常由单独的类定义,在大型游戏中,它们通常在文件中定义。有两种通用方法可以遵循:
扩展:在您的示例中Troll
,Werewolf
将扩展Enemy
,即扩展Entity
。Entity
会照顾运动,健康等基本事物,同时Enemy
将子类声明为敌人并做其他事情(Minecraft会遵循这种方法)。
基于组件:第二种方法(也是我最喜欢的方法)是一Entity
类,其中包含组件。组件可以是Moveable
或Enemy
。这些组件只关心运动或物理等一件事。此方法会中断较长的扩展链,并最大程度地降低发生冲突的风险。例如:如果不可移动敌人是从可移动角色继承而来的,该如何使它们成为敌人?。
在《魔兽世界》或《星际争霸2》等大型电子游戏中,实体不是类别,而是指定整个实体的数据集。脚本编制也很重要,因为您可以定义实体不是在类中而是在脚本中定义的(如果它是唯一的,则不是移动之类的东西)。
我目前正在为RTS编程,我采用基于组件的方法来处理实体,技能,物品以及游戏中所有动态的描述符和脚本文件。
component
在这种情况下a 是什么。链接将不胜感激。
我认为巨魔和狼人都从敌人那里继承了它的属性并改写了其中的一些,这是很酷的。
不幸的是,这种在90年代流行的多态方法在实践中已证明是个坏主意。假设您将“狼”添加到敌人列表中-好吧,它与狼人共享一些属性,因此您希望将这些属性合并到一个共享的基类中。'WolfLike'。现在,您将“人类”添加到敌人列表中,但是狼人有时是人类,因此它们也共享一些属性,例如两条腿走路,能够说话等。您是否为人类和狼人创建了“类人动物”共同基础,然后您是否必须停止从WolfLike派生的狼人?还是您要同时继承两者?在这种情况下,当类人动物中的某物与WolfLike中的某物发生冲突时,哪个属性优先?
问题在于尝试将现实世界建模为类树是无效的。采取任何3件事,您可能会发现4种不同的方式将其行为分解为共享和非共享的因素。这就是为什么许多人转而使用模块化或基于组件的模型的原因,在该模型中,一个对象由几个较小的对象组成,这些较小的对象组成整体,并且可以交换或更改较小的对象以组成所需的行为。在这里,您可能只有1个敌人类别,并且包含有关其行走方式的子对象或组件(例如Bipedal与Quadpededal),攻击方法(例如咬伤,爪子,武器,拳头),皮肤(绿色)巨魔,毛茸茸的狼人和狼),等等。
这仍然是完全面向对象的,但是什么是有用的对象的概念与课本中通常讲授的对象不同。通常,您只有一个表示一个抽象概念的具体类(例如“敌人”),而不是拥有一个包含各种抽象类的大型继承树和几个具体类的树,而是包含了更多表示更多抽象概念的具体类。 (例如,攻击,皮肤类型)。有时,可以通过1级继承来最好地实现这些第二类(例如,基本的Attack类和针对特定攻击的几个派生类),但是深层继承树就消失了。
但是,也许课程太重而无法进行实践,我不知道...
在大多数现代语言中,课程并不是“繁重的”。它们只是编写代码的另一种方式,它们通常只是包装您无论如何都要编写的过程方法,除了语法更简单之外。但是,无论如何,不要编写函数可以使用的类。类在本质上并不是更好,只有在它们使代码更易于管理或理解的地方。
类不涉及任何运行时开销。运行时多态仅通过函数指针进行调用。与其他开销相比,这些开销是极少的,例如Draw调用,并发同步,磁盘I / O,内核模式切换,较差的内存位置,过度使用动态内存分配,较差的算法选择,使用脚本语言和列表继续。面向对象本质上已经取代了之前的东西,这是有原因的,这是因为它要好得多。
要意识到的一件事是,面向对象代码的概念通常比其在语言中的实现更有价值。特别是,必须在主循环中的实体上执行数千次虚拟更新调用,这可能会在360或PS3等平台上的C ++中的缓存中造成混乱-因此,该实现可能会避免使用“虚拟”或“类”关键字的速度。
尽管它通常仍会遵循面向对象的继承和封装概念-只是以与语言本身不同的方式来实现它们(例如,好奇地递归模板,合成而不是继承(Marco描述的基于组件的方法))。如果继承总是可以在编译时解决,那么性能问题就消失了,但是代码可能会因模板,自定义RTTI实现(同样内置的实现通常不切实际地缓慢)或在宏等
在iOS / Mac上的Objective-C中,消息传递方案(甚至是高级缓存)也存在类似但更严重的问题...
我将尝试使用的方法将类继承和组件混合在一起。(首先,我不使Enemy成为一个类,而是使它成为一个组件。)我不喜欢这样的想法:对所有内容使用一个通用Entity类,然后添加必要的组件以充实该实体。相反,我更喜欢让一个类在构造函数中自动添加组件(和默认值)。然后,子类在其构造函数中添加其其他组件,因此子类将具有其组件和其父类组件。例如,武器类将添加所有武器通用的基本组件,然后剑子类将添加特定于剑的任何其他组件。我仍在争论是否使用text / xml资产来定义实体的值(例如特定的剑),或在代码中完成所有操作,或正确的组合方式。这仍然允许游戏使用代码语言的类型信息和多态性,并使ObjectFactories更加简单。