??xml version="1.0" encoding="utf-8" standalone="yes"?>
hWnd = FindWindowEx(hWnd , 0 , " SHELLDLL_DefView " , 0 );
hWnd = FindWindowEx(hWnd , 0 , " SysListView32 " , " FolderView " );
// 初始?nbsp;D3D 讑֤
InitD3D(hWnd);
昄的时候,如果x染在桌面的一角,则可以这样写Q?br>// 昄在左上角Q?28×128?/span>
RECT rect;
rect.left = 0;
rect.right = 128;
rect.top = 0;
rect.bottom = 128;
// 昄
g_pd3dDevice->Present(0 , &rect , 0 , 0);
在游戏引擎中Q?/span>Entity通常被翻译成实体Q也常用诸如GameObject?/span>Actor?/span>SimulationObject?/span>Unit?/span>Character{名字。相比于对图像声韛_擎的热情Q?/span>Entity层多q来一直备受冷遇,但最q几q随着大型游戏的发展,Entity层设计的重要性已l达到和囑փ声音的同{水qI而且已经出现了多U通用?/span>Entity架构。当Ӟq里伴随着争议和分歧?/span>
q是最早、最单、也是Q何h都能直接惛_的模式。这U方式下一?/span>Entity是一个简单的struct:
struct Mob
{
int level, hp, mp, attack, …;
};
q种情况下往往需要对不同cd?/span>Entity定义不同?/span>structQ比?/span>Player?/span>Mob?/span>Item?/span>Doodad{?/span>Entity的数据库可以直接使用现成的数据库pȝ或者从数据文gdQ比?/span>csv文g。一般会选择Excel~辑数据库,然后导出csv?/span>Excel的强大表格和l计计算功能是调节游戏数据^衡的得力工具。以致这U最古老而简单的Entity模式以强大的生命力一直活到现在?/span>
那么Z?/span>Developers会要L索其他方式呢Q最大的问题是这U方式下各种Entity完全不同质。比?/span>Player?/span>Mob?/span>Doodad都有位置Q都要做撞,但他们却是不同的cdQ不能用同一份代码;Player?/span>Mob都有hp?/span>mpQ也有基本相同的处理逻辑……当然Q这个可以用hack的方法解冻I只要各个struct前若q个成员cd和顺序完全相同,可以将指针cast成统一的一?/span>Entitycd来处理。不q,M人都能想到更好的办法Q用c!
q也?/span>Entity?/span>GameObject{这些名字的由来Q他们就是基cR于是我们可以得C颗承关pL(wi)Q例如:
Entity
Character
Player
Mob
Missile
Laser
GuidedMissile
Item
…
Entity对象的逻辑大多也是直接包含在类里的。但也有人采用了数据对象和逻辑对象的分,其好处是对相同的数据可以替换不同的逻辑。不q,个h比较怀疑这U分L否值得Q因为类的派生本w就是可以拥有不同的逻辑?/span>
另外Q?/span>Entity间的交互除了用标准的直接讉K方式外,l常使用消息模式。消息模式和Windows的消息模式类|Entity间通过消息交互。虽说窗口编E画了多q时间才摆脱了当q肥大的switch的消息处理模式,?/span>Entity层用消息模式还是有意义的,因ؓ消息很容易广播且可以直接在网l上发送。执着?/span>OO的h会将消息写成Command对象Q但原理仍然是一L(fng)?/span>
同时Q联|游戏出玎ͼ指针不能在不同的机器上标识对象,我们必须用稳定的ID来标识对象,于是我们有了EntityManager来分?/span>ID和管理对象集合,或者叫GameObjectManager?/span>ObjectManager{。这在一D|期内几乎成了完美的方案?/span>
随着游戏内容的丰富性的q速膨胀Q传l的q序员来实现游戏逻辑功能的模式也来力不从心。脚本语a的集成将大部分创意性工作从E序员的担子上拿了下来,交还l游戏设计h员。ؓ了给脚本提供_的控制权Q?/span>Entityl构上必L充分的灵zL?/span>
现在有句很流行的话,“唯一不变的是变化。(The only constant is change.Q?#8221;数据驱动使得变化对引擎的影响最化。数据驱动不能算是一U独立的Entity模式Q不如说它是一U设计思想Q其目的是内容制作和游戏引擎的制作分d来。与上面所说的填充Entity属性数据库的不同之处在于,它还要能通过数据来设计游戏逻辑?/span>
游戏设计人员需要的一Ҏ(gu)基本功能是自定义h物属性,所以与其在c里写死属性成员,不如使用属性表Q?/span>Attributes/PropertiesQ。通常使用一个哈希表Q?/span>HashtableQ,或?/span>std::mapQ或?/span>DictionaryQ或者就是个数组Q随个h喜好Q其实就是要一?/span>key-value的映表。然后ؓ脚本和编辑器提供对属性表的操作?/span>
动态的逻辑主要靠脚本了,必须本提供够的事g和方法。个人推荐用Lua脚本Q因为它是在游戏领域内用得最多的通用脚本语言Q其引擎很小、速度很快、易于集成,管语法q于松散。不要迷信宣传去用庞大、极慢、难于集成的Python。ؓ脚本提供事gQ其实也是调用脚本里的函数Q这里如果用了前面所q的消息模式Q那么就只要调用一个脚本方法,传递不同的消息参数p了。当然也有h觉得q样很丑陋而更愿意Z同的事g注册不同的函数?/span>
当有了数据驱动后Q?/span>Entity的承树(wi)基本失L义了Q因Z?/span>Entity是什么已l不是程序里军_的了Q而是通过数据和脚本设计出来的。但数据和脚本又不是全部Q一?/span>Entity的核心内容和需要高效处理的部分Q如撞,q是要程序来完成。于是我们需要重新设?/span>Entityc,困难的局面也q此开始?/span>
一个直观的x是一个统一且唯一?/span>Entityc,它包含了所有的基本功能Q如昄、碰撞检、运动、背包等Q然后由数据军_哪些lg被启用。比如一个玩家角色可能会启用l大部分lgQ而一颗树(wi)只启用显C和撞组件。但也伴随着~点Q一、这个类太大了;二、对于树(wi)木等一些简单的Entity也要费其他lg的私有数据所占的内存。那么一个简单的折中是部分用ѝ部分用数据定制。例?/span>Entity只提供最基本的组Ӟ再派生出CharactorEntity提供_人物角色使用的组件?/span>
提到lgQ那么很自然的就q渡到组件模式,是把显C、运动、攻凅R背包、队伍、声音等基本功能都做成独立的lgQ由数据来决定向Entity里添加哪些组件。由此可以得到另外一个扩展,是既然可以有引擎内|的lgQ那׃可以有脚本制作的lgQ实现脚本模块的复用。这U模式在GDC2002正式提出Q到现在L的引擎都有这U设计?/span>
q种模式在理Z很完,但实践上q是有不疑问。最常见的问题就是组仉的依赖关pR理x况下Q各个组件是完全独立的,但实践中必然有所依赖。比如运动速度、攻d度等和角色的基本属性有养Iq动lg需要角色的包围盒来试是否撞Q?/span>AIlg需要分析角色当前状态和发出q动、攻d令,角色动作状态变化时改变昄lg属性,dlg需要访问队伍信息组件以止d队友{等。处理这U依赖关pM要要解决两个问题Q?/span>
<!--[if !supportLists]-->一?span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal"> <!--[endif]-->谁依赖谁。比如是敏捷属性改变而去修改Ud速度Q还是运动组件读取敏捷属性来计算Ud速度。如果要游戏设计人员自由定义基本属性的话,p选择前者,因ؓ基本属性组件会是脚本组件?/span>
<!--[if !supportLists]-->二?span style="FONT: 7pt 'Times New Roman'; font-size-adjust: none; font-stretch: normal"> <!--[endif]-->如何取得另一lg的指?/span>/引用。常见的Ҏ(gu)是给每个lgcd一个唯一IDQ然后用?/span>ID?/span>Entity上查询注册了的组Ӟ如果扑ֈq回其指?/span>/引用Q否则返?/span>null。当Ӟ每次讉K都做q个查询会很费CPUQ如?/span>Entity的组件不会在q行时动态添加删除的话(除非在编辑器里,否则很少有h会这么做Q,可以?/span>Entity初始化后让每个组件缓存它所要用的其他组件指针。那么当所依赖的组件不存在怎么办,一般情况下都是无声地忽略?/span>
?/span>Entity由很多组件组成后Q交互的消息需要发l每一个组件。这里又一ơ体现出消息机制的优势,你不需要在Entity里ؓ每一个事件函数写一?/span>loop来调用组件的相应事g函数。但q里也出C一个问题,消息到达各个lg的顺序。很多时候这个顺序不会有什么媄响,但个别时候不同的序会导致完全不同的逻辑发展方向?/span>
此外Q?/span>Entity的序列化存储也变得比较复杂,l典?/span>Excel导出csv的模式难以奏效,因ؓq里需要结构化的存储,所以需要结构化的数据文件如XML来存储,或者完全用脚本来包含所有数据和构?/span>Entity?/span>
据个人经验,使用数据驱动的承模式时很是向往lg模式Q感觉上它一个非常自然的扩展方向Q但ֿ其引入的额外的复杂性,其是需要游戏设计h员具有一定的~程能力Q所以一直不敢全盘接q用。但退一步,在引擎里仍然使用lg思想Q但Entity的组件构成在~译时固定,可以辑ֈ某种妥协Q这和采用承与数据驱动的折中类伹{?/span>
q是又一U常见的折中模式Q即使用C++的多重承,各个组件类混入一?/span>EntitycR如Q?/span>
class Mob: public GameObject, public Renderable, public Movable, public Attackable
{
…
}
~程领域最古老的原则之一是?#8220;单快?#8221;。但随着问题的复杂化Q程序也随之变得来复杂。好的方法应该能有效的降低或隐藏复杂性。但是,没有不带副作用的药(No silver bullet.Q,在取得更强大的功能的同时M带来额外的复杂性。我们需要做出权衡,在必要时牺牲一些功能,也就是要估算性h(hun)比?/span>
一般游戏内容制作h员不会或不太会编E,~程人员也不善于游戏的内容创造和数值^衡,q于复杂的系l会D需要两面兼儡人才Q会大大增加做出一ƾ游戏的隑ֺ?/span>