cocos2dx-lua 在cocos2d中使用lua腳本進行開發,並介紹腳本在遊戲中的詳細用途

本站文章均爲 李華明Himi 原創,轉載務必在明顯處註明:
轉載自【黑米GameDev街區】 原文鏈接: http://www.himigame.com/iphone-cocos2dx/681.html

          ☞ 點擊訂閱 ☜
 本博客最新動態!及時將最新博文通知您!

對於遊戲公司而言,採用遊戲腳本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))

運行效果圖如下:

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

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

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

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

1
tolua_beginmodule(tolua_S,"CCLabelTTF");

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

沒錯這裏就是此類的所有是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
/* method: labelWithString of class  cocos2d::CCLabelTTF */
#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,基本就是這樣,對於腳本的熟悉,主要還是在公司進行使用然後慢慢熟悉和熟練掌握的,本章主要需要童鞋們記住的是腳本的概念和作用!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章