OGRE+CEGUI游戏教程(3)----角色创建

转载请注明出处:http://blog.csdn.net/pizzazhang

  源码和可执行程序链接http://code.google.com/p/pizzaprojects/downloads/list  

 

这次主要做了一个角色创建的小Demo。 用了火炬之光里面的图片资源(谁让这个游戏是用Ogre开发的呢,大爱)。

  •   使用了 CEGUI的ImageButton
  •   使用了文本窗口的一些特殊属性
  •   使用了输入框输入英文(暂时不支持输入法)。

效果图:选择角色, 第一个头像图片是鼠标移动上去的效果。

第二个头像图片是鼠标点击后的效果


点击头像后,会有人物出现。人物会原地播放动画。 当在输入框中输入名字的时候, 会出现开始按钮。 如果删除掉名字, 开始按钮消失。


开始游戏后,载入另一个UI


这是选择另一个人物后载入的UI

 

整体动态效果图:

下面是实现过程。

先把代码贴上:

Main.cpp

[cpp]  view plain copy
  1. #include "MyGUISystem.h"  
  2. #include "BaseApplication.h"  
  3. using namespace Ogre;  
  4. class Demo : public BaseApplication  
  5. {  
  6.     enum CharaType  
  7.     {  
  8.         CHARA_A,  
  9.         ChARA_B,  
  10.         CHARA_C  
  11.     };  
  12. public:  
  13.     Demo()  
  14.         :mCharaAnimState1(0), mCharaAnimState2(0)  
  15.     {   }  
  16.     virtual ~Demo()  
  17.     {   }  
  18.     bool frameRenderingQueued(const Ogre::FrameEvent& evt)  
  19.     {  
  20.         if(mShutDown)  
  21.             return false;  
  22.         //这里需要update否则Tooltip不会显示  
  23.         MyGUISystem::getSingletonPtr()->update(evt.timeSinceLastFrame);  
  24.         //这里需要addTime才能使动画动起来  
  25.         if(mCharaAnimState1)  
  26.             mCharaAnimState1->addTime(evt.timeSinceLastFrame);  
  27.         if(mCharaAnimState2)  
  28.             mCharaAnimState2->addTime(evt.timeSinceLastFrame);  
  29.         return BaseApplication::frameRenderingQueued(evt);  
  30.     }  
  31.     void createScene()  
  32.     {  
  33.         mCharaNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();  
  34.         mCharaEntA = mSceneMgr->createEntity("sinbad""sinbad.mesh");  
  35.         mCharaEntB = mSceneMgr->createEntity("jaiqua""jaiqua.mesh");  
  36.         mCharaEntC = mSceneMgr->createEntity("ninja""ninja.mesh");  
  37.         createParticle();  
  38.         setupGUI();  
  39.     }  
  40.     void setupGUI()  
  41.     {  
  42.         MyGUISystem::getSingletonPtr()->init();  
  43.         //角色图片按钮的Imageset创建  
  44.         CEGUI::ImagesetManager::getSingleton().create("chara_image.imageset");  
  45.         //载入角色创建窗口  
  46.         MyGUISystem::getSingletonPtr()->loadLayout("CharaCreateWindow");  
  47.         MyGUISystem::getSingletonPtr()->getWindow("StartBtn")->hide();  
  48.         //创建图片资源  
  49.         MyGUISystem::createImageset("CharaIntroA""chara_introa.tga");  
  50.         MyGUISystem::createImageset("CharaIntroB""chara_introb.tga");  
  51.         MyGUISystem::createImageset("CharaIntroC""chara_introc.tga");  
  52.         //从XML载入动画  
  53.         CEGUI::AnimationManager::getSingleton().loadAnimationsFromXML("Intro_Anim.xml");  
  54.         createGUIEvent();  
  55.     }  
  56.     void createGUIEvent()  
  57.     {  
  58.         MyGUISystem::subscribeEvent("CharaImgBtnA", CEGUI::PushButton::EventClicked,   
  59.             CEGUI::Event::Subscriber(&Demo::charaSelctedHandler, this));  
  60.         MyGUISystem::subscribeEvent("CharaImgBtnB", CEGUI::PushButton::EventClicked,   
  61.             CEGUI::Event::Subscriber(&Demo::charaSelctedHandler, this));  
  62.         MyGUISystem::subscribeEvent("CharaImgBtnC", CEGUI::PushButton::EventClicked,   
  63.             CEGUI::Event::Subscriber(&Demo::charaSelctedHandler, this));  
  64.         //当输入框中的文本变化时触发的事件  
  65.         MyGUISystem::subscribeEvent("NameInputbox", CEGUI::Editbox::EventTextChanged,  
  66.             CEGUI::Event::Subscriber(&Demo::inputAcceptedHandler, this));  
  67.         MyGUISystem::subscribeEvent("StartBtn", CEGUI::PushButton::EventClicked,  
  68.             CEGUI::Event::Subscriber(&Demo::startHandler, this));  
  69.     }  
  70.     void createLight()  
  71.     {  
  72.         mSceneMgr->setAmbientLight(ColourValue(0.3, 0.3, 0.3));  
  73.         mSceneMgr->createLight()->setPosition(20, 80, 50);  
  74.     }  
  75.     void createParticle()  
  76.     {  
  77.         //创建一个粒子系统  
  78.         Ogre::ParticleSystem* particle = mSceneMgr->createParticleSystem("chara_particle""chara_particle");  
  79.         Ogre::SceneNode* particleNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();  
  80.         particleNode->attachObject(particle);  
  81.         particleNode->setPosition(0, -25, 0);  
  82.     }  
  83.     void createChara(CharaType charaType)  
  84.     {  
  85.         //因为只用一个场景节点绑定个对象,所以这里要重置所有位置、方位和缩放参数  
  86.         mCharaNode->detachAllObjects();  
  87.         mCharaNode->resetOrientation();  
  88.         mCharaNode->setPosition(0, 0, 0);  
  89.         mCharaNode->setScale(1, 1, 1);  
  90.         //根据角色类型创建角色,并设定参数使得正好在屏幕中间出现。大小适中。  
  91.         switch(charaType)  
  92.         {  
  93.         case CHARA_A:  
  94.             mCharaType = CHARA_A;  
  95.             mCharaNode->attachObject(mCharaEntA);  
  96.             mCharaNode->setScale(3, 3, 3);  
  97.             //sinbad有上下2部分的Idle动画,所以这里分开使用  
  98.             mCharaAnimState1 = mCharaEntA->getAnimationState("IdleBase");  
  99.             mCharaAnimState2 = mCharaEntA->getAnimationState("IdleTop");  
  100.             mCharaAnimState2->setLoop(true);  
  101.             mCharaAnimState2->setEnabled(true);  
  102.             break;  
  103.         case ChARA_B:  
  104.             mCharaType = ChARA_B;  
  105.             mCharaNode->attachObject(mCharaEntB);  
  106.             mCharaNode->setScale(2, 2, 2);  
  107.             mCharaNode->setPosition(0, -15, 0);  
  108.             mCharaNode->yaw(Ogre::Degree(180));  
  109.             mCharaAnimState1 = mCharaEntB->getAnimationState("Turn");  
  110.             mCharaAnimState2 = 0;  
  111.             break;  
  112.         case CHARA_C:  
  113.             mCharaType = CHARA_C;  
  114.             mCharaNode->attachObject(mCharaEntC);  
  115.             mCharaNode->setScale(0.2, 0.2, 0.2);  
  116.             mCharaNode->setPosition(0, -15, 0);  
  117.             mCharaNode->yaw(Ogre::Degree(180));  
  118.             mCharaAnimState1 = mCharaEntC->getAnimationState("Idle3");  
  119.             mCharaAnimState2 = 0;  
  120.             break;  
  121.         }  
  122.         if(mCharaAnimState1)  
  123.         {  
  124.             mCharaAnimState1->setLoop(true);  
  125.             mCharaAnimState1->setEnabled(true);  
  126.         }  
  127.     }  
  128. private:  
  129.     bool charaSelctedHandler(const CEGUI::EventArgs& e)  
  130.     {  
  131.         //根据参数e得到获得事件的窗口  
  132.         const CEGUI::WindowEventArgs& windowArgs = static_cast<const CEGUI::WindowEventArgs&>(e);  
  133.         CEGUI::String charaType = windowArgs.window->getName();  
  134.         CEGUI::String charaDetail;  
  135.         if(charaType == "CharaImgBtnA")  
  136.         {  
  137.             charaDetail = (CEGUI::utf8*)Ogre::UTFString(L"哦,朋友,我是厉害的Sinbad战士。我帅不?").asUTF8_c_str();  
  138.             createChara(CHARA_A);  
  139.         }  
  140.         if(charaType == "CharaImgBtnB")  
  141.         {  
  142.             charaDetail = (CEGUI::utf8*)Ogre::UTFString(L"别看我是女人,我是很厉害的神箭手哦:)").asUTF8_c_str();  
  143.             createChara(ChARA_B);  
  144.         }  
  145.         if(charaType == "CharaImgBtnC")  
  146.         {  
  147.             charaDetail = (CEGUI::utf8*)Ogre::UTFString(L"别看我是忍者,其实我是大法师,只是/n伪装成忍者= =!").asUTF8_c_str();  
  148.             createChara(CHARA_C);  
  149.         }  
  150.         MyGUISystem::getSingletonPtr()->getWindow("CharaDetailText")->setText(charaDetail);  
  151.         return true;  
  152.     }  
  153.     bool startHandler(const CEGUI::EventArgs& e)  
  154.     {  
  155.         //清理工作  
  156.         mSceneMgr->clearScene();  
  157.         //这里需要清除指针,否则退出会有错误  
  158.         mCharaAnimState1 = mCharaAnimState2 = 0;  
  159.         //场景开始,载入介绍GUI  
  160.         MyGUISystem::getSingletonPtr()->loadLayout("IntroWindow");  
  161.         switch(mCharaType)  
  162.         {  
  163.         case CHARA_A:  
  164.             MyGUISystem::setProperty("IntroTopImg""Image""set:CharaIntroA image:full_image");  
  165.             break;  
  166.         case ChARA_B:  
  167.             MyGUISystem::setProperty("IntroTopImg""Image""set:CharaIntroB image:full_image");  
  168.             break;  
  169.         case CHARA_C:  
  170.             MyGUISystem::setProperty("IntroTopImg""Image""set:CharaIntroC image:full_image");  
  171.             break;  
  172.         }  
  173.         //介绍文本  
  174.         CEGUI::String str = (CEGUI::utf8*)Ogre::UTFString(L"很久很久以前......").asUTF8_c_str();  
  175.         MyGUISystem::getSingletonPtr()->getWindow("IntroText")->setText(str);  
  176.         //得到动画  
  177.         CEGUI::Animation* anim = CEGUI::AnimationManager::getSingleton().getAnimation("IntroAnim");  
  178.         //实例化动画  
  179.         CEGUI::AnimationInstance* inst = CEGUI::AnimationManager::getSingleton().instantiateAnimation(anim);  
  180.         //动画的应用窗口  
  181.         inst->setTargetWindow(MyGUISystem::getSingletonPtr()->getWindow("IntroText"));  
  182.         //动画开始  
  183.         inst->start();  
  184.         return true;  
  185.     }  
  186.     bool inputAcceptedHandler(const CEGUI::EventArgs& e)  
  187.     {  
  188.         mCharaName = MyGUISystem::getSingletonPtr()->getWindow("NameInputbox")->getText().c_str();  
  189.         if(mCharaName !=  "")  
  190.         {  
  191.             //如果输入框有文本的话,显示开始按钮  
  192.             MyGUISystem::getSingletonPtr()->getWindow("StartBtn")->show();  
  193.         }else  
  194.         {  
  195.             //否则隐藏按钮  
  196.             MyGUISystem::getSingletonPtr()->getWindow("StartBtn")->hide();  
  197.         }  
  198.         return true;  
  199.     }  
  200.     bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )  
  201.     {  
  202.         MyGUISystem::getSingletonPtr()->injectMouseButtonDown(MyGUISystem::convertButton(id));  
  203.         return true;  
  204.     }  
  205.     bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )  
  206.     {  
  207.         MyGUISystem::getSingletonPtr()->injectMouseButtonUp(MyGUISystem::convertButton(id));  
  208.         return true;  
  209.     }  
  210.     bool mouseMoved( const OIS::MouseEvent &arg )  
  211.     {  
  212.         MyGUISystem::getSingletonPtr()->injectMouseMove(arg.state.X.rel, arg.state.Y.rel);  
  213.         return true;  
  214.     }  
  215.     //这里需要注入keychar和键盘事件才能在Editbox中输入字符(不接受输入法)  
  216.     bool keyPressed( const OIS::KeyEvent &arg )  
  217.     {  
  218.         CEGUI::System::getSingleton().injectKeyDown(arg.key);  
  219.         CEGUI::System::getSingleton().injectChar(arg.text);  
  220.         if(arg.key == OIS::KC_ESCAPE)  
  221.             mShutDown = true;  
  222.         return true;  
  223.     }  
  224.     bool keyReleased( const OIS::KeyEvent &arg )  
  225.     {  
  226.         CEGUI::System::getSingleton().injectKeyUp(arg.key);  
  227.         return true;  
  228.     }  
  229. private:  
  230.     Ogre::String            mCharaName;             //角色名字  
  231.     Ogre::Entity*           mCharaEntA;             //角色A  
  232.     Ogre::Entity*           mCharaEntB;             //角色B  
  233.     Ogre::Entity*           mCharaEntC;             //角色C  
  234.     Ogre::SceneNode*        mCharaNode;             //角色节点  
  235.     Ogre::AnimationState*   mCharaAnimState1;       //角色动画状态  
  236.     Ogre::AnimationState*   mCharaAnimState2;       //备用角色动画状态  
  237.     CharaType               mCharaType;             //保存选择的角色类型  
  238. };  
  239. INT WINAPI WinMain(HINSTANCEHINSTANCELPSTRINT)  
  240. {  
  241.     Demo demo;  
  242.     try  
  243.     {  
  244.         demo.go();  
  245.     }  
  246.     catch(Ogre::Exception& e)  
  247.     {  
  248.         MessageBox(0, e.getFullDescription().c_str(), "Exception", MB_OK);  
  249.     }  
  250. }  

代码没有什么特别的解释。 这个Demo的实现主要是CEGUI的ImageButton的使用。

首先, 使用官方的Imageset编辑器对一张图片进行编辑,实际操作也就是把一张图片进行切片。 每个部分都在一个文件中定义一个UV坐标。这个Demo里使用的Imageset文件如下:

[html]  view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <Imageset Name="CharaImageset" Imagefile="./logo.tga" >  
  3.     <Image Name="Logo" XPos="208" YPos="0" Width="608" Height="146" />  
  4.     <Image Name="HoverA" XPos="0" YPos="553" Width="128" Height="128" />  
  5.     <Image Name="HoverB" XPos="129" YPos="553" Width="128" Height="128" />  
  6.     <Image Name="HoverC" XPos="256" YPos="552" Width="128" Height="128" />  
  7.     <Image Name="NormalA" XPos="0" YPos="424" Width="128" Height="128" />  
  8.     <Image Name="NormalB" XPos="129" YPos="424" Width="128" Height="128" />  
  9.     <Image Name="NormalC" XPos="257" YPos="425" Width="128" Height="128" />  
  10.     <Image Name="PushedA" XPos="1" YPos="682" Width="128" Height="128" />  
  11.     <Image Name="PushedB" XPos="129" YPos="682" Width="128" Height="128" />  
  12.     <Image Name="PushedC" XPos="256" YPos="681" Width="128" Height="128" />  
  13.     <Image Name="HoverStart" XPos="255" YPos="255" Width="125" Height="50" />  
  14.     <Image Name="NormalStart" XPos="252" YPos="255" Width="125" Height="50" />  
  15.     <Image Name="PushedStart" XPos="252" YPos="255" Width="125" Height="50" />  
  16.     <Image Name="Intro_Bottom" XPos="2" YPos="334" Width="1006" Height="90" />  
  17. </Imageset>  

接下来就是在Layout文件中使用这个Imageset的各个图片资源了。

火炬之光里的创建角色的角色按钮使用的是RadioButton, 由于ImageButton在游戏里用的最多,所以我打算用ImageButton实现角色选择的按钮。

下面展示Layout文件中某一个ImageButton的使用:

[html]  view plain copy
  1. <Window Type="TaharezLook/ImageButton" Name="CharaImgBtnA" >  
  2.     <Property Name="Font" Value="SimHei-14" />  
  3.     <Property Name="Tooltip" Value="杩欐槸瑙掕壊A" />  
  4.     <Property Name="HoverImage" Value="set:CharaImageset image:HoverA" />  
  5.     <Property Name="NormalImage" Value="set:CharaImageset image:NormalA" />  
  6.     <Property Name="PushedImage" Value="set:CharaImageset image:PushedA" />  
  7.     <Property Name="UnifiedAreaRect" Value="{{0.14953,0},{0.0922273,0},{0.252194,0},{0.289911,0}}" />  
  8.     <Window Type="TaharezLook/StaticText" Name="CharaTextA" >  
  9.       <Property Name="Font" Value="SimHei-14" />  
  10.       <Property Name="Text" Value="瑙掕壊A" />  
  11.       <Property Name="HorzExtent" Value="58" />  
  12.       <Property Name="VertExtent" Value="16.25" />  
  13.       <Property Name="TextColours" Value="tl:FF0000FF tr:FF0000FF bl:FF0000FF br:FF0000FF" />  
  14.       <Property Name="FrameEnabled" Value="False" />  
  15.       <Property Name="HorzFormatting" Value="HorzCentred" />  
  16.       <Property Name="UnifiedAreaRect" Value="{{0.00228956,0},{-0.0175811,0},{1.00038,0},{0.97344,0}}" />  
  17.       <Property Name="BackgroundEnabled" Value="False" />  
  18.       <Property Name="MousePassThroughEnabled" Value="True" />  
  19.     </Window>  
  20.   </Window>  

先定义一个ImageButton, 然后设置它的属性:

HoverImage: 鼠标移到上面的时候显示的图片

NormalImage: 平常时候显示的图片

PushedImage: 鼠标点击后显示的图片

 

Tooltip是鼠标停留在这个控件上一段时间后出现的提示文本。

 

以这个ImageButton为父窗口,建立一个StaticText, 这个文本窗口我们是用来显示按钮的文字的。由于ImageButton不能直接定义文本,要么通过图片直接绘制文本,要么在它上面建立一个文本窗口。

文本窗口既然在ImageButton上面,那么就需要对它设置一些特殊属性,否则我们点击ImageButton就得不到响应。

 

首先去除文本窗口的  Background和Frame, 就是背景和边框。

然后要使底下的ImageButton响应操作,需要设置上面的窗口MousePassThroughEnabled属性为True。 这个属性会忽略设置窗口的鼠标操作而传递到下面的控件。

 

在Main.cpp代码中, 使用EventTextChanged来响应文本的输入变化。 如果文本框里的文本变化了(即玩家输入了名字)那么开始按钮就会出现。 对Window调用show()和hide()就可以控制窗口的显示与否。

 

当选择了一个角色后,场景中间会建立一个人物实体。 可以只用一个场景节点来实现角色的切换的效果。只有当一个实体依附(attach)在一个节点时,场景中才会绘制出这个实体。所以我们建立3个人物的实体, 需要显示某个的时候Attach就行。

 

最后把这个例子中所需要的资源(layout、 imageset、animationXML文件以及材质、纹理图片等)放入Ogre可以定位的路径下。 比如就放在exe的目录中, 然后在resource配置中在一个资源组中添加 FileSystem=./

 

希望本文对你有所帮助。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CEGUI(Crazy Eddie’s GUI http://www.cegui.org.uk)是一个自由免费的GUI库,基于LGPL协议,使用C++实现,完全面向对象设计。CEGUI开发者的目的是希望能够让游戏开发人员从繁琐的GUI实现细节中抽身出来,以便有更多的开发时间可以放在游戏性上。 CEGUI的渲染需要3D图形API的支持,如OpenGL或Direct3D。另外,使用更高级的图形库也是可以的,比如OGRE、Irrlicht和RenderWare等,关键需求可以简化为二点: 纹理(Texture)的支持直接写屏(RHW的顶点格式、正交投影、或者使用shader实现) 本书截止日时,CEGUI的最新版本是0.6.0(本书的讨论也是基于此版本),本书光盘提供了SDK和全部源码的下载。 除此之外,CEGUI还同步提供了官方界面编辑器LayoutEditor和ImageSet编辑器,以方便UI和图像集的制作。作为界面编辑器,它需要系统级界面以提供编辑器操作,0.3.0版是基于MFC实现的;而在0.4.0版本以后,改为基于wxWidgets(跨平台的本地UI框架,这里的UI指Window操作系统底层,如:Windows、Unix和Mac,详见http://www.wxwidgets.org)实现。 目前将CEGUI作为游戏界面库开发的游戏已经有好多种,国内的天龙八部,巨人等游戏就是很好的例子。 CEGUI的功能是非常强大的,而且使用也非常的灵活,可以和脚本配合。可以通过配置文件自定义窗口外观。通过布局文件实现窗口布局等等特性,使得游戏的界面开发更加方便。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值