天天看點

在Cocos2dX遊戲中使用Lua腳本進行遊戲開發(基礎篇)

對于遊戲公司而言,采用遊戲腳本lua、python等進行開發也很常見,但是很多童鞋對腳本并沒有很熟悉的概念,本篇則向大家簡單介紹腳本的用途以及在Cocos2dx基礎用法;

Lua和python這些詳細介紹的話,請不太熟悉的童鞋自行百度百科哈,那麼對于lua和python則是兩個常用的腳本語言,lua相對于python而言,lua比較輕量級罷了,而其他差別就不多說了,但是為什麼本章要講解lua的原因則有兩點,首先第一:cocos2dx 遊戲引擎内嵌lua,第二點:自從“令人憤怒的小鳥”火起來之後,國内很多都偏向于使用lua了=。 =

那麼對于腳本的用途這裡也大概說兩點:

1.  腳本在手遊中是類于“大腦”的功能,所有遊戲相關的邏輯代碼一般都放在腳本中,而用戶端(前台)的代碼都則屬于“肢體”,也可以說是“播放器”,作用隻是使用者展示出UI界面的功能;那麼腳本的作用那麼不僅僅如此,比如地圖資料等都可以利用腳本使用;

2. 腳本在手機網遊中的作用尤為重要,比如一款網遊“Himi”沒有使用腳本,如果“Himi”1.0版本在釋出後突然發現用戶端出現一些棘手的bug需要修複,那麼你想修改那麼也要等待再次更新用戶端重新送出釋出才可以解決,這樣會流失一大批使用者,而且遊戲每次更新也會流失掉部分使用者,這是肯定的;但是如果“Himi”這款網遊使用腳本的話,那麼解決此類問題很eazy,比如我在“Himi”遊戲中的邏輯代碼都放在腳本a.lua 中,那麼如果a.lua邏輯中哪裡出現了問題,我們直接可以将修複後的a.lua腳本更新至伺服器中,因為一般腳本都會定義version号,比如a.lua有bug的version:1.0,那麼我們修複後的a.lua version改成1.1,當使用者每次啟動遊戲的時候,用戶端都會将腳本的version與伺服器腳本version做對比,當server端腳本version号比目前腳本新,那麼自動下載下傳并覆寫目前腳本,OK,問題解決;不僅僅如此,比如遊戲中做個活動呀,換個圖檔呀等等都可以即使更新,而不是每次修改前端代碼都要重新釋出新的遊戲版本,造成一些損失!

OK,不再多說了,下面我們來介紹在Cocos2dx中對于lua腳本的一些簡單使用,首先我們通過建立一個Cocos2dx-lua模版項目,預設此模版中有個示例,童鞋們可以直接運作項目看效果,但是大家可能會郁悶在class中完全找不到任何相關的代碼?!?那就對了,因為所有邏輯代碼都放置在了lua腳本中,項目啟動後直接解析的一個名稱為hello.lua的腳本!

打開項目的Resources仔細找下,有沒有發現有 hello.lua 合hello2.lua兩個腳本檔案?!OK,就是這裡拉。 那麼對于cocos2dx_lua demo的例子腳本我這裡不多說比較容易,但是肯定不太熟悉的童鞋比較疑惑,那麼Himi這裡重新整理了一份簡單的示例腳本代碼,大家可以直接将如下代碼直接複制到hello.lua中看效果;代碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126

require

"hello2"

-- 包含hello2這個腳本

-- 注視語句

-- 基本上調用的cocos2dx函數和類的時候就是以cocos2d.*這樣子來用

-- 注意2:function 關鍵字定義函數,end結束函數

-- 列印

cocos2d.CCLuaLog(

"腳本hello開始運作... "

.. myadd(3, 5))

-- 建立一個Scene

sceneForWorld = cocos2d.CCScene:node()

-- 建立一個Layer

layerForWorld = cocos2d.CCLayer:node()

sceneForWorld:addChild(layerForWorld)

-- 建立一個精靈

spriteForWorld  = cocos2d.CCSprite:spriteWithFile(

"Icon.png"

)

layerForWorld:addChild(spriteForWorld)

-- 擷取螢幕寬高

screenSize=cocos2d.CCDirector:sharedDirector():getWinSize()

-- 設定精靈坐标

spriteForWorld:setPosition(cocos2d.CCPoint(screenSize.width*0.5,screenSize.height*0.5))

-- 設定精靈縮放2倍

spriteForWorld:setScale(2)

-- 添加一個CCLabelTTF    (!!!!!!備注!!!!!!)

myLableTTF =cocos2d.CCLabelTTF:labelWithString(

"Himi- Lua 基礎"

,

"Helvetica-Bold"

,24)

myLableTTF:setPosition(cocos2d.CCPoint(screenSize.width*0.5,screenSize.height*0.5+100))

sceneForWorld:addChild(myLableTTF)

-- 添加一個CCLabelTTF

myLableTTF2 =cocos2d.CCLabelTTF:labelWithString(

"上面icon跟随使用者觸屏位置"

,

"Helvetica-Bold"

,24)

myLableTTF2:setPosition(cocos2d.CCPoint(screenSize.width*0.5,screenSize.height*0.5-100))

sceneForWorld:addChild(myLableTTF2)

--   @@@@@@@@@@觸摸事件

--開啟觸摸

layerForWorld:setIsTouchEnabled(

true

)

-- 注冊觸摸事件

layerForWorld.__CCTouchDelegate__:registerScriptTouchHandler(cocos2d.CCTOUCHBEGAN,

"btnTouchBegin"

)

layerForWorld.__CCTouchDelegate__:registerScriptTouchHandler(cocos2d.CCTOUCHMOVED,

"btnTouchMove"

)

layerForWorld.__CCTouchDelegate__:registerScriptTouchHandler(cocos2d.CCTOUCHENDED,

"btnTouchEnd"

)

-- touch handers

pointBegin = nil

function btnTouchBegin(e)

cocos2d.CCLuaLog(

"btnTouchBegin"

)

local v = e[1]

local pointMove = v:locationInView(v:view())

pointMove = cocos2d.CCDirector:sharedDirector():convertToGL(pointMove)

spriteForWorld:setPosition(cocos2d.CCPoint(pointMove.x,pointMove.y))

end

function btnTouchMove(e)

cocos2d.CCLuaLog(

"btnTouchMove"

)

local v = e[1]

local pointMove = v:locationInView(v:view())

pointMove = cocos2d.CCDirector:sharedDirector():convertToGL(pointMove)

spriteForWorld:setPosition(cocos2d.CCPoint(pointMove.x,pointMove.y))

end

function btnTouchEnd(e)

cocos2d.CCLuaLog(

"btnTouchEnd"

)

end

--   @@@@@@@@@@觸摸結束

--動态小狗

winSize = cocos2d.CCDirector:sharedDirector():getWinSize()

FrameWidth = 105

FrameHeight = 95

textureDog = cocos2d.CCTextureCache:sharedTextureCache():addImage(

"dog.png"

)

frame0 = cocos2d.CCSpriteFrame:frameWithTexture(textureDog, cocos2d.CCRectMake(0, 0, FrameWidth, FrameHeight))

frame1 = cocos2d.CCSpriteFrame:frameWithTexture(textureDog, cocos2d.CCRectMake(FrameWidth*1, 0, FrameWidth, FrameHeight))

spriteDog = cocos2d.CCSprite:spriteWithSpriteFrame(frame0)

spriteDog:setPosition(cocos2d.CCPoint(100, winSize.height/4*3))

layerForWorld:addChild(spriteDog)

animFrames = cocos2d.CCMutableArray_CCSpriteFrame__:

new

(2)

animFrames:addObject(frame0)

animFrames:addObject(frame1)

animation = cocos2d.CCAnimation:animationWithFrames(animFrames, 0.5)

animate = cocos2d.CCAnimate:actionWithAnimation(animation,

false

);

spriteDog:runAction(cocos2d.CCRepeatForever:actionWithAction(animate))

--自定義函數

function prForHimi()

cocos2d.CCLuaLog(

"reFresh function"

)

--取消選擇器

--cocos2d.CCScheduler:sharedScheduler():unscheduleScriptFunc(

"prForHimi"

)

end

--使用選擇器進行函數更新

--cocos2d.CCScheduler:sharedScheduler():scheduleScriptFunc(

"prForHimi"

, 1,

false

)

--循環語句

for

i=0,4,1

do

for

j=0,4,2

do

cocos2d.CCLuaLog(

"for loop"

,i)

end

end

-- 避免記憶體洩漏

collectgarbage(

"setpause"

, 100)

collectgarbage(

"setstepmul"

, 5000)

-- 播放背景音樂

--CocosDenshion.SimpleAudioEngine:sharedEngine():playBackgroundMusic(

"background.mp3"

,

true

)

-- 播放音效

--CocosDenshion.SimpleAudioEngine:sharedEngine():preloadEffect(

"effect1.wav"

)

-- run整個scene

cocos2d.CCDirector:sharedDirector():runWithScene(sceneForWorld)

cocos2d.CCLuaLog(

"腳本hello正常執行結束... "

.. myadd(3, 5))

運作效果圖如下:

在Cocos2dX遊戲中使用Lua腳本進行遊戲開發(基礎篇)

對于Himi上面給出的自己修改後的代碼注視寫的狠清楚了 =。 = 是以不多加贅述,但是Himi這裡需要還要詳細說一點;

腳本lua等一般都示通過中間層(解析)進行與前端代碼(Cocos2dX封裝的引擎類庫)互動,是以很多方法名稱可能發生了改變,那麼對于不太熟悉的童鞋我們如何下手?

OK,如剛才的代碼中有個“備注”,不知道細心童鞋們看到沒有,這裡是添加了一個CCLabelTTF ,假如我們不知道它的構造函數是否有修改,或者說參數忘記都是什麼了,那麼請打開你項目的libs檔案夾,然後打開lua檔案夾,繼續打開cocos2dx_support檔案夾找到 LuaCocos2d.cpp檔案打開,(注意這個檔案代碼很多,打開較慢)然後你會看到很多方法的定義與實作!

那麼假如我們來找 CCLabelTTF的構造方法,那麼搜一下如下語句:

1

tolua_beginmodule(tolua_S,

"CCLabelTTF"

);

你将發現此類下方一大批類似的代碼:

在Cocos2dX遊戲中使用Lua腳本進行遊戲開發(基礎篇)

沒錯這裡就是此類的所有是lua-cocos2dx之間的轉換函數定義,比如常用的CCLabelTTF構造函數:

1

tolua_function(tolua_S,

"labelWithString"

,tolua_Cocos2d_cocos2d_CCLabelTTF_labelWithString01);

此函數第一參數大家不用理會,第二個參數表示我們使用cocos2d/x時調用的函數名稱,後面則是lua-cocos2dx之間的轉換函數實作代碼,大家可以繼續搜尋第三個參數或者按住command然後點選第三個參數找到其函數實作代碼:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

#ifndef TOLUA_DISABLE_tolua_Cocos2d_cocos2d_CCLabelTTF_labelWithString01

static

int

tolua_Cocos2d_cocos2d_CCLabelTTF_labelWithString01(lua_State* tolua_S)

{

tolua_Error tolua_err;

if

(

!tolua_isusertable(tolua_S,1,

"cocos2d::CCLabelTTF"

,0,&tolua_err) ||

!tolua_isstring(tolua_S,2,0,&tolua_err) ||

!tolua_isstring(tolua_S,3,0,&tolua_err) ||

!tolua_isnumber(tolua_S,4,0,&tolua_err) ||

!tolua_isnoobj(tolua_S,5,&tolua_err)

)

goto

tolua_lerror;

else

{

const

char

* label = ((

const

char

*)  tolua_tostring(tolua_S,2,0));

const

char

* fontName = ((

const

char

*)  tolua_tostring(tolua_S,3,0));

float

fontSize = ((

float

)  tolua_tonumber(tolua_S,4,0));

{

cocos2d::CCLabelTTF* tolua_ret = (cocos2d::CCLabelTTF*)  cocos2d::CCLabelTTF::labelWithString(label,fontName,fontSize);

tolua_pushusertype(tolua_S,(

void

*)tolua_ret,

"cocos2d::CCLabelTTF"

);

}

}

return

1;

tolua_lerror:

return

tolua_Cocos2d_cocos2d_CCLabelTTF_labelWithString00(tolua_S);

}

#endif //#ifndef TOLUA_DISABLE

在這裡看到此函數轉換過程,并可以很清楚看到:

1

cocos2d::CCLabelTTF* tolua_ret = (cocos2d::CCLabelTTF*)  cocos2d::CCLabelTTF::labelWithString(label,fontName,fontSize);

到這裡大家會很清楚需要的參數都是哪些,如果還不清楚,繼續按住Command然後點選labelWithString進入cocos2dx引擎代碼 CCLabelTTF.cpp中的此函數實作啦!

可能這部分有童鞋看得比較迷茫 =。 = 那麼Himi來簡化這些複雜來說:

解析lua腳本中的一句代碼->通過解析層代碼->将其轉換并轉到前端代碼進行使用

那麼當然此過程也可逆:

前端代碼->通過解析層代碼->使用lua腳本中東東

這裡由于Himi對cocos2dx 中的lua還沒有深入了解,是以不知是否過程可逆;

OK,基本就是這樣,對于腳本的熟悉,主要還是在公司進行使用然後慢慢熟悉和熟練掌握的,本章主要需要童鞋們記住的是腳本的概念和作用!