OGRE+CEGUI游戏教程(4)----游戏逻辑脚本
2012-06-02 18:27
399 查看
转载请注明出处:http://blog.csdn.net/pizzazhang
之前的Demo中都是把游戏的逻辑处理放在Cpp文件中,如果我们需要不断尝试新的游戏逻辑的话,那么一般需要的步骤:
改CPP代码-->编译-->看效果-->改代码
对于比较细节的逻辑的话,这通常很麻烦。
使用逻辑脚本可以解决反复编译的麻烦, 因为:
只需要把游戏模块编译完(游戏模块-->音频、物理、GUI等), 在游戏中载入脚本,反复修改脚本的逻辑代码,然后运行查看效果。
即我们可以跳过编译环节,而且脚本语言一般都比较简单,可以关注与真正逻辑上的东西,而不是其他一些烦人的错误提示。
在CEGUI中可以直接使用Lua脚本来实现事件响应,具体可以参考CEGUI Wiki上的一些lua相关的文章。
这个Demo中主要的效果图:
代码中几乎看不到任何逻辑代码(UI控件触发后干什么,忍者的特定触发行为等)
这个程序中,使用了4个模块, Audio模块、GUI模块、Player模块和PlayerManager模块。
在Main.cpp中
可以看到,在主程序中基本没有逻辑代码,唯一比较特别的是在setupGUI中载入Lua脚本模块的代码。 当然可以自己写Lua载入的C++代码,但CEGUI已经提供了一个很好的Lua接口,所以偷懒:-)。 关于Lua在C++的使用可以参考游戏编程精粹5中的一篇文章。
下面是如果实现lua与C++交互的tolua++办法:
比如我有一个Player模块需要和Lua交互, Player.h的C++代码如下:
写一个Player.pkg文件, 这个文件只有Player类的公共方法声明:
Player.pkg:
不要忘了$#include "Ogre.h" 包含需要的头文件。
然后写一个 导出 pkg, 在这个文件中写你需要接口的所有pkg:
LuaInterface.pkg
在CEGUI bin目录中找到 tolua++cegui 或者tolua++, 使用命令:
tolua++cegui -H LuaInterface.h -o LuaInterface.cpp LuaInterface.pkg
把接口暴露给Lua。
把生成的LuaInterface.h和cpp放入需要编译的工程中, 比如在Main.cpp中
开头先包含:
#include "LuaInterface.h"
然后在Lua状态建立完毕后:
tolua_LuaInterface_open(luaState);
把lua状态传递给接口,这样就建立了C++与lua的通信了。
在lua脚本中,你可以使用你暴露出来的接口, 比如本文实现的效果:
使用起来还是很简单的。
如果你使用Python,那么也可以很容易使用脚本来表示逻辑,因为Python本身就是动态的脚本。
Python中使用逻辑不需要专门写一个类, 但由于偷懒, 省去很多单件的实现,所以直接在GUILogic中添加音频、GUI等模块 = =, 真正实现的时候还是要专门分离各个模块, 然后在主要的App代码中:gui_logic.register() , register可以是任何表示逻辑入口的方法。
就这样 :-)
之前的Demo中都是把游戏的逻辑处理放在Cpp文件中,如果我们需要不断尝试新的游戏逻辑的话,那么一般需要的步骤:
改CPP代码-->编译-->看效果-->改代码
对于比较细节的逻辑的话,这通常很麻烦。
使用逻辑脚本可以解决反复编译的麻烦, 因为:
只需要把游戏模块编译完(游戏模块-->音频、物理、GUI等), 在游戏中载入脚本,反复修改脚本的逻辑代码,然后运行查看效果。
即我们可以跳过编译环节,而且脚本语言一般都比较简单,可以关注与真正逻辑上的东西,而不是其他一些烦人的错误提示。
在CEGUI中可以直接使用Lua脚本来实现事件响应,具体可以参考CEGUI Wiki上的一些lua相关的文章。
这个Demo中主要的效果图:
代码中几乎看不到任何逻辑代码(UI控件触发后干什么,忍者的特定触发行为等)
这个程序中,使用了4个模块, Audio模块、GUI模块、Player模块和PlayerManager模块。
在Main.cpp中
class Demo : public BaseApplication { public: Demo(){} virtual ~Demo(){} bool frameRenderingQueued(const Ogre::FrameEvent& evt) { MyGUISystem::getSingletonPtr()->update(evt.timeSinceLastFrame); PlayerManager::getSingletonPtr()->update(evt.timeSinceLastFrame); return BaseApplication::frameRenderingQueued(evt); } void setupGUI() { MyGUISystem::getSingletonPtr()->init(); CEGUI::LuaScriptModule& script(CEGUI::LuaScriptModule::create()); lua_State* luaState = script.getLuaState(); tolua_LuaInterface_open(luaState); CEGUI::System::getSingleton().setScriptingModule(&script); CEGUI::System::getSingleton().executeScriptFile("gui_logic.lua"); } void createScene() { PlayerManager::getSingletonPtr()->setSceneMgr(mSceneMgr); setupGUI(); }
可以看到,在主程序中基本没有逻辑代码,唯一比较特别的是在setupGUI中载入Lua脚本模块的代码。 当然可以自己写Lua载入的C++代码,但CEGUI已经提供了一个很好的Lua接口,所以偷懒:-)。 关于Lua在C++的使用可以参考游戏编程精粹5中的一篇文章。
下面是如果实现lua与C++交互的tolua++办法:
比如我有一个Player模块需要和Lua交互, Player.h的C++代码如下:
#ifndef _PLAYER_H_ #define _PLAYER_H_ #include "Ogre.h" class Player { public: Player(Ogre::SceneManager* sceneMgr, const std::string& meshName); virtual ~Player(); void startAnimation(const std::string& animName); void update(float timeSinceLastTime); void setScale(float x, float y, float z); void setPosition(float x, float y, float z); void yaw(float degree); private: Ogre::AnimationState* mAnimState; Ogre::Entity* mEntity; Ogre::SceneNode* mNode; }; #endif
写一个Player.pkg文件, 这个文件只有Player类的公共方法声明:
Player.pkg:
$#include "Ogre.h" class Player { public: Player(Ogre::SceneManager* sceneMgr, const std::string& meshName); ~Player(); void startAnimation(const std::string& animName); void update(float timeSinceLastTime); void setScale(float x, float y, float z); void setPosition(float x, float y, float z); void yaw(float degree); };
不要忘了$#include "Ogre.h" 包含需要的头文件。
然后写一个 导出 pkg, 在这个文件中写你需要接口的所有pkg:
LuaInterface.pkg
$#include "MyGUISystem.h" $#include "Audio.h" $#include "Player.h" $#include "PlayerManager.h" $pfile "MyGUISystem.pkg" $pfile "Audio.pkg" $pfile "Player.pkg" $pfile "PlayerManager.pkg"
在CEGUI bin目录中找到 tolua++cegui 或者tolua++, 使用命令:
tolua++cegui -H LuaInterface.h -o LuaInterface.cpp LuaInterface.pkg
把接口暴露给Lua。
把生成的LuaInterface.h和cpp放入需要编译的工程中, 比如在Main.cpp中
开头先包含:
#include "LuaInterface.h"
然后在Lua状态建立完毕后:
tolua_LuaInterface_open(luaState);
把lua状态传递给接口,这样就建立了C++与lua的通信了。
在lua脚本中,你可以使用你暴露出来的接口, 比如本文实现的效果:
function addList(title, artist) local musicList = CEGUI.toMultiColumnList(MyGUISystem:getSingletonPtr():getWindow("list")) local color = CEGUI.colour(0.027, 0.05, 0.66, 0.7) local item = CEGUI.createListboxTextItem(title) item:setSelectionBrushImage("TaharezLook", "ListboxSelectionBrush") item:setSelectionColours(color) local row = musicList:addRow(item, 0) item = CEGUI.createListboxTextItem(artist) musicList:setItem(item, 1, row) item:setSelectionBrushImage("TaharezLook", "ListboxSelectionBrush") item:setSelectionColours(color) end function initList() local musicList = CEGUI.toMultiColumnList(MyGUISystem:getSingletonPtr():getWindow("list")) musicList:addColumn("title", 0, CEGUI.UDim(0.5, 0)) musicList:addColumn("artist", 1, CEGUI.UDim(0.5, 0)) musicList:setSelectionMode(CEGUI.MultiColumnList.RowSingle) end function handlePlay(args) audio1:setStop(true) audio2:setStop(true) if title == "Bloom" then audio1:playAudio() player:startAnimation("Backflip") else if title == "Feral" then audio2:playAudio() player:startAnimation("Spin") end end end function handleStop(args) audio1:setStop(true) audio2:setStop(true) player:startAnimation("Idle3") end function handleSelectionChanged(args) local list = CEGUI.toMultiColumnList(CEGUI.toWindowEventArgs(args).window) if list:isItemSelected(CEGUI.MCLGridRef(0, 0)) then title = "Bloom" else if list:isItemSelected(CEGUI.MCLGridRef(1, 0)) then title = "Feral" else title = "" end end end --------------------------------------------------------- --lua 进入点 --------------------------------------------------------- --载入UI MyGUISystem:getSingletonPtr():loadLayout("Root") --音频初始 audio1 = Audio:new() audio2 = Audio:new() audio1:createAudio("Bloom") audio2:createAudio("Feral") --初始音乐列表 initList() addList("Bloom", "Radiohead") addList("Feral", "Radiohead") player = PlayerManager:getSingletonPtr():createPlayer("ninja") player:setScale(0.3, 0.3, 0.3) player:yaw(180) player:setPosition(0, -25, 0)
使用起来还是很简单的。
如果你使用Python,那么也可以很容易使用脚本来表示逻辑,因为Python本身就是动态的脚本。
Python中使用逻辑不需要专门写一个类, 但由于偷懒, 省去很多单件的实现,所以直接在GUILogic中添加音频、GUI等模块 = =, 真正实现的时候还是要专门分离各个模块, 然后在主要的App代码中:gui_logic.register() , register可以是任何表示逻辑入口的方法。
class GUILogic: def __init__(self, sceneMgr, renderWindow): self.subscribe() self.initSound() self.sceneMgr = sceneMgr self.renderWindow = renderWindow def startScene(self): self.renderWindow.getViewport(0).backgroundColour = (1, 1, 1) ent = self.sceneMgr.createEntity("head", "ogrehead.mesh") ent.setMaterialName("Examples/CelShading") node = self.sceneMgr.getRootSceneNode().createChildSceneNode() node.attachObject(ent) node.setScale(4, 4, 4) node.yaw(OGRE.Degree(70)) #shader 参数 SP_SHININESS = 1 SP_DIFFUSE = 2 SP_SPECULAR = 3 #子实体 ##子实体是真正的渲染对象, 对子实体设置定制的参数,即我们从shader程序中得到的结果参数 ##来对子实体进行shader渲染 #眼睛 sub = ent.getSubEntity(0) sub.setCustomParameter(SP_SHININESS, OGRE.Vector4(35, 0, 0, 0)) sub.setCustomParameter(SP_DIFFUSE, OGRE.Vector4(1, 0.3, 0.3, 1)) sub.setCustomParameter(SP_SPECULAR, OGRE.Vector4(1, 0.6, 0.6, 1)) #皮肤 sub = ent.getSubEntity(1) sub.setCustomParameter(SP_SHININESS, OGRE.Vector4(10, 0, 0, 0)) sub.setCustomParameter(SP_DIFFUSE, OGRE.Vector4(0, 0.5, 0, 1)) sub.setCustomParameter(SP_SPECULAR, OGRE.Vector4(0.3, 0.5, 0.3, 1)) #耳朵 sub = ent.getSubEntity(2) sub.setCustomParameter(SP_SHININESS, OGRE.Vector4(25, 0, 0, 0)) sub.setCustomParameter(SP_DIFFUSE, OGRE.Vector4(1, 1, 0, 1)) sub.setCustomParameter(SP_SPECULAR, OGRE.Vector4(1, 1, 0.7, 1)) #牙齿 sub = ent.getSubEntity(3) sub.setCustomParameter(SP_SHININESS, OGRE.Vector4(20, 0, 0, 0)) sub.setCustomParameter(SP_DIFFUSE, OGRE.Vector4(1, 1, 0.7, 1)) sub.setCustomParameter(SP_SPECULAR, OGRE.Vector4(1, 1, 1, 1)) def btn_clicked(self, args): MyGUISystem.getSingleton().loadWindow("GameUI") self.soundIntro.stop() self.soundGame = self.soundMgr.createSound("promise", "promise.ogg") self.soundGame.play() self.startScene() return True def start_show(self, args): progbar= args.window if progbar.getProgress() > 0.999: MyGUISystem.getSingleton().getWindow("IntroStartBtn").show() def handle_item_dropped(self, args): if not args.window.getChildCount(): args.window.addChildWindow(args.dragDropItem) args.dragDropItem.setPosition(CEGUI.UVector2(CEGUI.UDim(0.05, 0), CEGUI.UDim(0.05, 0))) def subscribe(self): button = MyGUISystem.getSingleton().getWindow("IntroStartBtn") button.subscribeEvent("Clicked", self, "btn_clicked") progress= MyGUISystem.getSingleton().getWindow("IntroProgressBar") progress.subscribeEvent("ProgressChanged", self, "start_show") for i in range(1, 6): try: wnd = MyGUISystem.getSingleton().getWindow("Slot" + CEGUI.PropertyHelper.intToString(i)) wnd.subscribeEvent("DragDropItemDropped", self, "handle_item_dropped") except CEGUI.Exception, e: print e def initSound(self): self.soundMgr = SOUND.OgreOggSoundManager.getSingletonPtr() self.soundMgr.init() self.soundIntro = self.soundMgr.createSound("Boulevard Of Broken Dreams", "Boulevard Of Broken Dreams.ogg", / True, True) self.soundIntro.play()
就这样 :-)
相关文章推荐
- OGRE+CEGUI游戏教程(4)----游戏逻辑脚本
- OGRE+CEGUI游戏教程(4)----游戏逻辑脚本
- OGRE+CEGUI游戏教程(1)----GUI框架
- OGRE+CEGUI游戏教程(2)----NPC对话演示
- OGRE+CEGUI游戏教程(1)----GUI框架
- OGRE+CEGUI游戏教程(3)----角色创建
- OGRE+CEGUI游戏教程(1)----GUI框架
- OGRE+CEGUI游戏教程(2)----NPC对话演示
- OGRE+CEGUI游戏教程(3)----角色创建
- Unity 2D游戏开发教程之使用脚本实现游戏逻辑
- OGRE+CEGUI游戏教程(5)--物品/装备和技能系统
- OGRE+CEGUI游戏教程(2)----NPC对话演示
- OGRE+CEGUI游戏教程(3)----角色创建
- OGRE+CEGUI游戏教程(5)--物品/装备和技能系统
- Unity 2D游戏开发教程之使用脚本实现游戏逻辑
- OGRE+CEGUI游戏教程(5)--物品/装备和技能系统
- Unity 2D游戏开发教程之使用脚本实现游戏逻辑
- Cheat Engine游戏脚本修改器通关教程(脑残版)
- Ogre中级教程(九): 深入CEGUI
- 使用cocos2dx的lua脚本写游戏逻辑