OGRE+CEGUI游戏教程(4)----游戏逻辑脚本

转载 2012年03月26日 14:08:44

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

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

 

之前的Demo中都是把游戏的逻辑处理放在Cpp文件中,如果我们需要不断尝试新的游戏逻辑的话,那么一般需要的步骤:

改CPP代码-->编译-->看效果-->改代码

对于比较细节的逻辑的话,这通常很麻烦。

使用逻辑脚本可以解决反复编译的麻烦, 因为:

只需要把游戏模块编译完(游戏模块-->音频、物理、GUI等), 在游戏中载入脚本,反复修改脚本的逻辑代码,然后运行查看效果。

即我们可以跳过编译环节,而且脚本语言一般都比较简单,可以关注与真正逻辑上的东西,而不是其他一些烦人的错误提示。

 

在CEGUI中可以直接使用Lua脚本来实现事件响应,具体可以参考CEGUI Wiki上的一些lua相关的文章。

 

这个Demo中主要的效果图:


代码中几乎看不到任何逻辑代码(UI控件触发后干什么,忍者的特定触发行为等)

 

这个程序中,使用了4个模块, Audio模块、GUI模块、Player模块和PlayerManager模块。

在Main.cpp中:

  1. class Demo : public BaseApplication  
  2. {  
  3. public:  
  4.     Demo(){}  
  5.     virtual ~Demo(){}  
  6.     bool frameRenderingQueued(const Ogre::FrameEvent& evt)  
  7.     {  
  8.         MyGUISystem::getSingletonPtr()->update(evt.timeSinceLastFrame);  
  9.         PlayerManager::getSingletonPtr()->update(evt.timeSinceLastFrame);  
  10.         return BaseApplication::frameRenderingQueued(evt);  
  11.     }  
  12.     void setupGUI()  
  13.     {  
  14.         MyGUISystem::getSingletonPtr()->init();  
  15.         CEGUI::LuaScriptModule& script(CEGUI::LuaScriptModule::create());  
  16.         lua_State* luaState = script.getLuaState();  
  17.         tolua_LuaInterface_open(luaState);  
  18.         CEGUI::System::getSingleton().setScriptingModule(&script);  
  19.         CEGUI::System::getSingleton().executeScriptFile("gui_logic.lua");  
  20.           
  21.     }  
  22.     void createScene()  
  23.     {         
  24.         PlayerManager::getSingletonPtr()->setSceneMgr(mSceneMgr);  
  25.         setupGUI();  
  26.     }  

可以看到,在主程序中基本没有逻辑代码,唯一比较特别的是在setupGUI中载入Lua脚本模块的代码。 当然可以自己写Lua载入的C++代码,但CEGUI已经提供了一个很好的Lua接口,所以偷懒:-)。 关于Lua在C++的使用可以参考 游戏编程精粹5中的一篇文章。

 

 


 

下面是如果实现lua与C++交互的tolua++办法:

比如我有一个Player模块需要和Lua交互, Player.h的C++代码如下:

  1. #ifndef _PLAYER_H_  
  2. #define _PLAYER_H_  
  3. #include "Ogre.h"  
  4. class Player  
  5. {  
  6. public:  
  7.     Player(Ogre::SceneManager* sceneMgr, const std::string& meshName);  
  8.     virtual ~Player();  
  9.     void startAnimation(const std::string& animName);  
  10.     void update(float timeSinceLastTime);  
  11.     void setScale(float x, float y, float z);  
  12.     void setPosition(float x, float y, float z);  
  13.     void yaw(float degree);  
  14. private:  
  15.     Ogre::AnimationState*   mAnimState;  
  16.     Ogre::Entity*           mEntity;  
  17.     Ogre::SceneNode*        mNode;  
  18. };  
  19. #endif  

写一个Player.pkg文件, 这个文件只有Player类的公共方法声明:

Player.pkg:

  1. $#include "Ogre.h"  
  2. class Player  
  3. {  
  4. public:  
  5.     Player(Ogre::SceneManager* sceneMgr, const std::string& meshName);  
  6.     ~Player();  
  7.     void startAnimation(const std::string& animName);  
  8.     void update(float timeSinceLastTime);  
  9.     void setScale(float x, float y, float z);  
  10.     void setPosition(float x, float y, float z);  
  11.     void yaw(float degree);  
  12. };  

不要忘了$#include "Ogre.h" 包含需要的头文件。

然后写一个 导出 pkg, 在这个文件中写你需要接口的所有pkg:

LuaInterface.pkg

  1. $#include "MyGUISystem.h"  
  2. $#include "Audio.h"  
  3. $#include "Player.h"  
  4. $#include "PlayerManager.h"  
  5. $pfile "MyGUISystem.pkg"      
  6. $pfile "Audio.pkg"  
  7. $pfile "Player.pkg"  
  8. $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脚本中,你可以使用你暴露出来的接口, 比如本文实现的效果:

  1. function addList(title, artist)  
  2.     local musicList = CEGUI.toMultiColumnList(MyGUISystem:getSingletonPtr():getWindow("list"))  
  3.     local color = CEGUI.colour(0.027, 0.05, 0.66, 0.7)  
  4.     local item = CEGUI.createListboxTextItem(title)  
  5.     item:setSelectionBrushImage("TaharezLook""ListboxSelectionBrush")  
  6.     item:setSelectionColours(color)  
  7.     local row = musicList:addRow(item, 0)  
  8.     item = CEGUI.createListboxTextItem(artist)  
  9.     musicList:setItem(item, 1, row)  
  10.     item:setSelectionBrushImage("TaharezLook""ListboxSelectionBrush")  
  11.     item:setSelectionColours(color)  
  12. end  
  13. function initList()  
  14.     local musicList = CEGUI.toMultiColumnList(MyGUISystem:getSingletonPtr():getWindow("list"))  
  15.     musicList:addColumn("title", 0, CEGUI.UDim(0.5, 0))  
  16.     musicList:addColumn("artist", 1, CEGUI.UDim(0.5, 0))  
  17.     musicList:setSelectionMode(CEGUI.MultiColumnList.RowSingle)  
  18. end  
  19. function handlePlay(args)  
  20.     audio1:setStop(true)  
  21.     audio2:setStop(true)  
  22.     if title == "Bloom" then  
  23.         audio1:playAudio()  
  24.         player:startAnimation("Backflip")  
  25.     else if title == "Feral" then  
  26.         audio2:playAudio()  
  27.         player:startAnimation("Spin")  
  28.     end  
  29. end  
  30. end  
  31. function handleStop(args)  
  32.     audio1:setStop(true)  
  33.     audio2:setStop(true)  
  34.     player:startAnimation("Idle3")  
  35. end  
  36. function handleSelectionChanged(args)  
  37.     local list = CEGUI.toMultiColumnList(CEGUI.toWindowEventArgs(args).window)  
  38.     if list:isItemSelected(CEGUI.MCLGridRef(0, 0)) then  
  39.         title = "Bloom"  
  40.     else if list:isItemSelected(CEGUI.MCLGridRef(1, 0)) then  
  41.         title = "Feral"  
  42.     else  
  43.         title = ""  
  44.     end  
  45. end  
  46. end  
  47. ---------------------------------------------------------  
  48. --lua 进入点  
  49. ---------------------------------------------------------  
  50. --载入UI  
  51. MyGUISystem:getSingletonPtr():loadLayout("Root")  
  52. --音频初始  
  53. audio1 = Audio:new()  
  54. audio2 = Audio:new()  
  55. audio1:createAudio("Bloom")  
  56. audio2:createAudio("Feral")  
  57. --初始音乐列表  
  58. initList()  
  59. addList("Bloom""Radiohead")  
  60. addList("Feral""Radiohead")  
  61. player = PlayerManager:getSingletonPtr():createPlayer("ninja")  
  62. player:setScale(0.3, 0.3, 0.3)  
  63. player:yaw(180)  
  64. player:setPosition(0, -25, 0)  

使用起来还是很简单的。

 

如果你使用Python,那么也可以很容易使用脚本来表示逻辑,因为Python本身就是动态的脚本。

Python中使用逻辑不需要专门写一个类, 但由于偷懒, 省去很多单件的实现,所以直接在GUILogic中添加音频、GUI等模块 = =, 真正实现的时候还是要专门分离各个模块, 然后在主要的App代码中:gui_logic.register() , register可以是任何表示逻辑入口的方法。

[python] view plaincopy
  1. class GUILogic:  
  2.     def __init__(self, sceneMgr, renderWindow):  
  3.         self.subscribe()  
  4.         self.initSound()  
  5.           
  6.         self.sceneMgr = sceneMgr  
  7.         self.renderWindow = renderWindow  
  8.         
  9.     def startScene(self):  
  10.         self.renderWindow.getViewport(0).backgroundColour = (111)  
  11.         ent = self.sceneMgr.createEntity("head""ogrehead.mesh")  
  12.         ent.setMaterialName("Examples/CelShading")  
  13.         node = self.sceneMgr.getRootSceneNode().createChildSceneNode()  
  14.         node.attachObject(ent)  
  15.         node.setScale(444)  
  16.         node.yaw(OGRE.Degree(70))  
  17.           
  18.         #shader 参数  
  19.         SP_SHININESS = 1  
  20.         SP_DIFFUSE = 2  
  21.         SP_SPECULAR = 3  
  22.           
  23.         #子实体  
  24.         ##子实体是真正的渲染对象, 对子实体设置定制的参数,即我们从shader程序中得到的结果参数  
  25.         ##来对子实体进行shader渲染  
  26.         #眼睛  
  27.         sub = ent.getSubEntity(0)  
  28.         sub.setCustomParameter(SP_SHININESS, OGRE.Vector4(35000))  
  29.         sub.setCustomParameter(SP_DIFFUSE, OGRE.Vector4(10.30.31))  
  30.         sub.setCustomParameter(SP_SPECULAR, OGRE.Vector4(10.60.61))  
  31.         #皮肤  
  32.         sub = ent.getSubEntity(1)  
  33.         sub.setCustomParameter(SP_SHININESS, OGRE.Vector4(10000))  
  34.         sub.setCustomParameter(SP_DIFFUSE, OGRE.Vector4(00.501))  
  35.         sub.setCustomParameter(SP_SPECULAR, OGRE.Vector4(0.30.50.31))  
  36.         #耳朵  
  37.         sub = ent.getSubEntity(2)  
  38.         sub.setCustomParameter(SP_SHININESS, OGRE.Vector4(25000))  
  39.         sub.setCustomParameter(SP_DIFFUSE, OGRE.Vector4(1101))  
  40.         sub.setCustomParameter(SP_SPECULAR, OGRE.Vector4(110.71))  
  41.         #牙齿  
  42.         sub = ent.getSubEntity(3)  
  43.         sub.setCustomParameter(SP_SHININESS, OGRE.Vector4(20000))  
  44.         sub.setCustomParameter(SP_DIFFUSE, OGRE.Vector4(110.71))  
  45.         sub.setCustomParameter(SP_SPECULAR, OGRE.Vector4(1111))  
  46.             
  47.     def btn_clicked(self, args):  
  48.         MyGUISystem.getSingleton().loadWindow("GameUI")  
  49.         self.soundIntro.stop()  
  50.         self.soundGame = self.soundMgr.createSound("promise""promise.ogg")  
  51.         self.soundGame.play()  
  52.           
  53.         self.startScene()  
  54.         return True  
  55.     def start_show(self, args):  
  56.         progbar= args.window  
  57.         if progbar.getProgress() > 0.999:  
  58.             MyGUISystem.getSingleton().getWindow("IntroStartBtn").show()  
  59.          
  60.     def handle_item_dropped(self, args):  
  61.         if not args.window.getChildCount():  
  62.             args.window.addChildWindow(args.dragDropItem)  
  63.             args.dragDropItem.setPosition(CEGUI.UVector2(CEGUI.UDim(0.050), CEGUI.UDim(0.050)))  
  64.        
  65.     def subscribe(self):  
  66.         button = MyGUISystem.getSingleton().getWindow("IntroStartBtn")  
  67.         button.subscribeEvent("Clicked",  
  68.                               self,  
  69.                               "btn_clicked")  
  70.           
  71.         progress= MyGUISystem.getSingleton().getWindow("IntroProgressBar")  
  72.         progress.subscribeEvent("ProgressChanged",  
  73.                                 self,  
  74.                                 "start_show")  
  75.           
  76.         for i in range(16):  
  77.             try:  
  78.                 wnd = MyGUISystem.getSingleton().getWindow("Slot" + CEGUI.PropertyHelper.intToString(i))  
  79.                 wnd.subscribeEvent("DragDropItemDropped",  
  80.                                    self,  
  81.                                    "handle_item_dropped")  
  82.             except CEGUI.Exception, e:  
  83.                 print e  
  84.                   
  85.     def initSound(self):  
  86.         self.soundMgr = SOUND.OgreOggSoundManager.getSingletonPtr()  
  87.         self.soundMgr.init()  
  88.         self.soundIntro = self.soundMgr.createSound("Boulevard Of Broken Dreams""Boulevard Of Broken Dreams.ogg", /  
  89.                                       TrueTrue)  
  90.         self.soundIntro.play()  

OGRE+CEGUI游戏教程(4)----游戏逻辑脚本

转载请注明出处:http://blog.csdn.net/pizzazhang 之前的Demo中都是把游戏的逻辑处理放在Cpp文件中,如果我们需要不断尝试新的游戏逻辑的话,那么一般需要的步骤: 改...

OGRE+CEGUI游戏教程(4)----游戏逻辑脚本

转载请注明出处:http://blog.csdn.net/pizzazhang   源码和可执行程序链接http://code.google.com/p/pizzaprojects/download...

Unity 2D游戏开发教程之使用脚本实现游戏逻辑

Unity 2D游戏开发教程之使用脚本实现游戏逻辑

在Unity中使用Lua脚本:语言层和游戏逻辑粘合层处理

为什么非要在Unity里面用Lua呢?原因: 方便做功能的热更新; Lua语言的深度和广度都不大,易学易用,可以降低项目成本。...

在Unity中使用Lua脚本:语言层和游戏逻辑粘合层处理

http://blog.csdn.net/zhaoguanghui2012/article/details/46916705 点击打开链接 前言:为什么要用Lua ...

OGRE+CEGUI游戏教程(1)----GUI框架

转载文章请注明出处:http://blog.csdn.net/pizzazhang    源码和可执行程序链接http://code.google.com/p/pizzaprojects/downl...

OGRE+CEGUI游戏教程(2)----NPC对话演示

转载请注明出处:http://blog.csdn.net/pizzazhang   源码和可执行程序链接http://code.google.com/p/pizzaprojects/downlo...

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

转载请注明出处:http://blog.csdn.net/pizzazhang   源码和可执行程序链接http://code.google.com/p/pizzaprojects/download...

在Unity中使用Lua脚本:语言层和游戏逻辑粘合层处理

在Unity3D中实现一个Lua组件,用来整合Lua上层逻辑代码。
  • Neil3D
  • Neil3D
  • 2015年04月11日 11:38
  • 25204

使用cocos2dx的lua脚本写游戏逻辑

原文: http://www.hanxi.info/2013/10/06/original-cocos2dx-script-game/
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:OGRE+CEGUI游戏教程(4)----游戏逻辑脚本
举报原因:
原因补充:

(最多只允许输入30个字)