项目简介:基于各种开源库(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>

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

  1. 软件和硬件都是对生活的高度抽象---论中断控制(ARM体系编程)

    不同的芯片体系设计在集成电路系统设计阶段其实都遵循大体一致的设计思想,芯片设计发展那么多年,真正为人所熟知的就是X86架构和ARM架构,当然还有日渐没落的MIPS,其他都是一些简单的控制器芯片体系.而 ...

  2. c语言编程能控制热风炉,利用C语言设计热风炉悬链线拱顶研究.pdf

    j|il ll_ ll梅 诋 融 技 j 萎 |.每薯tj n叠宣鞲s瓿 利用C语言设计热风炉悬链线拱顶 鄢 明 吴建霖 冯 飞 (柳钢设计院) 摘 要 :介绍 了利用 C语言求解两段 圆弧拟合悬链线 ...

  3. 抖音iOS最复杂功能的重构之路--播放器交互区重构实践

    背景介绍 本文以抖音中最为复杂的功能,也是最重要的功能之一的交互区为例,和大家分享一下此次重构过程中的思考和方法,主要侧重在架构.结构方面. 交互区简介 交互区是指播放页面中可以操作的区域,简单理解就 ...

  4. 网易云音乐数仓治理之数据任务重构实践

    云音乐数仓在经历了前期混沌摸索,中期建设完善,如今已逐步形成了一套适合自己的数仓体系和建设规范.增量模型及任务全部走线上设计评审流程,但仍有大量历史任务"年久失修"等待治理.本文以 ...

  5. 新颖性搜索(Novelty Search,NS)算法实践——利用NS算法解决迷宫导航问题

    新颖性搜索(Novelty Search,NS)算法实践--利用NS算法解决迷宫导航问题 新颖性搜索(Novelty Search,NS)算法介绍 NS实现基础 NovItem NoveltyArch ...

  6. 用Tkinter打造自己的Python IDE开发工具(4)利用HP_tk模块设计自己的代码编辑器

    用Tkinter打造自己的Python IDE开发工具(4)利用HP_tk模块设计自己的代码编辑器 HP_tk.py模块是小白量化第二代量化系统中的开发模块.其中HP_tk.py模块是小白量化系统GU ...

  7. 用Tkinter打造自己的Python IDE开发工具(5)利用HP_tka模块设计自己的中文代码编辑器

    用Tkinter打造自己的Python IDE开发工具(5)利用HP_tka模块设计自己的中文代码编辑器 前面我们介绍了在Tkinter中使用exec()函数运行用户程序的方法.exec()采用多线程 ...

  8. 如何利用超级电容设计简单的不间断电源

    如何利用超级电容设计简单的不间断电源 在许多应用中,电源电压无论在什么情况下都持续可用是很重要的.要确保这一点有时并不容易.一种新概念可以为设计极其紧凑的不间断电源提供一种优化解决方案. 问题: 在电 ...

  9. 利用场景法设计atm自动取款机的测试用例_atm自动取款机的测试用例

    1. 软件测试用例实例 自动取款机取款用例规约和测试用例 取款用例说明: 此用例完成用户利用自动取款机取款的全部流程,分为以下流程:插卡,输入密码,选择金额,取款,取卡等操作. 事件流: 该用例在用户 ...

  10. 计算机虚拟建造创新实践英语,室内设计专业虚拟实践教学环节的设计

    摘 要:虚拟实践教学系统是以虚拟现实技术为依托建设而成的实践系统,学生可以便利的在系统中完成实践操作,获得身临其境的感受,在实践中巩固理论知识.本文针对室内设计专业虚拟实践教学系统的设计方法做出了总结 ...

最新文章

  1. shell--数组的定义/访问/赋值/遍历
  2. mysql 转成树_mysql整形转换的坑
  3. ProgressBar(圆形、水平进度条)的基本使用(点击Button1按钮,显示或消失圆形ProgressBar)(每点击一次Button2按钮,水平进度条增加10%)
  4. C++使用数组的链表实现(附完整源码)
  5. Product Archive相关的标准function module
  6. java wmi远程桌面服务器_WMI实现远程监控多台windows服务器
  7. [react] 在React中如何避免不必要的render?
  8. JNI的方式调用DLL(SO)(上)
  9. 生态功能区划方法之三:聚类分析法和生态融合法
  10. 高性能计算机的基准测试程序包括,QX∕T 148-2020 气象领域高性能计算机系统测试与评估规范(可复制版)(40页)-原创力文档...
  11. Num70 债权查询 债权审核
  12. VC++ MsChart控件怎么用?
  13. 汇编语言集成开发环境 RadASM 中文版 (修复object file not found报错)
  14. 模拟电路47(有源滤波器2-二阶低通滤波器)
  15. windows XP下openbravo ERP 2.40安装手迹
  16. 计算机exo乐谱,【图片】【送谱】EXO所有歌曲的谱子【吉他谱吧】_百度贴吧
  17. python制作表白神器_用Python做一个520表白神器,值得收藏
  18. 2022-05-08 Unity核心5——Tilemap
  19. “21 天好习惯”第一期-7
  20. glibc 知:手册21:日期和时间

热门文章

  1. 高等数学学习笔记——第六十一讲——空间曲线的弧长与曲率
  2. 程序员必须了解的10大技术搜索引擎
  3. 【delphi】TMS_Component_Pack_v9.2.4.0中的TadvMemo 支持中文完美修改
  4. angularjs textarea 剩余字数统计
  5. 电脑计算机丢失msvcp140.dll,电脑缺少msvcp140.dll怎么办
  6. BLUES吉他学习笔记001 bluesrv[1-5]
  7. R语言作图——Dumbbell plot(哑铃图)
  8. 计算机课开机心得学生,计算机课学习心得范文体会范文(精选8篇)
  9. js中undefined怎么判断
  10. element修改图标的大小