重构实践——利用配置文件实现设计的高度抽象

    项目简介:基于各种开源库(OGRE、OpenSteer、Newton、Raknet、OpenAL)的游戏引擎项目,目前项目正在进行2.0版本的开发,主要工作是对前一版本从整体框架上进行大幅度改进,建立健壮的异常和运行时错误处理机制,以及完成各个子系统框架的重构,这篇文章就是根据笔者对AI子系统重构实践写成。

设计动机:

1、抽象程度低。引入任何一个新类型事物,都需要加入其对应的个体类或群体类及群体管理器。

2、不同个体之间的耦合程度高。具体体现在有着某种关系的个体之间,如追踪与被追踪关系。其中,一类个体A的状态受到另一类个体B的直接干涉(B通过设置A的一类标志,来迫使A的状态转变),这显然与自然规则和OOD原则相违背。按照面向对象的设计思想,一个对象应该尽量做到内聚,也就是说对象应该有自主能力,它掌控着自身所有的状态和变化,必要时提供自身的一些信息(比如,位置信息)。

3、灵活度低。如果需要添加/删除/更新功能,则需要对每个个体类型的代码进行相应修改。

设计思路:

 1、对于抽象程度低的设计缺陷,采用提炼所有存在类中并集,加之配置文件运行时动态具类化(即,根据配置文件和创建参数动态确定创建对象的类型,如Tiger、Deer等)。之所有考虑提炼并集而不是交集,目的是让其以配置文件形式而非代码(即,继承)来具类。
 2、通过提炼AI对象之间的相互作用关系,得出一种以角色(Role)为基础的关系抽象。在此设计中,每个对象都一个或者多个角色,同时又有其感兴趣的一个或者多个角色。角色管理器担当着管理角色-对象列表(如图1)。对象在创建时根据其角色将自身注册到全局的角色管理器中。一个对象能够在需要时在角色管理器中搜索其感兴趣的角色对象,获取其参数后,根据计算值更新自己的状态。如时序图2所示。

图1


图2 示例时序图(省略了Deer的状态更新过程)

实现:

1、AI个体抽象类CIndividual,维护着个体的智能,是OpenSteer::SimpleVehicle和Ogre::UserDefinedObject的子类。
2、AI个体抽象包装类CIndividualWrapper,负责对象的视觉表现,对CIndividual起着包装作用,是CIndividual的友元。
3、角色管理器模板类CRolesManager,实现如下:

000001     class CIndividual;
000002    
000003     /** 全局角色管理器
000004    @author Groov0V(groov0v.luo@gmail.com)
000005    
000006    负责管理角色对应的对象列表
000007    */

000008    
000009     template<typename T>
000010     class CRolesManager
000011    {
000012     public:
000013        ~CRolesManager()
000014        {
000015            RoleRegistryMapIter iter;
000016            TRAV(m_roleRegistryMap , iter)
000017            {
000018                SAFE_DELETE( iter->second );
000019            }
000020        }
000021    
000022         /** 将对象指针添加到角色ID对应的列表中
000023        */

000024         void Add( unsigned int roleID , T* pObj)
000025        {
000026            RoleRegistryMapIter iter = m_roleRegistryMap.find(roleID);
000027             if(iter != m_roleRegistryMap.end())
000028                iter->second->push_back(pObj);
000029             else
000030            {
000031                std::list<T*>* listPtr = new std::list<T*>;
000032                listPtr->push_back(pObj);
000033                m_roleRegistryMap.insert(make_pair(roleID , listPtr));
000034            }
000035        }
000036    
000037         /** 从角色列表中移除对象
000038        */

000039         void Remove( unsigned int roleID , T* pObj)
000040        {
000041            RoleRegistryMapIter iter = m_roleRegistryMap.find(roleID);
000042             if(iter != m_roleRegistryMap.end())
000043                iter->second->erase(pObj);
000044        }
000045    
000046         /** 返回指定角色的对象列表
000047        */

000048        std::list<T*>* GetObjList( unsigned int roleID)
000049        {
000050            RoleRegistryMapIter iter = m_roleRegistryMap.find(roleID);
000051             if(iter != m_roleRegistryMap.end())
000052                 return iter->second;
000053             else
000054                 return NULL;
000055        }
000056     private:
000057         /** 角色-对象注册表
000058        */

000059        stdext::hash_map< unsigned int , std::list<T*>*> m_roleRegistryMap;
000060         typedef typename stdext::hash_map< unsigned int , std::list<T*>*>::iterator RoleRegistryMapIter;
000061    };
000062    
000063     #define g_rolesManager DMF::globe_instance< CRolesManager<CIndividual> >::Instance()
000064    

4、配置脚本(利用TinyXML实现读/存):

000001    <AIObjects>
000002        <Object name="Tiger">
000003         <Roles>
000004         <Role name="Tracer" id="0" />
000005         </Roles>
000006         <DisRoles>
000007         <DisRole name="BeTracer" id="1" />
000008         </DisRoles>
000009         <NumericParams>
000010             <Param name="SIGHT_DISTANCE" value="1200" />
000011             <Param name="PURSUIT_DISTANCE" value="800" />
000012             <Param name="ATTACK_DISTANCE" value="200" />
000013             <Param name="WALK_STRAIGHT_TIME" value="2.5" />
000014             <Param name="WALK_TIME" value="10.0" />
000015             <Param name="IDLE_TIME" value="2.5" />
000016             <Param name="PURSUIT_TIME" value="15" />
000017             <Param name="WALK_SPEED" value="20" />
000018             <Param name="PURSUIT_SPEED" value="100" />
000019             <Param name="ATTACK_SPEED" value="120" />
000020             <Param name="MOVE_SPEED" value="50" />
000021             <Param name="LENGTH" value="35" />
000022             <Param name="ENERGY" value="100" />
000023             <Param name="STEER_FORCE" value="200" />
000024             <Param name="STEER_MAX_SPEED" value="150" />
000025             <Param name="STEER_RADUIS" value="25" />
000026             <Param name="WANDER_JITTER" value="100" />
000027             <Param name="WANDER_RADUIS" value="50" />
000028             <Param name="ENERGY_DES" value="20" />
000029            </NumericParams>
000030            <StringParams>
000031             <Param name="PLACEHOLDERMATNAME" value="GOOFPlaceHolderTiger" />
000032             <Param name="PLACEHOLDERMESHNAME" value="soundnode.mesh" />
000033             <Param name="Type" value="GameTigerObject" />
000034             <Param name="MeshFile" value="dire_cat.mesh" />
000035            </StringParams>
000036            <AnimationStates>
000037             <State id="0" name="cpause1" />
000038             <State id="3" name="crun" />
000039             <State id="-1" name="cwalk" />
000040            </AnimationStates>
000041        </Object>
000042        <Object name="Deer">
000043         <Roles>
000044         <Role name="BeTracer" id="1" />
000045         </Roles>
000046         <DisRoles>
000047         <DisRole name="Tracer" id="0" />
000048         </DisRoles>    
000049         <NumericParams>
000050             <Param name="WALK_SPEED" value="20" />
000051             <Param name="RUN_SPEED" value="120" />
000052             <Param name="IDLE_TIME" value="8.0" />
000053             <Param name="WALK_TIME" value="8.0" />
000054             <Param name="ENERGY" value="100" />        
000055             <Param name="LENGTH" value="35" />
000056             <Param name="WALK_STRAIGHT_TIME" value="1.5" />
000057             <Param name="RUN_DISTANCE" value="600" />
000058             <Param name="SAFE_DISTANCE" value="820" />
000059             <Param name="STEER_FORCE" value="200" />
000060             <Param name="STEER_MAX_SPEED" value="150" />
000061             <Param name="STEER_RADUIS" value="25" />
000062             <Param name="WANDER_RADUIS" value="50" />
000063             <Param name="WANDER_JITTER" value="40.0" />
000064             <Param name="ENERGY_DES" value="20" />
000065            </NumericParams>
000066            <StringParams>
000067             <Param name="PLACEHOLDERMATNAME" value="GOOFPlaceHolderDeer" />
000068             <Param name="PLACEHOLDERMESHNAME" value="soundnode.mesh" />
000069             <Param name="Type" value="GameDeerObject" />
000070             <Param name="MeshFile" value="deer.mesh" />
000071            </StringParams>
000072            <AnimationStates>
000073             <State id="0" name="creadyl" />
000074             <State id="6" name="crun" />
000075             <State id="-1" name="cwalk" />
000076            </AnimationStates>        
000077        </Object>
000078        <Object name="Bird">
000079            ... ...
000080        </Object>
000081        <Object name="Butterfly">
000082            ... ...
000083        </Object>
000084    </AIObjects>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值