2013年4月21日 星期日

再說說 CORONA SDK 與 LUA 語法



CORONA SDK starter 完全免費,不用懷疑
從2013年4月4日星期四開始,Corona SDK 推出 starter 版本,它把以往『開發測試 加 build to device 免費,但是上架到 store 時要付錢』的方式,改成現在連上架也免費。以前的方式是若沒付錢,會加一個提醒訊息在程式啓動的時候,現在 starter 版本已經不會這樣了。趕快加入 Corona SDK 開發者的行列吧!

上次講到 LUA 的 table 還有 Corona 的 API 呼叫,我接下來要介紹 LUA table 的一些用法,實做就像這樣:

問題1: API 要的是 table 我傳給他的卻是個 value 值?
以後你會常常遇到,Corona SDK 有個很好用的 API 叫 timer.performWithDelay( delay, listener [, iterations] ),它的功能是讓程式等待個 delay 的時間,再去呼叫執行 listener 這個 function,然後重覆 iterations 次。

我有個剛學 Corona SDK 的朋友,他把一段問題的 code 給我看,我發現會有這種誤會。也就是說例如:

print("start!")
local function run()
  print("I am running.")
end
timer.performWithDelay( 3000, run() )
print("end!!")


會得到的結果

start!
I am running.
end!!

這個跟你寫 timer.performWithDelay( 3000, run ) 的結果是不一樣的。

start!
end!!
I am running.

我們要的是第二種結果才對吧?所以你要弄清楚 run() 是呼叫執行它,而 run 則是把 run 這個函式的對應 table / pointer 傳給它。

問題2: 我們可不可以自己來做一個像 Corona 那樣的 API 呢?我們看一下,假設我有一個叫 smile.jpg 的圖,我想把它放在螢幕的中間,那 Corona 程式是這樣寫的

local background = display.newImage( "smile.jpg" )
background.x = display.contentWidth / 2
background.y = display.contentHeight / 2

如果我想仿照上面的 display.newImage,我想寫一個叫 display.newSmile 的 function ,只要我告訴他 who 它就列印 who smiled. 然後我可以告訴他 who 是 who (像上面 background.x = 某個值這樣) 這該怎麼做呢?看看下面的程式:

local function Smile( who )
  print(who .. " smiled.")
end
local display = { newSmile = Smile, who = "Ted", }
display.newSmile(display.who)
display.who = "Bob"
display.newSmile(display.who)

PS: LUA 可以用 .key 來取用 table 的值,他跟用方括號陣列方式取用有相同結果,例如 table a = { x = 10 } 相同於 table a = { ["x"] = 10 } 而 a.x = 10 也是 a["x"] = 10

這裡告訴你說,你不但可以放值在 table 裡面,你也可以把 function 放到 LUA 的 table 裡面。
所以我們知道 Corona 的 API 事實上也只是一些 table 而已,你只要知道 table 有哪些 key 就可以很容易抓住它的精華。


順帶一提,定義 table 裡面一個接一個的初始值,你可以接一個逗號在最後面 local display = { newSmile = Smile, who = "Ted", },『..."Ted",』 逗號沒有跟著下一個初始值是允許的。這樣你看 Corona 的 sample code 時候比較不會覺得奇怪。


問題3: 那麼冒號 : 存取 table 的 function 又是怎麼回事?看看下面的程式:

local ndisplay = {}  -- 若取名 display 會蓋過原來的 table 造成問題喔!
ndisplay.who = "Bob"
function ndisplay:newSmile(who)
  if who then print(who .. " smiled.") end
  if self then print(self.who .. " likes bowling.") end
end
ndisplay:newSmile(ndisplay.who)
ndisplay.who = "Tom"
ndisplay:newSmile(ndisplay.who)

其實 LUA 原本是建議我們用冒號 : 來存取 table 的 function,這也最正確的方式。
換個物件導向的程式說法,就是說我們用 . 存取 property 用 : 存取 method。(哈!雖然 LUA 不是物件導向語言)
如果在 LUA 裡面你不這樣做,你可以試試再加上下面這些程式碼

ndisplay.newSmile(ndisplay.who)
-- 上面這一行無法正確執行,會有語法錯誤 input:5: attempt to concatenate field 'who' (a nil value)
-- 若詳細查 LUA 的書,你會發現用 : 定義的函式,若以 . 呼叫,這呼叫方法會需要帶 self 這個參數進去才能正確執行

ndisplay.newSmile(self,ndisplay.who)
-- 上面這一行可以正確執行,因為我們有傳了 self 進去
-- 但是用 : 定義的函式,若以 . 呼叫,雖然我們把 self 傳進去,但是它函式裡面也收不到這個值

之後,我們開始講 Corona SDK 的 API 繪圖物件時,常常要呼叫 obj:removeSelf() 來清除物件和物件佔去的記憶空間。你就
不會覺得奇怪,為什麼不是用 obj.removeSelf() 了。

...待續

沒有留言:

張貼留言