这周的前两天,研究xml小有成就,这周的后两天,我继续研究lua和cpp的结合。昨天小有成就,今天来给大家分享一下经验~
先说一下效果,按照惯例,上一张图~
这两天同组程序员"cc"研究了charcter controller,角色和场景的碰撞检测已经很完美了。 所以目前的效果是:通过上下左右箭头,如同90坦克那样控制坦克在场景中移动,并且可以检测到楼梯上下。坦克的移动是个加速过程,速度从5-20,松开按键后归到5。
而目前控制坦克逻辑已经完全交给了lua脚本!这个是昨天研究了一天的成果,相当舒服,而且对于cc(character controller)物体和非cc物体,都可以使用同一个behavior脚本控制(得益于gameobject的继承结构和override函数)。
下面附上这一段控制的逻辑脚本
Tank.lua 1 . -- |------------------------------------------- 2 . -- Private variables 3 . fSpeed = 10 4 . fMaxSpeed = 20 5 . fMinSpeed = 5 6 . fAccelaration = 10 7 . 8 . -- |------------------------------------------- 9 . -- System functions 10 . function Start () 11 . local flag = true 12 . end 13 . 14 . function Update (fElapsedTime) 15 . -- move up. translate and rotate 16 . if (IsKey(KeyCode.VK_UP)) then 17 . fSpeed = fSpeed + fElapsedTime * fAccelaration 18 . if (fSpeed > fMaxSpeed) then fSpeed = fMaxSpeed end 19 . SetEuler( 0 , 0 , 0 ) 20 . GlobalTranslate( 0 , 0 , 1 ,fElapsedTime * fSpeed) 21 . end 22 . -- move left. 23 . if (IsKey(KeyCode.VK_LEFT)) then 24 . fSpeed = fSpeed + fElapsedTime * fAccelaration 25 . if (fSpeed > fMaxSpeed) then fSpeed = fMaxSpeed end 26 . SetEuler( 0 , - 90 , 00 ) 27 . GlobalTranslate( - 1 , 0 , 0 ,fElapsedTime * fSpeed) 28 . end 29 . -- move down. 30 . if (IsKey(KeyCode.VK_DOWN)) then 31 . fSpeed = fSpeed + fElapsedTime * fAccelaration 32 . if (fSpeed > fMaxSpeed) then fSpeed = fMaxSpeed end 33 . SetEuler( 0 , 180 , 0 ) 34 . GlobalTranslate( 0 , 0 , - 1 ,fElapsedTime * fSpeed) 35 . end 36 . -- move right. 37 . if (IsKey(KeyCode.VK_RIGHT)) then 38 . fSpeed = fSpeed + fElapsedTime * fAccelaration 39 . if (fSpeed > fMaxSpeed) then fSpeed = fMaxSpeed end 40 . SetEuler( 0 , 90 , 0 ) 41 . GlobalTranslate( 1 , 0 , 0 ,fElapsedTime * fSpeed) 42 . end 43 . -- if any key released. 44 . if (( not IsKey(KeyCode.VK_UP)) and ( not IsKey(KeyCode.VK_LEFT)) and ( not IsKey(KeyCode.VK_DOWN)) and ( not IsKey(KeyCode.VK_RIGHT))) then 45 . fSpeed = fMinSpeed 46 . end 47 . end
有过lua基础的同学应该很容易看懂。这段脚本其实和unity3d绑定在gameobject上的behavior异曲同工。 哈哈,废话,我的设计思想多数是在模仿和借鉴unity3d。因为它的易用和易理解,现在很火。所以借鉴unity3d的结构一定能让程序更加易用。
下面大概说一下具体的实现吧。
先说设计思想。gameknife目前基本已经确定是以gameobject为中心的结构了,所以我考虑可以为每一个gameobject绑定一个behavior。这个behavior就是一个lua脚本。gameobject在绘制前会调用behavior的update() ,在每一次reset时(或者是create时)调用start(),为gameobject作初始化(是不是象极了unity?)。 通过update()函数,反向的再调用c++中的函数,相当于把frameMove()做到外部可以动态改变,这样,便可以驱动游戏的逻辑了。
那么现在的设计是这样的:
C++代码 代码 1 . void InitBehavior( const char * filename, bool uselib = false ) 2 . { 3 . if (m_lsoBehavior -> DoFile(filename) != 0 ) 4 . { 5 . OutputDebugString(L " ===LuaScriptSystem> Behavior Script Init Error!\n " ); 6 . return ; 7 . } 8 . m_bIsBehavior = true ; 9 . if (uselib) 10 . m_lsoBehavior -> OpenLibs(); 11 . kLuaLinkFunctions(); 12 . } 13 . 14 . void kLuaLinkFunctions() 15 . { 16 . if (m_lsoBehavior) 17 . { 18 . m_lsoBehavior -> GetGlobals().RegisterDirect( " IsKeyDown " , * this , & kGameObject::luaIsKeyDown); 19 . m_lsoBehavior -> GetGlobals().RegisterDirect( " IsKeyUp " , * this , & kGameObject::luaIsKeyUp); 20 . m_lsoBehavior -> GetGlobals().RegisterDirect( " IsKey " , * this , & kGameObject::luaIsKey); 21 . m_lsoBehavior -> GetGlobals().RegisterDirect( " LocalTranslate " , * this , & kGameObject::kLuaTranslateLocal); 22 . m_lsoBehavior -> GetGlobals().RegisterDirect( " GlobalTranslate " , * this , & kGameObject::kLuaTranslateGlobal); 23 . m_lsoBehavior -> GetGlobals().RegisterDirect( " LocalRotate " , * this , & kGameObject::kLuaRotateLocal); 24 . m_lsoBehavior -> GetGlobals().RegisterDirect( " GlobalRotate " , * this , & kGameObject::kLuaRotateGlobal); 25 . m_lsoBehavior -> GetGlobals().RegisterDirect( " SetEuler " , * this , & kGameObject::kLuaSetEuler); 26 . } 27 . }
initBehavior是外部调用的,为gameobject绑定lua文件。 然后链接Functions,把控制逻辑的函数链接进lua state
C++代码 代码 1 . void kLuaIntialize() 2 . { 3 . // 获得名字为Start的函数指针 4 . LuaFunction < void > pStartFunc = m_lsoBehavior -> GetGlobal( " Start " ); 5 . pStartFunc(); 6 . } 7 . 8 . void kLuaUpdate( float fElapsedTime) 9 . { 10 . // 获得名字为Update的函数指针 11 . LuaFunction < float > pUpdateFunc = m_lsoBehavior -> GetGlobal( " Update " ); 12 . pUpdateFunc(fElapsedTime); 13 . }
这里是start和update在c++中的体现,分别在create和framemove中调用即可。
这样,就将lua脚本和c++执行的逻辑联系起来了。
ps. 昨天做这个程序时,其实设计没花太多时间,大量时间放在那个register函数上了。 luaplus中有相当多的register函数: register(xxx), registerDirect(xxx), registerFunc(...), registerObjectDirect(), registerObjectFunc()。选择上测试了好久。建议大家在做的时候先建一个tmain的小工程,测试,测试完成后直接移入大工程。我昨天深受其害,后来才意识到应该使用小工程测试,毕竟luaplus深入研究的文章不多,文档也写得...唉,毕竟是个人项目。那个Joshua C. Jensen确实太牛逼了,膜拜!
转载于:https://www.cnblogs.com/gameknife/archive/2010/05/29/1832159.html