OGRE+CEGUI游戏教程(5)--物品/装备和技能系统
2011-10-30 02:56
387 查看
转载请注明出处:http://blog.csdn.net/pizzazhang
源码和可执行程序链接http://code.google.com/p/pizzaprojects/downloads/list
一般游戏只要是类RPG的,都会有一套装备/物品系统,还有技能系统。 玩火炬之光的同时,我在想它的装备/物品系统和技能系统是如何实现的。 由于火炬之光使用的是CEGUI, 所以我找到它的ui文件, 发现它的技能系统使用的是一个layout文件,但鼠标移到技能上的时候,有点像一个Tooltip渐入,然后显示(带图片和字体),鼠标移开后又消失。感觉上非常像一个Tooltip。
如果是纯粹的一个layout进行显示/隐藏的话,那么每个物品/装备/技能栏都需要注册一个MouseEnterArea事件,而且这个layout必须得到这些槽绑定的物品/技能对象的数据。
如果是Tooltip的话,必须自己重写Tooltip系统,让Tooltip的调用改用layout而不是固有的LookNFeel中的Tooltip样式。
由于重写一个Tootip对于我来说还是有些难度的,所以我询问了CEGUI论坛的“大牛”们,得到了一种不错的解决方案:
http://www.cegui.org.uk/phpBB2/viewtopic.php?f=10&t=5549
下面是运用这种方法得到的效果图:
这里是一个简单的示范,基本的功能是:
鼠标Hover到一个槽中的时候,显示这个槽附带物品/技能的说明,并且可以使用中文。
点击装备的时候,装备可以附加到正确的装备槽中。
那么如何实现呢?对于显示带图片和颜色字体的Tooltip的话,上面那个CEGUI论坛链接有详细的说明, 先看下我根据他的思想写的代码:
使用一个stringstream来对Tooltip的文本进行加工,需要图片的地方就加入图片的tag, 需要颜色的地方加入colour的tag。
如果需要在Tooltip中加入中文,那么你需要一个CEGUI::String字串对象,然后在设置Tooltip文本的时候,把这个字串对象转换成CEGUI::utf8文本。 当然转换中文后显示会变慢 = =
对于图片的显示,需要更改LookNFeel中的Tooltip的Colour Range,在ImagerySection Name="label“的地方,把颜色值调成白色
如何把对应槽和物品/装备等联系起来呢?我想到的一种方法是使用UserString来进行通信。
首先我们需要一个Item和Skill类来封装我们的物品和技能的属性:
技能的话差不多, 不过基本上只需要设置技能等级,然后技能的消耗和伤害等根据公式计算:
Skill(const CEGUI::String& name)
{
mName = name;
mLevel = 1;
mCost = 100;
mDamage = 1000;
}
接下来就是在逻辑地方调用了它们了。 在上面的代码中,我使用了一个vector来保存需要使用的物品和技能,当然你需要更复杂的管理系统,就像对象工厂那样的系统。
在Tooltip的显示中,使用传递进去的Item或者Skill来动态的加载物品或装备的信息。
当装备一件装备时,为了能让它到特定的槽中, 我们可以传递一个UserString来通信:
然后注册一个点击事件,对应的响应方法:
bool onEquip(const CEGUI::EventArgs& args)
{
const CEGUI::WindowEventArgs& WindowArgs = static_cast<const CEGUI::WindowEventArgs&>(args);
if(WindowArgs.window->getUserString("type") == "Weapon")
{
//得到User字串传递过来的信息来进行操作
CEGUI::Window* invBottom = MyGUISystem::getSingletonPtr()->getWindow("InventoryBottom");
//从当前槽中移除
invBottom->removeChildWindow(WindowArgs.window);
CEGUI::Window* invTop = MyGUISystem::getSingletonPtr()->getWindow("InventoryTop");
//加入到装备栏的槽中
invTop->getChild(0)->addChildWindow(WindowArgs.window);
//重新设定位置和大小(相对)
WindowArgs.window->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0), CEGUI::UDim(0, 0)));
WindowArgs.window->setSize(CEGUI::UVector2(CEGUI::UDim(1, 0), CEGUI::UDim(1, 0)));
}
return true;
}
先从当前槽中移除物品绑定的窗口对象,然后根据传递过来的UserString来判断应该放在哪个槽中,对后把它加入这个槽窗口中并重置位置和大小。
对于一个复杂的装备/物品和技能系统,远不止这些。我只是一个示范,而且是在CEGUI+OGRE这个环境中。所以希望对研究Ogre和CEGUI的同学有帮助,同时希望有更好方案的同学提出意见,共同进步。
源码和可执行程序链接http://code.google.com/p/pizzaprojects/downloads/list
一般游戏只要是类RPG的,都会有一套装备/物品系统,还有技能系统。 玩火炬之光的同时,我在想它的装备/物品系统和技能系统是如何实现的。 由于火炬之光使用的是CEGUI, 所以我找到它的ui文件, 发现它的技能系统使用的是一个layout文件,但鼠标移到技能上的时候,有点像一个Tooltip渐入,然后显示(带图片和字体),鼠标移开后又消失。感觉上非常像一个Tooltip。
如果是纯粹的一个layout进行显示/隐藏的话,那么每个物品/装备/技能栏都需要注册一个MouseEnterArea事件,而且这个layout必须得到这些槽绑定的物品/技能对象的数据。
如果是Tooltip的话,必须自己重写Tooltip系统,让Tooltip的调用改用layout而不是固有的LookNFeel中的Tooltip样式。
由于重写一个Tootip对于我来说还是有些难度的,所以我询问了CEGUI论坛的“大牛”们,得到了一种不错的解决方案:
http://www.cegui.org.uk/phpBB2/viewtopic.php?f=10&t=5549
下面是运用这种方法得到的效果图:
这里是一个简单的示范,基本的功能是:
鼠标Hover到一个槽中的时候,显示这个槽附带物品/技能的说明,并且可以使用中文。
点击装备的时候,装备可以附加到正确的装备槽中。
那么如何实现呢?对于显示带图片和颜色字体的Tooltip的话,上面那个CEGUI论坛链接有详细的说明, 先看下我根据他的思想写的代码:
#include "BaseApplication.h" #include "MyGUISystem.h" #include "Item.h" #include "Skill.h" #include <vector> class Demo : public BaseApplication { public: bool frameRenderingQueued(const Ogre::FrameEvent& evt) { if(mShutDown) return false; //这里需要update否则Tooltip不会显示 MyGUISystem::getSingletonPtr()->update(evt.timeSinceLastFrame); return BaseApplication::frameRenderingQueued(evt); } void createScene() { createItems(); createSkills(); setupGUI(); } void setupGUI() { MyGUISystem::getSingletonPtr()->init(); //创建图片资源 CEGUI::ImagesetManager::getSingleton().create("items2.imageset"); CEGUI::ImagesetManager::getSingleton().create("skill.imageset"); MyGUISystem::getSingletonPtr()->loadLayout("GameUI"); createGUIEvents(); CEGUI::Window* itemWidget = MyGUISystem::getSingletonPtr()->getWindow("InvBottomSlot1"); //这里传递一个User字串映射来装备到特定槽中 itemWidget->setUserString("type", "Weapon"); //格式化信息 formatInvTooltip(itemWidget, mItems[0]); CEGUI::Window* skillWidget = MyGUISystem::getSingletonPtr()->getWindow("SkillSlot1"); formatSkillTooltip(skillWidget, mSkills[0]); } void createGUIEvents() { MyGUISystem::subscribeEvent("InvBottomSlot1", CEGUI::Window::EventMouseClick, CEGUI::Event::Subscriber(&Demo::onEquip, this)); } bool onEquip(const CEGUI::EventArgs& args) { const CEGUI::WindowEventArgs& WindowArgs = static_cast<const CEGUI::WindowEventArgs&>(args); if(WindowArgs.window->getUserString("type") == "Weapon") { //得到User字串传递过来的信息来进行操作 CEGUI::Window* invBottom = MyGUISystem::getSingletonPtr()->getWindow("InventoryBottom"); //从当前槽中移除 invBottom->removeChildWindow(WindowArgs.window); CEGUI::Window* invTop = MyGUISystem::getSingletonPtr()->getWindow("InventoryTop"); //加入到装备栏的槽中 invTop->getChild(0)->addChildWindow(WindowArgs.window); //重新设定位置和大小(相对) WindowArgs.window->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0), CEGUI::UDim(0, 0))); WindowArgs.window->setSize(CEGUI::UVector2(CEGUI::UDim(1, 0), CEGUI::UDim(1, 0))); } return true; } //创建我们需要的物品,保存在一个向量中 void createItems() { Item* item = new Item("Item21", "Weapon"); item->setDesc("A Nice Weapon!"); item->setIconName("set:items2 image:item21"); item->setCost("3000"); item->setTechLevel("14"); mItems.push_back(item); } //创建技能,保存在一个向量中 void createSkills() { Skill* skill = new Skill((CEGUI::utf8*)Ogre::UTFString(L"火球术").asUTF8_c_str()); skill->setDesc((CEGUI::utf8*)Ogre::UTFString(L"发射一颗巨大的火球冲向敌人").asUTF8_c_str()); skill->setLevel(4); skill->setIconName("set:skill image:skill1"); mSkills.push_back(skill); } //格式化信息提示:使用字串流加入图片、字体等来格式化 void formatInvTooltip(CEGUI::Window* window, Item* item) { std::stringstream ssTooltip; ssTooltip <<"[font='SimHei-14'][colour='FF0000FF']"<<item->getName()<<std::endl <<"[top-padding='5'][bottom-padding='10'][image-width='60'][image-height='90'][colour='FFFFFFFF'][image='" <<item->getIconName()<<"']"<<std::endl <<"------------------------"<<std::endl <<"[top-padding='0'][bottom-padding='0'][font='SimHei-14'][colour='FF00FFFF']" << item->getDesc() << std::endl <<"------------------------"<<std::endl <<"Tech Level: " << item->getTechLevel() << std::endl <<"------------------------"<<std::endl <<"Cost: "<<item->getCost()<<std::endl; //简单地设置TooltipText就可以获得图片和字体的效果 window->setTooltipText(ssTooltip.str()); } //格式化技能提示,同物品信息提示的格式化操作 void formatSkillTooltip(CEGUI::Window* window, Skill* skill) { std::stringstream ssTooltip; ssTooltip <<"[font='SimHei-14'][colour='FFFFFF00']"<<skill->getName()<<std::endl <<"[top-padding='5'][bottom-padding='10'][image-width='80'][image-height='80'][colour='FFFFFFFF'][image='" <<skill->getIconName()<<"']"<<std::endl <<"------------------------"<<std::endl <<"[top-padding='0'][bottom-padding='0'][font='SimHei-14'][colour='FF00FF00']" << skill->getDesc() << std::endl <<"------------------------"<<std::endl <<(CEGUI::utf8*)Ogre::UTFString(L"技能等级: ").asUTF8_c_str()<< skill->getLevel() << std::endl <<"------------------------"<<std::endl <<(CEGUI::utf8*)Ogre::UTFString(L"技能消耗: ").asUTF8_c_str()<<skill->getCost()<<std::endl <<"------------------------"<<std::endl <<(CEGUI::utf8*)Ogre::UTFString(L"技能伤害:").asUTF8_c_str()<<skill->getDamage()<<std::endl; //简单地设置TooltipText就可以获得图片和字体的效果 window->setTooltipText((CEGUI::utf8*)ssTooltip.str().c_str()); } private: bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) { MyGUISystem::getSingletonPtr()->injectMouseButtonDown(MyGUISystem::convertButton(id)); return true; } bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) { MyGUISystem::getSingletonPtr()->injectMouseButtonUp(MyGUISystem::convertButton(id)); return true; } bool mouseMoved( const OIS::MouseEvent &arg ) { MyGUISystem::getSingletonPtr()->injectMouseMove(arg.state.X.rel, arg.state.Y.rel); return true; } bool keyPressed( const OIS::KeyEvent &arg ) { CEGUI::System::getSingleton().injectKeyDown(arg.key); CEGUI::System::getSingleton().injectChar(arg.text); if(arg.key == OIS::KC_ESCAPE) mShutDown = true; return true; } bool keyReleased( const OIS::KeyEvent &arg ) { CEGUI::System::getSingleton().injectKeyUp(arg.key); return true; } private: std::vector<Item*> mItems; std::vector<Skill*> mSkills; }; INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT) { try { Demo demo; demo.go(); } catch(Ogre::Exception& e) { MessageBox(0, e.getFullDescription().c_str(), "Exception", MB_OK); } }
使用一个stringstream来对Tooltip的文本进行加工,需要图片的地方就加入图片的tag, 需要颜色的地方加入colour的tag。
如果需要在Tooltip中加入中文,那么你需要一个CEGUI::String字串对象,然后在设置Tooltip文本的时候,把这个字串对象转换成CEGUI::utf8文本。 当然转换中文后显示会变慢 = =
对于图片的显示,需要更改LookNFeel中的Tooltip的Colour Range,在ImagerySection Name="label“的地方,把颜色值调成白色
如何把对应槽和物品/装备等联系起来呢?我想到的一种方法是使用UserString来进行通信。
首先我们需要一个Item和Skill类来封装我们的物品和技能的属性:
#pragma once #include <string> class Item { public: Item(const std::string& name, const std::string& type) { mName = name; mType = type; } virtual ~Item() { } const std::string& getName() { return mName; } const std::string& getType() { return mType; } void setIconName(const std::string& iconName) { mIconName = iconName; } const std::string& getIconName() { return mIconName; } void setDesc(const std::string& desc) { mDesc = desc; } const std::string& getDesc() { return mDesc; } void setTechLevel(const std::string& level) { mTechLevel = level; } const std::string& getTechLevel() { return mTechLevel; } void setCost(const std::string& cost) { mCost = cost; } const std::string& getCost() { return mCost; } private: std::string mName; //物品名称 std::string mIconName; //图片名称 std::string mTechLevel; //技术等级 std::string mDesc; //物品描述 std::string mCost; //物品消费 std::string mType; //物品类型 };
技能的话差不多, 不过基本上只需要设置技能等级,然后技能的消耗和伤害等根据公式计算:
Skill(const CEGUI::String& name)
{
mName = name;
mLevel = 1;
mCost = 100;
mDamage = 1000;
}
float getCost() { return mCost * mLevel/mMaxLevel; }
float getDamage() { return mDamage * mLevel * mLevel/mMaxLevel; }
接下来就是在逻辑地方调用了它们了。 在上面的代码中,我使用了一个vector来保存需要使用的物品和技能,当然你需要更复杂的管理系统,就像对象工厂那样的系统。
在Tooltip的显示中,使用传递进去的Item或者Skill来动态的加载物品或装备的信息。
当装备一件装备时,为了能让它到特定的槽中, 我们可以传递一个UserString来通信:
//这里传递一个User字串映射来装备到特定槽中 itemWidget->setUserString("type", "Weapon");
然后注册一个点击事件,对应的响应方法:
bool onEquip(const CEGUI::EventArgs& args)
{
const CEGUI::WindowEventArgs& WindowArgs = static_cast<const CEGUI::WindowEventArgs&>(args);
if(WindowArgs.window->getUserString("type") == "Weapon")
{
//得到User字串传递过来的信息来进行操作
CEGUI::Window* invBottom = MyGUISystem::getSingletonPtr()->getWindow("InventoryBottom");
//从当前槽中移除
invBottom->removeChildWindow(WindowArgs.window);
CEGUI::Window* invTop = MyGUISystem::getSingletonPtr()->getWindow("InventoryTop");
//加入到装备栏的槽中
invTop->getChild(0)->addChildWindow(WindowArgs.window);
//重新设定位置和大小(相对)
WindowArgs.window->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0), CEGUI::UDim(0, 0)));
WindowArgs.window->setSize(CEGUI::UVector2(CEGUI::UDim(1, 0), CEGUI::UDim(1, 0)));
}
return true;
}
先从当前槽中移除物品绑定的窗口对象,然后根据传递过来的UserString来判断应该放在哪个槽中,对后把它加入这个槽窗口中并重置位置和大小。
对于一个复杂的装备/物品和技能系统,远不止这些。我只是一个示范,而且是在CEGUI+OGRE这个环境中。所以希望对研究Ogre和CEGUI的同学有帮助,同时希望有更好方案的同学提出意见,共同进步。
相关文章推荐
- OGRE+CEGUI游戏教程(5)--物品/装备和技能系统
- OGRE+CEGUI游戏教程(5)--物品/装备和技能系统
- 关于李三影【Unity 游戏开发教程】装备系统 - 01. JSON数据创建与使用要做笔记的地方
- [过游戏保护]之第一讲[背包、怪物、技能地面物品、任务、队友、装备、宠物、周围玩家]
- OGRE+CEGUI游戏教程(4)----游戏逻辑脚本
- 这阵子使用kbengine+unity做的游戏(mmo物品系统,装备系统,战斗系统,聊天系统完成)
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十五)制作精美的可任意拖放对象的物品栏及装备栏
- OGRE+CEGUI游戏教程(1)----GUI框架
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十五)制作精美的可任意拖放对象的物品栏及装备栏
- OGRE+CEGUI游戏教程(1)----GUI框架
- OGRE+CEGUI游戏教程(2)----NPC对话演示
- OGRE+CEGUI游戏教程(3)----角色创建
- OGRE+CEGUI游戏教程(1)----GUI框架
- Unity教程之-Unity游戏技能Skill系统架构设计
- OGRE+CEGUI游戏教程(2)----NPC对话演示
- OGRE+CEGUI游戏教程(4)----游戏逻辑脚本
- OGRE+CEGUI游戏教程(3)----角色创建
- OGRE+CEGUI游戏教程(2)----NPC对话演示
- OGRE+CEGUI游戏教程(3)----角色创建
- OGRE+CEGUI游戏教程(4)----游戏逻辑脚本