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

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

之前的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()


 

就这样 :-)

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值