首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Ogitor代码分析

Ogitor代码分析

作者头像
逍遥剑客
发布2018-05-23 15:18:06
5250
发布2018-05-23 15:18:06
举报

引擎状态监听(观察者)

底层变化时, 需要高层UI做出反应. 这个有一个原则, 就是下层逻辑不能依赖上层逻辑, 所以通过一个接口进行消息的派发. 如果是.net的话, 可以用delegate/event实现. C++的话, 可以自己用模板写个delegate用, 效率比用接口高…

实体抽象(工厂方法)

扩展性是很强, 但是…类太多了-_-. 这里有种基于DLL的插件模型可以学习. 工厂方法需要知道具体的工厂对象, 这里要求初始化工厂的对象(OgitorRoot)要知道具体的工厂定义(C++的#include做得太失败了, 导致编译效率低下…). 但是做成DLL插件的话, 就可以利用DLL的导出函数反向调用OgitorRoot进行注册. 不过, 对于内部使用, 进行二进制分离有意义吗?

Undo/Redo(命令模式)

这机制实现的前提是, 所有CBaseEditor对象都可以用一系列的”属性”来进行初始化/设置. 所以每一个Command都是针对属性的修改. 对于Create/Destory来说, 可以看成对所有属性的修改外加对象的创建/删除. 属性的变量类型并没有进行抽象, 而是转换成了字符串, 需要时再转换回来. 如果是.net的话, 就方便许多, 直接可以获得PropertyInfo[], 而且能跟PropertyGrid控件进行属性的自动绑定. 不过这属于语言的”反射”应用, 标准C++不具备这个特性(@_@).

  1. BaseEditor^ object = root->FindObject(objName);  
  2. if (nullptr == object)  
  3. return;  
  4. Dictionary<String^, Object^> properties = undoCmd->Properties;  
  5. for each(KeyValuePair<String^, Object^> pair in properties)  
  6. {  
  7.     PropertyInfo^ info = object->GetType()->GetProperty(pair->Key);  
  8. if (nullptr != info)  
  9.         info->SetValue(object, pair->Value, nullptr);  
  10. }  

鼠标编辑

就是移动, 旋转, 缩放对象的操作响应还有可视化表示. 操作时的选中轴是所有编辑对象统一使用一套, 自定义的表示, 如下图中的spot light, 是通过派生CVisualHelper来进行定制绘制的.

多选处理

这里到是没用什么有用的模式, 不过对于OgitorsRoot::VolumeSelect()的算法到是很感兴趣.

在viewport上的矩形选框, 可以对应3D空间一个5个平面组成的包围体(远面不包含), 以这个包围体到场景树去遍历查询所有实体, 就能得到选中的实体列表. 所有选中对象组合成一个CMultiSelEditor进行移动/旋转/缩放.

属性编辑

把SetXXX全部定义到一个函数指针数组, 根据类型(ID)进行索引, 避免了一堆if-else. 无论是UI到引擎, 还是引擎到UI的通知, 都是以这个ID来进行查找的. PropertyGrid的Item绑定的数据, 也是这个ID, 而不是实际的对象. 但是, 这样也带来另一个问题: 每扩充一个属性就会去改动这个类型定义的头文件, 那DLL中定义的特殊属性怎么办?

  1. /// The definition for any SETXXX function
  2. /// BIND_ID: is the BINDING ID between the PropertyGrid and the Actual Functions
  3. ////param val     : Since the actual variable types change, PropertyGrid passes
  4. ///                 Its values as String and refresh
  5. ////param refresh : Since those functions can be called by any object other than PropertyGrid
  6. ///                 this parameter defines if the value at PropertyGrid should be refreshed
  7. ///                 used as "false" from PropertyGrid
  8. typedef void (THISCALL CBaseEditor::* BINDINGSETFUNC)(int BIND_ID,Ogre::String val,bool refresh);  
  9. static BINDINGSETFUNC   m_SetFunctions[MAXIMUM_BINDING_FUNCTIONS]; ///< List of BINDING FUNCTIONS

序列化

这里有能体现出属性进行抽象的好处了, 所有对象直接写进XML格式的工程文件. 用XML的好处就是, 增删属性不用改文件序列化的代码, 缺点是解析速度慢, 占用空间大. 而二进制就比较郁闷, 格式一改动就要进行代码变更, 通常还要兼容几个版本的文件. 地形方面由于是插件的原因, 文件是独立的. 不过不管什么场景, 地形独立出来其实没什么不好的, 因为地形的格式比较稳定, 不会经常变动, 独立出来更方便做版本管理.

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2010年01月17日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引擎状态监听(观察者)
  • 实体抽象(工厂方法)
  • Undo/Redo(命令模式)
  • 鼠标编辑
  • 多选处理
  • 属性编辑
  • 序列化
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档