Ogre设计模式分析-观察者模式
2010-03-31 21:18
441 查看
观察者模式是游戏开发中十分常用的模式,Ogre也大量运用了此模式来监听,比如FrameListener.ResourceListener
这种方式比常见的回调函数更好用,因为观察者模式是基于接口的,任何类只要继承这个接口,注册后就可以监听我们需要观察的对象。不想监听,取消注册就行了,
具体实现原理,我们以为FrameListener为例子,然后再举一反三在自己的游戏中使用它,比如场景编辑器,我拖动了一个entity,改变了他的位置,那么显示对象属性的控件应该更新这个对象的位置,我们就可以设计一个监听类来监听任何对对象的操作,有变化就通知给显示面板。
Ogre的帧监听怎么实现的呢
1,先设计了一个基类,作为接口,啥东西都没,要自己override
class _OgreExport FrameListener
{
public:
virtual bool frameStarted(const FrameEvent& evt) { return true; }
virtual bool frameEnded(const FrameEvent& evt) { return true; }
virtual ~FrameListener() {}
};
2,然后在renderOneFrame(void)里面就会每帧调用这个基类的函数
bool Root::renderOneFrame(void)
{
if(!_fireFrameStarted()) // 调用帧开始
return false;
_updateAllRenderTargets();
return _fireFrameEnded(); // 调用帧结束
}
3, 看看具体实现
bool Root::_fireFrameStarted(FrameEvent& evt)
{
// Increment frame number
++mCurrentFrame;
// Remove all marked listeners
std::set<FrameListener*>::iterator i;
for (i = mRemovedFrameListeners.begin();
i != mRemovedFrameListeners.end(); i++)
{
mFrameListeners.erase(*i);
}
mRemovedFrameListeners.clear();
// Tell all listeners
// 通知所有注册了的帧监听类
for (i= mFrameListeners.begin(); i != mFrameListeners.end(); ++i)
{
if (!(*i)->frameStarted(evt))
return false;
}
return true;
}
看了源码,就明白,root里面保存有一个容器mFrameListeners,存储了所有注册了的帧监听
只要加入到这个容器,就可以被遍历.然后通过C++的动态多态,实现frameStarted的调用
4, 怎么加入这个容器呢?就是addFrameListener函数
void Root::addFrameListener(FrameListener* newListener)
{
// Check if the specified listener is scheduled for removal
std::set<FrameListener *>::iterator i = mRemovedFrameListeners.find(newListener);
// If yes, cancel the removal. Otherwise add it to other listeners.
if (i != mRemovedFrameListeners.end())
mRemovedFrameListeners.erase(*i);
else
mFrameListeners.insert(newListener); // Insert, unique only (set)
}
5, 所有要使用一个帧监听,实例一个,再addFrameListener就OK,否则void Root::removeFrameListener(FrameListener* oldListener)
,而且我们可以创建N个帧监加入容器,就可以在任何类里面调用到frameStarted函数.
--------------------------------------------------------------------------------------------------------------------------
其作用,其实和用函数指针实现的回调函数差不多,但是明显比常见的回调的方式更好
由于是基于接口的,那么扩展性非常好,比如Ogre的代码是封装成一个dll的,如果用回调,可能要写明回调到那个函数,可视Ogre并不知道用户写的函数,所以Ogre用接口,只操作接口,而用户继承这个接口,用C++动态多态,就可以实现对应函数的调用.
这种方式很适合库和库之间,比如我Ogre的渲染模块用了一个库,客户端可以用我,场景编辑器也可以用我,Ogre的渲染模块就应该设计很多接口
比如场景编辑器,我拖动了一个entity,改变了他的位置,那么显示对象属性的控件应该更新这个对象的位置,我们就可以设计一个监听类来监听任何对对象的操作,有变化就通知给显示面板。
依葫芦画瓢
1,先设计一个SceneListener基类
2, 设计一个管理者SceneListenerManager来管理这些类,Ogre里面就是用root管理的
那么只要我们在更改对象属性的地方调用此函数通知所有监听者
所有监听者都会被通知,那么只要我们注册成一个监听者就可以收到这个消息
假设显示面板要收到这个消息
这种方式比常见的回调函数更好用,因为观察者模式是基于接口的,任何类只要继承这个接口,注册后就可以监听我们需要观察的对象。不想监听,取消注册就行了,
具体实现原理,我们以为FrameListener为例子,然后再举一反三在自己的游戏中使用它,比如场景编辑器,我拖动了一个entity,改变了他的位置,那么显示对象属性的控件应该更新这个对象的位置,我们就可以设计一个监听类来监听任何对对象的操作,有变化就通知给显示面板。
Ogre的帧监听怎么实现的呢
1,先设计了一个基类,作为接口,啥东西都没,要自己override
class _OgreExport FrameListener
{
public:
virtual bool frameStarted(const FrameEvent& evt) { return true; }
virtual bool frameEnded(const FrameEvent& evt) { return true; }
virtual ~FrameListener() {}
};
2,然后在renderOneFrame(void)里面就会每帧调用这个基类的函数
bool Root::renderOneFrame(void)
{
if(!_fireFrameStarted()) // 调用帧开始
return false;
_updateAllRenderTargets();
return _fireFrameEnded(); // 调用帧结束
}
3, 看看具体实现
bool Root::_fireFrameStarted(FrameEvent& evt)
{
// Increment frame number
++mCurrentFrame;
// Remove all marked listeners
std::set<FrameListener*>::iterator i;
for (i = mRemovedFrameListeners.begin();
i != mRemovedFrameListeners.end(); i++)
{
mFrameListeners.erase(*i);
}
mRemovedFrameListeners.clear();
// Tell all listeners
// 通知所有注册了的帧监听类
for (i= mFrameListeners.begin(); i != mFrameListeners.end(); ++i)
{
if (!(*i)->frameStarted(evt))
return false;
}
return true;
}
看了源码,就明白,root里面保存有一个容器mFrameListeners,存储了所有注册了的帧监听
只要加入到这个容器,就可以被遍历.然后通过C++的动态多态,实现frameStarted的调用
4, 怎么加入这个容器呢?就是addFrameListener函数
void Root::addFrameListener(FrameListener* newListener)
{
// Check if the specified listener is scheduled for removal
std::set<FrameListener *>::iterator i = mRemovedFrameListeners.find(newListener);
// If yes, cancel the removal. Otherwise add it to other listeners.
if (i != mRemovedFrameListeners.end())
mRemovedFrameListeners.erase(*i);
else
mFrameListeners.insert(newListener); // Insert, unique only (set)
}
5, 所有要使用一个帧监听,实例一个,再addFrameListener就OK,否则void Root::removeFrameListener(FrameListener* oldListener)
,而且我们可以创建N个帧监加入容器,就可以在任何类里面调用到frameStarted函数.
--------------------------------------------------------------------------------------------------------------------------
其作用,其实和用函数指针实现的回调函数差不多,但是明显比常见的回调的方式更好
由于是基于接口的,那么扩展性非常好,比如Ogre的代码是封装成一个dll的,如果用回调,可能要写明回调到那个函数,可视Ogre并不知道用户写的函数,所以Ogre用接口,只操作接口,而用户继承这个接口,用C++动态多态,就可以实现对应函数的调用.
这种方式很适合库和库之间,比如我Ogre的渲染模块用了一个库,客户端可以用我,场景编辑器也可以用我,Ogre的渲染模块就应该设计很多接口
比如场景编辑器,我拖动了一个entity,改变了他的位置,那么显示对象属性的控件应该更新这个对象的位置,我们就可以设计一个监听类来监听任何对对象的操作,有变化就通知给显示面板。
依葫芦画瓢
1,先设计一个SceneListener基类
2, 设计一个管理者SceneListenerManager来管理这些类,Ogre里面就是用root管理的
// 用boost库的智能指针管理的场景对象而已 class Object; typedef boost::shared_ptr<Object> ObjectPtr; typedef boost::weak_ptr<Object> ObjectWeakPtr; // 场景监听基类 class SceneListener { public: SceneListener(void) {} virtual ~SceneListener(void) {} virtual void onObjectPropertyChanged(const ObjectPtr& object, const String& name) {}; }; // 场景监听管理器 class SceneListenerManager { protected: typedef std::list<SceneListener*> Listeners; Listeners mListeners; public: SceneListenerManager(void); ~SceneListenerManager(void); void addSceneListener(SceneListener* listener) { mListeners.push_back(listener); } void removeSceneListener(SceneListener* listener) { mListeners.remove(listener); } // SceneListener* exclude 表示不用通知自己,因为自己也可能是一个SceneListener void _fireObjectPropertyChanged(const ObjectPtr& object, const String& name, SceneListener* exclude = 0) { for (Listeners::const_iterator it = mListeners.begin(); it != mListeners.end(); ++ it) { SceneListener* listener = *it; if (listener != exclude) { listener->onObjectPropertyChanged(object, name); } } } };
那么只要我们在更改对象属性的地方调用此函数通知所有监听者
object->setProperty("position", position); getSceneListenerManager()->_fireObjectPropertyChanged(object, "position", this);
所有监听者都会被通知,那么只要我们注册成一个监听者就可以收到这个消息
假设显示面板要收到这个消息
// 编辑器的属性面板 class PropertyPlane : public SceneListener { public: // 初始化的时候加入监听 PropertyPlane(void) { getSceneListenerManager()->_addSceneListener(this); } // 重写 void onObjectPropertyChanged(const ObjectPtr& object, const String& name) { // 显示这个对象的新的属性,对象指针和属性名字已经传过来了 } };
相关文章推荐
- Ogre设计模式分析-观察者模式
- OGRE分析之设计模式(一)
- Android源码分析:Android中的设计模式——观察者模式
- OGRE分析之设计模式(一)
- Java设计模式之从[星际争霸的兵种升级]分析观察者(Observer)模式
- 观察者设计模式--listView的源码分析
- OGRE分析之设计模式(二)
- 设计模式之----观察者模式(Listview刷新原理分析)
- Ogre的设计模式分析之-单件模式
- Java 设计模式情景分析——观察者模式
- OGRE分析之设计模式(三)
- OGRE分析之设计模式 iterator
- OGRE分析之设计模式
- OGRE分析之设计模式Iterator
- Android 设计模式情景分析——观察者模式
- OGRE分析之设计模式(四)
- Head First--设计模式之观察者模式分析
- 设计模式之---观察者模式简单分析
- OGRE分析之设计模式Chain of Responsibility
- OGRE分析之设计模式(四)