Delta3D学习之App类

 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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值