http://blog.csdn.net/sxy0082002/archive/2009/06/30/4311020.aspx
这里分两部分说delta3d中的app类。主要是dtABC::BaseABC dtABC::Application 和 dtGame::Application
先从BaseABC说起
view plaincopy to clipboardprint?
BaseABC ::BaseABC (const std ::string & name /*= "BaseABC"*/ ) : Base (name )
{
RegisterInstance (this );
System * sys = &dtCore ::System ::GetInstance ();
assert (sys );
AddSender (sys );
CreateDefaultView ();
}
BaseABC ::BaseABC (const std ::string & name /*= "BaseABC"*/ ) : Base (name )
{
RegisterInstance (this );
System * sys = &dtCore ::System ::GetInstance ();
assert (sys );
AddSender (sys );
CreateDefaultView ();
}
在构造函数中该类完成了
1 注册实体
2 构造System
3 监听System消息
4 创建默认View 为其配置场景,窗口,摄像机等参数,并加载地图。
那么BaseABC具体监听了System中的那些消息呢
通过OnMessage()函数 我们可以看出其接受来自System的 MESSAGE_EVENT_TRAVERSAL
MESSAGE_PRE_FRAME MESSAGE_FRAME MESSAGE_POST_FRAME 并根据所接受到的不同消息调用对应的函数
view plaincopy to clipboardprint?
virtual void EventTraversal(const double deltaSimTime){};
virtual void PreFrame(const double deltaSimTime) = 0;
virtual void Frame(const double deltaSimTime) = 0;
virtual void PostFrame(const double deltaSimTime) = 0;
virtual void EventTraversal(const double deltaSimTime){};
virtual void PreFrame(const double deltaSimTime) = 0;
virtual void Frame(const double deltaSimTime) = 0;
virtual void PostFrame(const double deltaSimTime) = 0;
dtABC::Application类中会实现上面四个接口。上述四个消息都是在帧循环中发出的,是App类必须要处理的消息。另外
virtual void Config(); 转发了System中的Config()消息。并且在跳出应用程序后通过Quit()函数调用System中的Stop()函数
创建的View列表实现如下。
view plaincopy to clipboardprint?
typedef std::vector<dtCore::RefPtr<dtCore::View> >
ViewList; ViewList mViewList;
typedef std::vector<dtCore::RefPtr<dtCore::View> >
ViewList; ViewList mViewList;
通过提供的相应接口实现对View的初始化,并管理View中的场景,需要绘制的对象,摄像机 ,键盘,鼠标。哦 对 还有一个重要的功能忘了说了,那就是在BaseABC中封装了地图的加载功能。
void BaseABC::LoadMap(dtDAL::Map& map, bool addBillBoards)
当然这个地图也是被加到View中Scene里的。其中addBillBoards的含义目前还不清楚 吼吼
关于BaseABC就说到这了,往下是Application。它继承自dtABC::BaseABC和 dtUtil::ConfigProperties的。
其中dtUtil::ConfigProperties只是一个配置属性的接口。
跟上面一样也是先说说Application实现的功能
1 注册键盘和鼠标回调
2 加载App属性列表
3 实现应用程序需要功能
先从教程中的一段小代码往下看你Application怎么运作的
view plaincopy to clipboardprint?
Application *app = new Application("Mydatafile.xml");
app->Config();
app->Run();
Application *app = new Application("Mydatafile.xml");
app->Config();
app->Run();
首先是构造函数
view plaincopy to clipboardprint?
Application::Application(const std::string& configFilename, dtCore::DeltaWin* win) : BaseClass("Application")
, mFirstFrame(true)
, mKeyboardListener(new dtCore::GenericKeyboardListener())
, mMouseListener(new dtCore::GenericMouseListener())
{
//注册该实例 RegisterInstance(this);
//注册回调函数到对应监听器 mKeyboardListener->SetPressedCallback (dtCore::GenericKeyboardListener::CallbackType (this, &Application::KeyPressed));
//…… 剩下七七八八监听注册省略
//配置窗口 mWindow = win;
//创建默认View实例
CreateInstances(); mStats = new dtCore::StatsHandler(*mCompositeViewer);
if (!configFilename.empty())
{ std::string foundPath = dtCore::FindFileInPathList(configFilename);
//读取配置文件
ParseConfigFile(foundPath)
}
}
Application::Application(const std::string& configFilename, dtCore::DeltaWin* win) : BaseClass("Application")
, mFirstFrame(true)
, mKeyboardListener(new dtCore::GenericKeyboardListener())
, mMouseListener(new dtCore::GenericMouseListener())
{
//注册该实例 RegisterInstance(this);
//注册回调函数到对应监听器 mKeyboardListener->SetPressedCallback (dtCore::GenericKeyboardListener::CallbackType (this, &Application::KeyPressed));
//…… 剩下七七八八监听注册省略
//配置窗口 mWindow = win;
//创建默认View实例
CreateInstances(); mStats = new dtCore::StatsHandler(*mCompositeViewer);
if (!configFilename.empty())
{ std::string foundPath = dtCore::FindFileInPathList(configFilename);
//读取配置文件
ParseConfigFile(foundPath)
}
}
其中的CreateInstances()中有
view plaincopy to clipboardprint?
mCompositeViewer = new osgViewer::CompositeViewer;
mCompositeViewer->setUpThreading();
mCompositeViewer->addView(mViewList.front()->GetOsgViewerView()); //连接相关输入和对应监听器 GetKeyboard()->AddKeyboardListener(mKeyboardListener.get()); GetMouse()->AddMouseListener(mMouseListener.get());
mCompositeViewer = new osgViewer::CompositeViewer;
mCompositeViewer->setUpThreading();
mCompositeViewer->addView(mViewList.front()->GetOsgViewerView()); //连接相关输入和对应监听器 GetKeyboard()->AddKeyboardListener(mKeyboardListener.get()); GetMouse()->AddMouseListener(mMouseListener.get());
具体键盘和鼠标是怎么实现监听的没看呢还 关于OSG中的类现在还不了解 就先放在这不管他了 吼吼
构造函数结束后下面就是Config()该函数不只是转发system消息
在此依旧是略过osg相关 在Config()的最后部分有一个ReadSystemProperties()用来读取到的配置数据
在此期间如果发现配置文件中有SIM_FRAME_RATE MAX_TIME_BETWEEN_DRAWS或者USE_FIXED_TIME_STEP则更改System的状态标识位。(Config是在帧循环开始前配置的)
最后是
view plaincopy to clipboardprint?
void Application::Run()
{
dtCore::System::GetInstance().Run();
}
void Application::Run()
{
dtCore::System::GetInstance().Run();
}
从这里可以看出Application首先调用System的Run()函数进入帧循环,然后在根据System在不同阶段发出的消息 调用自身的对应函数来实现当前事件处理,以及渲染任务。这里需要注意的是在osg的frame里面实现了traversals, event, update, and render。但是Delta将traversals移到了EventTraversal(const double deltaSimTime)中
好了关于Application的介绍也就说到这里了。关于这次学习计划主要是弄清楚Delta3d中各个模块之间的关系以及消息传递 函数回调的方法。 至于Application是如何读取xml的我没有细看 反正是一个开源项目...
既然说到这了也就该把dtGame::GameApplication给一起说了. 正如上面所说的到达Application这个层次时,我们仍然没有跟Actor打上交道呢(但是已经有了添加删除DeltaDraw的接口)。而且EntryPoint,Manager等也没有出现。这一切都是在GameApplication中引入的。
view plaincopy to clipboardprint?
class DT_GAME_EXPORT GameApplication: public dtABC::Application
{
DECLARE_MANAGEMENT_LAYER(GameApplication)
public:
GameApplication(int argc, char** argv, const std::string& configFileName = "config.xml", dtCore::DeltaWin* window = NULL);
virtual void Config();
const std::string& GetGameLibraryName() const { return mLibName; }
void SetGameLibraryName(const std::string& newName) { mLibName = newName; }
dtGame::GameManager* GetGameManager() { return mGameManager.get(); }
void SetGameManager(dtGame::GameManager &gameManager);
protected:
virtual ~GameApplication();
private:
};
class DT_GAME_EXPORT GameApplication: public dtABC::Application
{
DECLARE_MANAGEMENT_LAYER(GameApplication)
public:
GameApplication(int argc, char** argv, const std::string& configFileName = "config.xml", dtCore::DeltaWin* window = NULL);
virtual void Config();
const std::string& GetGameLibraryName() const { return mLibName; }
void SetGameLibraryName(const std::string& newName) { mLibName = newName; }
dtGame::GameManager* GetGameManager() { return mGameManager.get(); }
void SetGameManager(dtGame::GameManager &gameManager);
protected:
virtual ~GameApplication();
private:
};
上面是精简过的GameApplication类结构。可以看出来GameApplication只是用来连接GameEntryPoint和App ,其他的实际工作还是由Application完成的,另一边关于角色组件的信息还是由GameEnterPoint来配置,并由GameManager进行管理。
先看一段简单的代码
view plaincopy to clipboardprint?
dtCore::RefPtr<dtGame::GameApplication> app = new dtGame::GameApplication(argc, argv);
app->SetGameLibraryName(std::string(appToLoad));
app->Config();
app->Run();
app = NULL;
dtCore::RefPtr<dtGame::GameApplication> app = new dtGame::GameApplication(argc, argv);
app->SetGameLibraryName(std::string(appToLoad));
app->Config();
app->Run();
app = NULL;
还是按照上面的顺序分析
第一步是构造函数
view plaincopy to clipboardprint?
GameApplication::GameApplication(int argc, char** argv, const std::string& configFileName, dtCore::DeltaWin* window)
: dtABC::Application(configFileName, window)
, mArgc(argc)
, mArgv(argv)
, mEntryPoint(NULL)
, mCreateFunction(NULL)
, mDestroyFunction(NULL)
{
RegisterInstance(this);
//注意 这里取消了Application中默认的键盘回调函数
GetKeyboard()->RemoveKeyboardListener(GetKeyboardListener());
//取消了OSG的默认关闭功能 就是ESC建 要不然Delta3d还没关呢 他就关了不是乱套了嘛
GetCompositeViewer()->setKeyEventSetsDone(0);
}
GameApplication::GameApplication(int argc, char** argv, const std::string& configFileName, dtCore::DeltaWin* window)
: dtABC::Application(configFileName, window)
, mArgc(argc)
, mArgv(argv)
, mEntryPoint(NULL)
, mCreateFunction(NULL)
, mDestroyFunction(NULL)
{
RegisterInstance(this);
//注意 这里取消了Application中默认的键盘回调函数
GetKeyboard()->RemoveKeyboardListener(GetKeyboardListener());
//取消了OSG的默认关闭功能 就是ESC建 要不然Delta3d还没关呢 他就关了不是乱套了嘛
GetCompositeViewer()->setKeyEventSetsDone(0);
}
第二步就是设置要读取的角色库名称(这一步必须在配置之前完成)
第三步是对GameApplication进行配置 这里面的内容比较多 把异常处理部分去掉 挑主要的说了
view plaincopy to clipboardprint?
void GameApplication::Config()
{
dtUtil::LibrarySharingManager& lsm = dtUtil::LibrarySharingManager::GetInstance();
std::string libName = GetGameLibraryName();
//获得要启动的角色库
mEntryPointLib = lsm.LoadSharedLibrary(libName);
//获得进入点
dtUtil::LibrarySharingManager::LibraryHandle::SYMBOL_ADDRESS createAddr;
dtUtil::LibrarySharingManager::LibraryHandle::SYMBOL_ADDRESS destroyAddr;
createAddr = mEntryPointLib->FindSymbol("CreateGameEntryPoint");
destroyAddr = mEntryPointLib->FindSymbol("DestroyGameEntryPoint");
#if (__GNUC__ == 3 && __GNUC_MINOR__ <= 4)
mCreateFunction = (CreateEntryPointFn)createAddr;
mDestroyFunction = (DestroyEntryPointFn)destroyAddr;
#else
mCreateFunction = reinterpret_cast<CreateEntryPointFn>(createAddr);
mDestroyFunction = reinterpret_cast<DestroyEntryPointFn>(destroyAddr);
#endif
mEntryPoint = mCreateFunction();
//创建游戏管理器
mGameManager = new dtGame::GameManager( *GetScene() );
mEntryPoint->Initialize(*this, mArgc, mArgv);
//此时才开始进行Application的默认配置(根据配置文件名称配置)
Application::Config();
mGameManager->SetApplication(*this);
mEntryPoint->OnStartup(*this);
}
}
void GameApplication::Config()
{
dtUtil::LibrarySharingManager& lsm = dtUtil::LibrarySharingManager::GetInstance();
std::string libName = GetGameLibraryName();
//获得要启动的角色库
mEntryPointLib = lsm.LoadSharedLibrary(libName);
//获得进入点
dtUtil::LibrarySharingManager::LibraryHandle::SYMBOL_ADDRESS createAddr;
dtUtil::LibrarySharingManager::LibraryHandle::SYMBOL_ADDRESS destroyAddr;
createAddr = mEntryPointLib->FindSymbol("CreateGameEntryPoint");
destroyAddr = mEntryPointLib->FindSymbol("DestroyGameEntryPoint");
#if (__GNUC__ == 3 && __GNUC_MINOR__ <= 4)
mCreateFunction = (CreateEntryPointFn)createAddr;
mDestroyFunction = (DestroyEntryPointFn)destroyAddr;
#else
mCreateFunction = reinterpret_cast<CreateEntryPointFn>(createAddr);
mDestroyFunction = reinterpret_cast<DestroyEntryPointFn>(destroyAddr);
#endif
mEntryPoint = mCreateFunction();
//创建游戏管理器
mGameManager = new dtGame::GameManager( *GetScene() );
mEntryPoint->Initialize(*this, mArgc, mArgv);
//此时才开始进行Application的默认配置(根据配置文件名称配置)
Application::Config();
mGameManager->SetApplication(*this);
mEntryPoint->OnStartup(*this);
}
}
在这里随便提一下上面调用的GameEnteryPoint中的两个函数
1. Initialize() 读取命令行参数。也就是说在这里你可以根据需要配置相应启动参数。并且在Initialize()中你可以做一些配置工作开始前所需要的其他操作。在这里不要做任何与GM有关的工作(上面的源码已经告诉我们了,GM还没被创建呢)。你可以根据需要来重写这个函数。
2. OnStartUp() 在这里你的程序要开始运行了!创建你的所有组件,加载地图以及做其他所有的工作去启动你的游戏。这是在进入你自己的游戏循环开始前最后一个要被调用的函数。这个函数是一定需要的!
再往下的Run()就是调用Application的Run()函数。上面已经说过了。
OK这就把delta3d中的这几个app类都说完了,下一步就开始看GameManager的实现了,看看各个组件和角色到底是怎么联系到一起去的。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/sxy0082002/archive/2009/06/30/4311020.aspx