Introduction to corona sdk

87,875 views

Published on

Published in: Technology

Introduction to corona sdk

  1. 1. Introduction to Corona SDK Cooper Maa 2013/9
  2. 2. Who am I? • 本名:馬萬圳 (Cooper Maa) • 現任於: • 擅長 Arduino、嵌入式系統韌體研發、物聯網及網 路通訊協定
  3. 3. Downloading Examples https://github.com/coopermaa/Corona_SDK_Intro
  4. 4. Agenda • Corona SDK Overview • Quick Start • Corona SDK Framework – Text, Shapes, Images, Audio – Events and Listeners – Physics – Storyboard – Widget
  5. 5. Corona SDK Overview
  6. 6. What is Corona SDK? • 程式語言很簡單 (Lua) • 很快就可以上手 • 開發跨平台 Apps (iPhone, iPad, Android)
  7. 7. A piece of cake
  8. 8. 好比剪貼勞作 用 Corona SDK 寫 Game 就這麼簡單
  9. 9. Cross Platform Development
  10. 10. xcode + Objective-C eclipse + Java 之前兩套都要學,而且都不容易學
  11. 11. Notepad++ and Corona SDK 現在只要會 Lua,既簡單又輕鬆
  12. 12. 有 Free 版可用 (Starter)
  13. 13. 誰在用 Corona SDK?
  14. 14. and more…
  15. 15. High Performance 30 fps: 預設每秒 30 個 frames
  16. 16. 不只可以寫遊戲
  17. 17. What is Lua? • • • • Scripting Language Small and Simple Extensible Portable
  18. 18. Lua v.s Othe Languages if not carMoving then -- do something elseif noGas then -- do something else end if (!carMoving) { // do something } else if (noGas) { // do something else } for i = 1,10 do print(i) end for (i=1; i<=10; i++) { print(i); } for j = 100,1,-1 do print(j) end for (j=100; j>0; j++) { print(j); }
  19. 19. Lua objects are Tables array = { "a", "b", 100, "hello" } dictionary = { x=5, y=7, name="Coopermaa" } t = {} t[1] = "a" t["x"] = 5 t.x = 5 key = "x" t[key] = 5 ----- empty table numerical index key index equivalent property access -- any type can be a key t["printCooper"] = function print("Cooper") end
  20. 20. Object methods -- create empty table local o = {} -- add method function o:saySomething(something) print(something) end -- output 'hi' o:saySomwthing("hi")
  21. 21. The ':' is syntactic sugar -- create empty table local o = {} -- add method function f(self, something) print(something) end o.saySomething = f -- output 'hi' o.saySomething(o, "hi")
  22. 22. Arrays are 1-based -- Lua: index begins with 1 local array = {'a', 'b', 'c'} for i=1,#array do print(array[i]) end // Other languages: index begins with 0 array = ['a', 'b', 'c']; for (var i=0; i<arr.length; i++) { console.log(array[i]); }
  23. 23. Features of Corona SDK • • • • • • • • • OpenGL graphics OpenAL audio Box2D Physics Texture atlases, sprites Networking GPS, multi-touch, accelerometer, camera, video Widgets library and native web views, textfields Services: ads, analytics, IAP Game networks: Game Center (iOS) and Google Play Game Services for achievements, leaderboards, real-time multiplayer games • Corona Cloud (shutdown) : multiplayer support, leaderboards, chat, push notification, game analytics
  24. 24. Community • • • • • http://www.coronalabs.com/community/ - 官方社群 http://docs.coronalabs.com/ - 官方文件 http://www.youtube.com/user/CoronaLabs - 官方 Youtube https://github.com/coronalabs - 官方 github http://www.youtube.com/user/CoronaGeek
  25. 25. Quick Start
  26. 26. 註冊帳號 http://bit.ly/QTRjWG 要先註冊帳號才能下載 Corona SDK
  27. 27. 下載 Free 版 Corona SDK 注意!Windows 版只能 Build Android App
  28. 28. 安裝 Corona SDK 按照慣例,都是按 [Next] 一路到底即可
  29. 29. 安裝 XCODE (Mac only) https://developer.apple.com/xcode/ 裝了 XCODE 才能 Build 出 iOS App
  30. 30. 安裝 JDK 6 (32-bit) http://bit.ly/nYenCt 裝了 JDK 才能 Build 出 Android App (.apk 檔)
  31. 31. 打開 Corona Simulator 點按 [Corona SDK > Corona Simulator]
  32. 32. 啟動(激活) Corona SDK 第一次開 Corona Simulator 要先輸入帳號啟動軟體
  33. 33. Corona Simulator 之後都是用 Corona Simulator 來跑程式
  34. 34. Corona Simulator Output 視窗 這個視窗提供偵錯用的訊息
  35. 35. Sample Apps 點按 Corona Simulator 的 [Sample Apps] 裏面有很多分類好的範例,都有程式碼可供學習
  36. 36. Step-by-step example 點按 [Demo] 有幾個一步步教學
  37. 37. Playing Corona Demos
  38. 38. Demo: Images & Text
  39. 39. Demo: Touch & Sound
  40. 40. Demo: Physics
  41. 41. Text Editor TextMate for Mac Notepad++ for Windows
  42. 42. Project Structure • Project_Folder (top-level) – images (folder) – audio (folder) – videos (folder) – data (folder, read-olny files, e.g. json and xml, fonts) – scripts (folder, other Lua files, apart from main.lua) – main.lua (every project must contain a main.lua) – config.lua (Configuration settings for an app) – build.settings (Build-time settings for an app) – Icon-hdpi.png, Icon-mdpi.png, Icon-ldpi.png 一定要有 main.lua,其它檔案可有可無
  43. 43. 體驗活動 實作:Hello World HelloWorld
  44. 44. 進行流程 1 建立 HelloWorld 資料夾 2 編輯 main.lua 3 用 Corona Simulator 載入 main.lua 4 Build 出 Android .apk 檔
  45. 45. 2 編輯 main.lua -- print 會把字串印到 Corona Simulator Output 視窗 print("Hello World") -- 建立 "Hello World" 文字 -- 語法: display.newText([parentGroup], string, left, top, font, size) local myText = display.newText("Hello World!", 50, 50, "Arial", 60) -- 設定文字顏色為紅色 -- 語法: [object]:setTextColor(R, G, B) myText:setTextColor(255, 0, 0) 本例會在畫面上產生一個 Hello World 的文字 也會在 Corona Simulator Output 視窗印出 Hello World
  46. 46. 3 用 Corona Simulator 載入 main.lua
  47. 47. 4 Build Android .apk 點按 [File > Build for Android (Ctrl + B)] 在 [Save to Folder] 欄位輸入存放 .apk 檔的資料夾
  48. 48. 在手機上安裝並執行 App
  49. 49. Text, Shapes, Images, Audio
  50. 50. Text and Image local background = display.newImage( "world.jpg" ) local myText = display.newText( "Hello, World!", 0, 0, native.systemFont, 40 ) myText.x = display.contentWidth / 2 myText.y = display.contentWidth / 4 myText:setTextColor( 255,110,110 ) 點按 [Sample Apps > Getting Started > HelloWorld] 注意!myText 的 x, y 是自己的中心點,不是 left 和 top
  51. 51. 座標系統 (x, y): x 是水平位置,y 是垂直位置 左上角的座標是 (0, 0)
  52. 52. 解析度百百種 iPad 768x1024 iPhon4 640x960 Galaxy SIII 720x1280 Nexus One 480x800
  53. 53. 自動縮放
  54. 54. Content Area -- config.lua application = { content = { width = 320, height = 480, scale = "letterbox" } } 在 config.lua 裏定義 Content Area 的寬和高 在不同的裝置上,Corona 會自動縮放 Text, Image, Vector
  55. 55. Scale methods 模式 說明 letterbox 等比例縮放。整個 Content Area 都會在 Screen 裏,但 是設備的畫面比例如果跟 Content Area 不一樣,畫面 可能會產生黑邊。黑邊還是可以利用,只要把視覺元 素放到 Content Area 外即可。 zoomEven 等比例縮放。但設備畫面比例如果跟 Content Area 不 一樣,部份內容可能會被犧牲掉 (被裁減掉)。 zoomStrech 填滿整個 Screen。預設的 method。畫面會撐開導致 內容變形。因為會扭曲 Content Area,所以不建議用 這種模式。
  56. 56. 體驗活動 實作:認識 Scaling
  57. 57. Fishes - 水族箱 Droid 點按 [Sample Apps > Graphics > Fishes] 開啟範例 點按 [ViewAs > iPhone 5] 模擬 iPhone 5
  58. 58. 開啟 config.lua -- config.lua application = { content = { width = 320, height = 480, scale = "letterbox" } } 點按 [File > Show Project Files ] 打開專案資料夾 然後用編輯器打開 config.lua,原始內容如上
  59. 59. 刪除 Content Area 的設定 -- config.lua application = { } Content Area 解析度會變成 iPhone 5 的 640 x 1136 因為水族箱沒有等比例縮放,所以魚跑出去了
  60. 60. letterbox 模式 -- config.lua application = { content = { width = 320, height = 480, scale = "letterbox" } } letterbox 會等比例縮放 但因為 iPhone 5 畫面比例不一樣,所以上下有黑邊
  61. 61. zoomEven zoomStrech zoomEven: 等比例縮放,但內容被切掉了一部份 zoomStrech: 填滿整個 Screen,不過內容變形了
  62. 62. Shapes display.newline() - 線 display.newRect() - 矩形 display.newRoundedRect() - 有圓角的矩形 display.newCircle() - 圓形
  63. 63. 體驗活動 實作:認識 Shapes Shapes
  64. 64. 建立 config.lua -- config.lua application = { content = { width = 320, height = 480, scale = "letterbox" } } 輸入上列內容以設定 Content Area 與 Scaling
  65. 65. 畫出三角形 _W = display.contentWidth _H = display.contentHeight -- 利用 newLine() 畫出三角形, 框線寬度為 3,框線顏色為白色 -- 語法: display.newLine([parentGroup], x1, y1, x2, y2) local l = display.newLine(_W/2, 0, 0, _H/4) l.width = 3 l:setColor(255, 255, 255) -- 畫出三角形另外兩條邊 -- 語法: lineObject:append(x, y, [x2, y2...]) l:append(_W, _H/4, _W/2, 0) 建立 main.lua,然後輸入上列程式碼以畫出三角形
  66. 66. 畫出矩形 -- 利用 newRect() 畫出矩形,填充顏色為黃色, -- 白色筆刷,寬度為 3 -- 語法: display.newRect([parentGroup], left, top, width, height) local r = display.newRect(0, _H/4, _W, _H*3/4) r:setFillColor(255, 255, 0) r.strokeWidth = 3 r:setStrokeColor(255, 255, 255)
  67. 67. 畫出圓形 -- 利用 newCircle() 畫圓,半徑為 80, -- 填充色為綠色,黑色筆刷,寬度為 4 -- 語法: display.newCircle([parentGroup,] xCenter, yCenter, radius) local c = display.newCircle(_W/2, _H*3/5, 80) c:setFillColor(0, 255, 0) c.strokeWidth = 4 c:setStrokeColor(0, 0, 0)
  68. 68. 體驗活動 實作:翻滾吧!小魚 HelloTransition
  69. 69. 簡易動畫說明 1 讓魚游到右上角 2 移動時魚要翻滾
  70. 70. 1 載入背景及魚的圖檔 -- 載入水族箱背景 local background = display.newImage("bkg.jpg") -- 載入魚的圖檔 local fish = display.newImage("fish.png", 30, 220)
  71. 71. 2 加上簡單的動畫 -- 載入水族箱背景 local background = display.newImage("bkg.jpg") -- 載入魚的圖檔 local fish = display.newImage("fish.png", 30, 220) function listener(object) print("I am here!!!") end -- 讓魚花 3.5 秒鐘的時間移動到右上角 -- 移動時要翻滾 360 度, 快要到達時減速 -- 完成移動後就呼叫 listener() transition.to(fish, {time=3500, x=250, y=80, rotation=360, transition=easing.outExpo, onComplete=listener}) 移動完成時,Output 視窗 會印出 "I am here!!!"
  72. 72. transition.to() 功能說明 語法 在指定時間內轉換 display object 的狀態,例如 移動位置(x and y)、透明度(alpha)、大小(width and height)、縮放比例 (xScale, yScale) 等 transition.to( target, params ) Control Property 說明 time 指定轉換的時間,預設是 500 (單位:milliseconds) delay 指定轉換前的延遲時間,即多久後開始轉換,預設是 0 delta false 表示 target property 為指定值,true 為變動值。例如 y=100,false 時會移動到 100,true 是往下移動 100單位 transition 設定轉換的 easing function,見下頁說明 onStart 轉換開始會呼叫的 listener function,target 會傳給 listener onComplete 轉換完畢會呼叫的 listener function,target 會傳給 listener
  73. 73. Easing Functions 功能說明 Easing Functions 是緩和用的函式,可以讓動畫 變得比較平滑緩和一點 Easing Function 說明 easing.inExpo() 開始速度為 0,然後才加速。內插值算法為指數函數 easing.inOutExpo() 開始速度為 0,接著加速,然後再放慢速度。內插值算法 為指數函數 easing.inOutQuad() 開始速度為 0,接才加速,然後再放慢速度。內插值算法 為二次函數 easing.inQuad() 開始速度為 0,然後才加速。內插值算法為二次函數 easing.linear() 使用線性函數計算內插值,預設的 easing function easing.outExpo() 開始速度很快,快到達時減速。內插值算法為指數函數 easing.outQuad() 開始速度很快,快到達時減速。內插值算法為二次函數
  74. 74. Easing Functions 的比較 點按 [Sample Apps > Graphics > Easing Examples] 打開範例
  75. 75. 體驗活動 認識 Display Group HelloDisplayGroup
  76. 76. Display Group 遊戲載入後 titleScreen 會往上移 然後開始進行遊戲 Display Group 可以包含其它 display objects,方便管理一群 display objects,例如一起移動一群(組)物件。 Display Group 很類似 Photoshop 圖層的概念
  77. 77. 遊戲流程 1 往上移動 titleScreen 2 移動完成後開始遊戲 讓小魚進行翻滾
  78. 78. 1 載入背景及魚的圖檔 -- 載入水族箱背景 local background = display.newImage("bkg.jpg") -- 載入魚的圖檔 local fish = display.newImage("fish.png", 30, 220) -- 載入音效檔 local bubble = audio.loadSound("bubble.wav") -- 開始進行遊戲 function startGame() -- 讓魚花 3.5 秒鐘的時間移動到右上角 -- 移動時要翻滾 360 度, 快要到達時減速 transition.to(fish, {time=3500, x=250, y=80, rotation=360, transition=easing.outExpo}) audio.play(bubble) end
  79. 79. 2 顯示 titleScreen -- 顯示 titleScreen Display Group function showTitleScreen() -- 建立 titleScreen Display Group local titleScreen = display.newGroup() -- 產生兩個 display objects 並放入 titleScreen display.newText(titleScreen, "開心水族箱", 20, 110, "Arial", 50) display.newText(titleScreen, "Start", 120, 280, "Arial", 40) -- 花 1.2 秒把 titleScreen 往上移,1 秒後開始動作 -- 移動完成時呼叫 startGame() transition.to(titleScreen, {time=1200, delay=1000, y=-480, onComplete=startGame}) end showTitleScreen() 這就是所謂的場景轉換,使用 storyboard 來管理會更簡單
  80. 80. Current Stage 1 往上移動 2 移回原位 Current Stage 是最上層的 Display Group 可利用 display.getCurrentStage() 取得
  81. 81. 移動畫面 -- 載入背景圖 display.newImage( "world.jpg" ) -- 顯示 "Hello World" local myText = display.newText("Hello, World!", 0, 0, nil, 40) myText.x = display.contentWidth / 2 myText.y = display.contentWidth / 4 myText:setTextColor( 255,110,110 ) -- current stage 是最上層的 Display Group stage = display.getCurrentStage() -- 花 1.2 秒把 stage 往上移,1 秒後開始動作 transition.to(stage, {time=1200, delay=1000, y=-480}) -- 花 1.2 秒把 stage 移回原位,2.5 秒後開始動作 transition.to(stage, {time=1200, delay=2500, y=0}) HelloTransition2
  82. 82. Events and Listeners
  83. 83. Events • • • • • System Timers Buttons Collision Audio
  84. 84. Event Types • Runtime Events – enterFrame - occurs at fps interval (30 or 60) – system - such as app suspend or exit – orientation - changes from portrait to landscape or vice-versa • Local events, such as: – – – – – – touch (hit) - user touches the device screen / display objects collision - two physics object collide timer - a running timer completes its duration audio - an audio file finishes playing networkRequest - network requests phase/status/response location (GPS) - generated by the GPS hardware
  85. 85. GearRotaion enterFrame Event -- 載入齒輪 gear 於畫面中央 local gear = display.newImage("gear.png") gear.x = display.contentWidth / 2 gear.y = display.contentHeight / 2 -- 讓齒輪每一個 Frame 旋轉 1 度 local function animate(event) gear.rotation = gear.rotation + 1 end Runtime:addEventListener("enterFrame", animate) -- 可以利用 xScale, yScale 調整齒輪的縮放比例 gear.xScale, gear.yScale = 0.8, 0.8 利用 enterFrame 事件讓齒輪產生旋轉的效果
  86. 86. HelloTouch Touch Event _RADIUS = 20 local tapSound = audio.loadSound("beep.mp3") -- 在 touch 的位置畫出一顆黃色的球 local function onTouch(e) -- 有 began, moved, ended 和 cancelled -- 四種 touch events -- 這裏只處理 began event if e.phase == "began" then local circle = display.newCircle(e.x, e.y, _RADIUS) circle:setFillColor(255, 255, 0) audio.play(tapSound) return true end end Runtime:addEventListener("touch", onTouch) 使用 addEventListener() 註冊 Listener 使用 removeEventListener() 移除 Listener
  87. 87. HelloTimer HelloTimer - function listener local timeDelay = 500 local iterations = 20 -- Timer delay 時間 -- 重複次數 -- 畫出白色的 Text text = display.newText("0", 115, 105, "Arial", 160) text:setTextColor(255, 255, 255) -- 定義 function listener function listener(event) local count = event.count text.text = count if count >= iterations then timer.performWithDelay(timeDelay, listener, iterations) end end -- 在 timer up 時呼叫 listener,重複指定次數 timerID = timer.performWithDelay(timeDelay, listener, iterations) 畫面上的數字會從 0 數到 20,然後再從 1 數到 20…
  88. 88. HelloTimer2 HelloTimer2 - table listener local timeDelay = 500 local iterations = 20 -- Timer delay 時間 -- 重複次數 -- 畫出白色的 Text text = display.newText("0", 115, 105, "Arial", 160) text:setTextColor(255, 255, 255) -- 定義 table listener function text:timer(event) local count = event.count self.text = count if count >= iterations then timer.performWithDelay(timeDelay, text, iterations) end end -- 在 timer up 時呼叫 listener,重複指定次數 timer.performWithDelay(timeDelay, text, iterations) 畫面上的數字會從 0 數到 20,然後再從 1 數到 20…
  89. 89. 體驗活動 實作:Hello Animation HelloAnimation
  90. 90. 跑來跑去的球 1 定義球半徑、球速與方向 2 在畫面中央畫出黃色的球 3 加上動畫讓球移動 碰到邊邊時切換方向
  91. 91. 定義 Content Area -- config.lua application = { content = { width = 320, height = 480, scale = "letterbox" } } 輸入上列內容以設定 Content Area 與 Scaling
  92. 92. 1 定義球半徑、球速與方向 _W = display.contentWidth _H = display.contentHeight -- 定義球半徑、球速與預設方向 local radius = 20 local xspeed = 7.5 local yspeed = 6.4 local xdirection = 1 local ydirection = 1 xdirection = 1 往正向移動 (右),-1 則反向移動 (左) ydirection = 1 往正向移動 (下),-1 則反向移動 (上)
  93. 93. 2 在畫面中央畫出黃色的球 -- 在畫面中央畫出一顆黃色的球 local ball = display.newCircle( _W/2, _H/2, radius) ball:setFillColor(255, 255, 0)
  94. 94. 設定畫面四邊的位置 -- 設定畫面四邊的位置 -- 這邊是 letterbox 的算法,zoomEven 算法不一樣 local screenTop = 0 local screenBottom = _H local screenLeft = 0 local screenRight = _W 待會球會移動,碰到邊邊時要讓球切換方向
  95. 95. 3 加上動畫讓球移動 -- 加上動畫讓球移動,碰到邊邊時切換方向 function animate(eveent) local dx = xspeed * xdirection local dy = yspeed * ydirection local xNew, yNew = ball.x + dx, ball.y + dy if xNew > screenRight - radius or xNew < screenLeft + radius then xdirection = -xdirection end if yNew > screenBottom - radius or yNew < screenTop + radius then ydirection = -ydirection end ball:translate(dx, dy) end Runtime:addEventListener("enterFrame", animate) 動畫的播放預設是 30 fps,每秒 30 格
  96. 96. zoomEven 模式下螢幕四邊的算法 display.viewableContentWidth (0, 0) (display.screenOriginX, display.screenOriginY) display.viewableContentHeight
  97. 97. 所以,四邊位置為… local local local local local d = display -- 變數別名,簡化程式碼 screenTop = d.screenOriginY screenBottom = d.viewableContentHeight + d.screenOriginY screenLeft = d.screenOriginX screenRight = d.viewableContentWidth + d.screenOriginX display.screenOriginX 與 display.screenOriginY 在 zoomEven 模式下,原點通常不是 (0, 0)
  98. 98. 如果很多顆球怎麼辦? 1 定義一個畫球的 function 2 把畫出來的球放進集合 3 針對集合裏的每一顆球 加上動畫讓球移動 一樣碰到邊邊時切換方向 HelloAnimation2
  99. 99. 定義球的各項參數 -- 定義三顆球的參數 (半徑、球速、顏色等) local params = { { radius=20, xdir=1, ydir=1, xspeed=2.8, yspeed=6.1, r=255, g=0, b=0 }, { radius=12, xdir=1, ydir=1, xspeed=3.8, yspeed=4.2, r=255, g=255, b=0 }, { radius=15, xdir=1, ydir=-1, xspeed=5.8, yspeed=5.5, r=255, g=0, b=255 }, }
  100. 100. 1 定義一個畫球的 function -- 定義畫球的 function,新球都會在畫面中央出現 local function newBall(params) local xpos = display.contentWidth*0.5 local ypos = display.contentHeight*0.5 local circle = display.newCircle(xpos, ypos, params.radius) circle:setFillColor(params.r, params.g, params.b) circle.xdir = params.xdir circle.ydir = params.ydir circle.xspeed = params.xspeed circle.yspeed = params.yspeed circle.radius = params.radius return circle end
  101. 101. 2 把畫出來的球放進集合 local collection = {} -- 畫出三顆球,並把球放進 collection 集合 for i=1,#params do local ball = newBall(params[i]) collection[#collection + 1] = ball end
  102. 102. 設定畫面四邊的位置 -- 設定畫面四邊的位置, 這邊是 zoomEven 的算法 local d = display -- 變數別名,簡化程式碼 local screenTop = d.screenOriginY local screenBottom = d.viewableContentHeight + d.screenOriginY local screenLeft = d.screenOriginX local screenRight = d.viewableContentWidth + d.screenOriginX -- config.lua application = { content = { width = 320, height = 480, scale = "zoomEven" } }
  103. 103. 3 加上動畫讓球移動 -- 加上動畫讓球移動,碰到邊邊時切換方向 function animate(event) for _,ball in pairs(collection) do local dx = ball.xspeed * ball.xdir local dy = ball.yspeed * ball.ydir local xNew, yNew = ball.x + dx, ball.y + dy local radius = ball.radius if xNew > screenRight - radius or xNew < screenLeft + radius then ball.xdir = -ball.xdir end if yNew > screenBottom - radius or yNew < screenTop + radius then ball.ydir = -ball.ydir end ball:translate(dx, dy) end end Runtime:addEventListener("enterFrame", animate)
  104. 104. Physics
  105. 105. HelloPhysics 物理效果入門 啟動物理引挈後,木箱就會變成自由落體掉到地面上
  106. 106. 載入背景、地面與木箱 local sky = display.newImage("bkg_clouds.png") sky.x = 160; sky.y = 195 local ground = display.newImage("ground.png") ground.x = 160; ground.y = 445 local crate = display.newImage("crate.png") crate.x = 180; crate.y = 50 crate.rotation = 5 (x, y) 指的是物體自己的中心點 rotation 指的是旋轉角度
  107. 107. 啟動物理引挈並放入物體 local physics = require("physics") physics.start() local sky = display.newImage("bkg_clouds.png") sky.x = 160; sky.y = 195 local ground = display.newImage("ground.png") ground.x = 160; ground.y = 445 physics.addBody(ground, "static") local crate = display.newImage("crate.png") crate.x = 180; crate.y = 50; crate.rotation = 5 physics.addBody(crate) ground 是靜止的物體 (static body),不受重力影響
  108. 108. 影片欣賞 Youtube 影片教學: http://bit.ly/17MQkgn
  109. 109. 體驗活動 實作:HelloPhysics2 HelloPhysics2
  110. 110. 從天而降大量的箱子
  111. 111. 程式流程 1 定義一個產生箱子物體的 function 2 利用 timer.performWithDelay() 每 0.5 秒跑一次 newCrate() 產生箱子
  112. 112. 1 定義產生箱子的 function -- 定義產生箱子的 function function newCrate() local crate = display.newImage("crate.png") crate.x = math.random(320) crate.y = -50; crate.rotation = 5 physics.addBody(crate) end x 座標由亂數產生 y 座標設成負的,感覺就像從螢幕外面放入箱子
  113. 113. 2 利用 timer 每 0.5 秒產生一個箱子 -- 每 0.5 秒跑一次 newCrate() 產生箱子 -- 設定 timer 執行 50 次,設成 0 表示無窮 timer.performWithDelay(500, newCrate, 50) 按 [Ctrl + R] 重新載入,即可看到完成的結果
  114. 114. 比較 density, bounce 的差別 點按 [Sample Apps > Physics > ManyCrates] 會發現:大箱子比較重,最小的箱子比較會彈跳
  115. 115. 體驗活動 實作:拍氣球 ImpulseBallon
  116. 116. 拍氣球 當使用者拍氣球時,就對氣球施力讓它往上飛
  117. 117. 進行流程 1 載入背景、地面與氣球 2 啟動物理引挈並放入物體 3 加入觸控事件處理並讓氣球往上飛
  118. 118. 1 載入背景、地面與氣球 local sky = display.newImage("bkg_clouds.png") sky.x = 160; sky.y = 195 local ground = display.newImage("ground.png") ground.x = 160; ground.y = 445 local balloon = display.newImage("red_balloon.png") balloon.x = 180; balloon.y = -50 因為要從天而降,所以氣球 (ballon) 的 y 座標是負的 氣球圖檔可在 [Sample Apps > Physics > CollisonFilter] 找到
  119. 119. 2 啟動物理引挈並放入物體 local physics = require("physics") physics.start() local sky = display.newImage("bkg_clouds.png") sky.x = 160; sky.y = 195 local ground = display.newImage("ground.png") ground.x = 160; ground.y = 445 physics.addBody(ground, "static") local balloon = display.newImage("balloon.png") balloon.x = 180; balloon.y = -50 physics.addBody(balloon)
  120. 120. 3 加入觸控事件處理 -- 使用者拍氣球時,就推動一下氣球讓它往上飛 function balloon:tap(e) balloon:applyLinearImpulse(0, -0.8, balloon.x, balloon.y) end balloon:addEventListener("tap", balloon) applyLinearImpulse() 會產生一個推動力 第一和第二個參數分別是 x 和 y 方向的推動力 y 是負的,所以氣球會往上飛
  121. 121. 物理引挈 - 進階用法一覽
  122. 122. 橋 (Bridge) 中間是木板連結起來的橋,左右各連結一根竹竿 範例路徑: [Sample Apps > Physics > Bridge]
  123. 123. 鍊條 (Chains) 畫面右半部是連結在一起的鍊條 範例路徑: [Sample Apps > Physics > Chains]
  124. 124. 玩偶 (RagDoll) 玩偶是多個 Shapes 鏈結起來的 物體,可以用繩子操控玩偶 範例路徑: [Sample Apps > Physics > RagDoll]
  125. 125. 物理連結 (Physics Joints) Joint Types 說明 Pivot Joint 樞紐連結。最常用的連結,舉凡輪胎、馬達、齒輪、轉 盤、關節等都可以用 Pivot Joint 完成。在 Box2D 稱為 revolute joint。 Distance Joint 距離連結,以固定距離連結物體 Piston Joint 活塞連結。在 Box2D 稱為 prismatic joint Friction Joint 摩擦連結 Weld Joint 焊接連結。這種連結方式不會移動或旋轉。 Wheel Joint 結合了 piston 與 pivot 兩種 joints。在 Box2D 稱為 line joint。 Pulley Joint 滑輪連結。把繩索連結兩個物體,繩索長度是常數,如 果一物體被往下拉,另一個物體就會往上拉 Touch Joint 觸控連結。把物體連結到目前觸控的位置
  126. 126. Storyboard
  127. 127. Concepts of Storyboard 1 Storyboard 的用途是場景管理 (Scene Management) 2 使用 storyboard.newScene() 建立新場景 3 使用 storyboard.gotoScene() 切換場景 4 5 每個 Scene 物件都有個 view property,也就是其內部 的 display group 在 Scene 生命中的每個階段都有對應的事件
  128. 128. storyboard 範例 點按 [Sample Apps > Interface > Storyboard] 打開範例 觸控後會呼叫 storyboard.gotoScene() 切換到下一個場景
  129. 129. 切換場景 功能說明 語法 範例 切換到指定的場景 storyboard.gotoScene( sceneName [, options] ) storyboard.gotoScene( "scene1", {effect = "fade"}) option 說明 effect 設定場景轉換的效果,例如 fade, zoomOutIn, zoomOutInFade, flip, flipFadeOutIn, ZoomOutInRotate, zoomInOutRotate, fromRight, fromLeft, fromTop, fromButtom, slideLeft, slideRight, slideDown, slideUp, crossFade 等 time 轉換效果的持續時間,預設是 500 milliseconds params (optional) 傳遞給下一個場景的自訂資料。資料會透過 event listeners 傳遞,可從 createScene, willEnterScene 與 enterScene 這幾個事件的 event.params 取得
  130. 130. 建立新場景 -- scene1.lua local storyboard = require "storyboard" local scene = storyboard.newScene() function scene:createScene( event ) -- object creation code here end function scene:enterScene( event ) -- scene logic goes here end scene:addEventListener( "createScene" ) scene:addEventListener( "enterScene" ) return scene 使用 storyboard.newScene() 建立新場景 記得要用 addEventListener() 註冊每個階段的 event listener
  131. 131. 場景的事件 event 說明 createScene 當場景的 view 不存在時會呼叫。通常會在這階段建立 display objects 並加到 self.view 裏 willEnterScene 發生於場景轉換開始前 enterScene 發生於場景移到螢幕上時 (即場景轉換完畢時)。通常會在 這個階段 start timers, load audio, start listeners 等 exitScene 發生於場景即將移開螢幕時。通常會在這個階段 stop timers, unload audio, stop listeners 等 didExitScene 發生於場景移開螢幕時 (即場景轉換完畢時) destroyScene 發生於場景被清除 (purge) 或被移除時 (remove)。通常會 在這個階段 remove listeners, widgets 等 一般來說,willEneterScene 和 didExitScene 比較少用
  132. 132. 清除與移除場景的差別 -- Called immediately after scene has moved onscreen: function scene:enterScene( event ) print( "1: enterScene event" ) -- remove previous scene's view storyboard.purgeScene( storyboard.getPrevious() ) --[[ INSERT code here (e.g. start timers, load audio, start listeners, etc.) ]] end Mobile Devices 記憶體很珍貴,不用時要「節能減碳」 purgeScene() 是清除 display objects,場景將來還可以再 re-load removeScene() 是把整個模組 unload
  133. 133. Scene Template --------------------------------------------------------- scenetemplate.lua (節錄) ------------------------------------------------------- local storyboard = require( "storyboard" ) local scene = storyboard.newScene() -- Called when the scene's view does not exist: function scene:createScene( event ) local group = self.view end -- Called immediately after scene has moved onscreen: function scene:enterScene( event ) local group = self.view end 點按 [Sample Apps > Interface > Storyboard] 打開範例 點按 [File > Show Project Files] 即可找到 scenetemplate.lua
  134. 134. 體驗活動 Hello Storyboard (重寫 HelloDisplayGroup) HelloStoryboard
  135. 135. 遊戲流程 2 1 顯示 titleScreen 場景 切換到 gameScreen 3 讓小魚進行翻滾到 指定地點
  136. 136. 1 main.lua local storyboard = require( "storyboard" ) -- 切換到 titleScreen 場景 storyboard.gotoScene("titleScreen", {effect = "fade", time=300})
  137. 137. 2 titleScreen.lua -- titleScreen.lua local storyboard = require( "storyboard" ) local scene = storyboard.newScene() function scene:createScene( event ) local group = self.view display.newText(group, "開心水族箱", 20, 110, "Arial", 50) display.newText(group, "Start", 120, 280, "Arial", 40) end function scene:enterScene(event) local function showGameScreen() -- 切換場景,花 1.2 秒把 titleScreen 往上移 storyboard.gotoScene("gameScreen", "slideUp", 1200) end timer.performWithDelay(1000, showGameScreen, 1) end scene:addEventListener("createScene", scene) scene:addEventListener("enterScene", scene) return scene
  138. 138. 3 gameScreen.lua -- gameScreen.lua local storyboard = require( "storyboard" ) local scene = storyboard.newScene() local fish = nil local bubble = audio.loadSound("bubble.wav") function scene:createScene( event ) local group = self.view display.newImage(group, "bkg.jpg") fish = display.newImage(group, "fish.png", 30, 220) end function scene:enterScene(event) -- 讓魚花 3.5 秒鐘的時間移動到右上角 -- 移動時要翻滾 360 度, 快要到達時減速 transition.to(fish, {time=3500, x=250, y=80, rotation=360, transition=easing.outExpo}) audio.play(bubble) end scene:addEventListener("createScene", scene) scene:addEventListener("enterScene", scene) return scene
  139. 139. Widget
  140. 140. Widgets • button • switch • segmented control • slider • stepper • spinner • table view (list view) • scroll view • tab bar • picker wheel • progress view 點按 [Sample Apps > Interface > WidgetDemo] 看示範
  141. 141. ButtonEvents 1. 示範 Button widget 2. 使用影像檔製作 button 3. 處理 onPress, onRelease 與 onEvent 事件 點按 [Sample Apps > Interface > ButtonEvents] 看示範
  142. 142. Widget 建立步驟 1 載入 widget library: local widget = require("widget") 2 使用 widget.newXXXX() 產生 widget
  143. 143. HelloWidgets 建立按鈕 local widget = require( "widget" ) local function btnClicked(event) print(event.target.id .. ": Hello World") end -- Create a simple button widget.newButton { id = "simple button", left = 60, top = 120, label = "Say Hello", onRelease=btnClicked }
  144. 144. 建立切換鈕 local function onOffSwitchListener(event) print("On/Off SwitchnIs on?: " .. tostring(event.target.isOn)) end -- Create a default on/off switch local onOffSwitch = widget.newSwitch { left = 100, top = 230, initialSwitchState = true, onPress = onOffSwitchListener }
  145. 145. Corona Simulator Output 點按 Button 或 Switch 時,在 Output 視窗裏看見的訊息
  146. 146. 工具箱 (3rd Party Tools)
  147. 147. Koneki LDT Lua Devepment Tools (LDT) 是 Eclipse-based 的 Lua IDE
  148. 148. Outlaw IDE 有免費版: Outlaw Lite version,可建立專案的數量有限
  149. 149. 有 syntax highlighting 與 auto complete 功能
  150. 150. TexturePacker 用來產生 Sprite sheet 圖檔
  151. 151. 用來設定 Physics Parameters 以建立 Collision shapes
  152. 152. Gumbo - Corona Level Designer Gumbo 可以自動產生 UI 的 Lua Code,有 Web 與 PC 版
  153. 153. LevelHelper 用拖曳 (Drag and drop) 的方式建立關卡 (level)
  154. 154. Path Movement Joints Custom Shapes Cutting Engine
  155. 155. tiled map editor
  156. 156. Lime 2D Tile Engine Lime 可以使用 Tiled 產生的 Map
  157. 157. Feature Demo: http://bit.ly/17jGVMr
  158. 158. 補充資料
  159. 159. App Icons for iOS File Size (w x h) Purpose Icon.png 57 x 57 Icon - iPhone Icon@2x.png 114 x 114 Icon - Retina iPhone Icon-72 72 x 72 Icon - iPad Icon-72@2x.png 144 x 144 Icon - Retina iPad Icon-Small-50.png 50 x 50 Search - iPad Icon-Small-50@2x.png 100 x 100 Search - Retina iPad Icon-Small.png 29 x 29 Search - iPhone Icon-Small@2x.png 58 x 58 Search - Retina iPhone
  160. 160. App Icons for Android File Size (w x h) Icon-xhdpi.png 96 x 96 Icon-hdpi.png 72 x 72 Icon-mdpi.png 48 x 48 Icon-ldpi.png 36 x 36
  161. 161. Android Manifest Permissions -- build.settings settings { android = { versionCode = "11", -- App 版本號碼 version 1.1 usesPermissions = { "android.permission.INTERNET", "android.permission.VIBRATE", "android.permission.ACCESS_FINE_LOCATION", "android.permission.CAMERA", "android.permission.REBOOT", }, }, } 在專案資料夾下建立 build.settings 上列這些設定代表需要: 「存取網路、設備震動、GPS、Camera 以及重開機」等權限
  162. 162. Android 支援的 Permissions http://bit.ly/S2Met
  163. 163. HelloVibrate HelloVibrate 安裝時會要求「控制震動」的權限 點按 App 的 [Vibrate] 按鈕就會產生震動
  164. 164. build.settings -- build.settings settings = { android = { usesPermissions = { "android.permission.VIBRATE", } } }
  165. 165. main.lua local widget = require( "widget" ) local function btnClicked(event) -- 讓設備震動 system.vibrate() end -- Create a simple button widget.newButton { left = 60, top = 120, label = "Vibrate", onRelease=btnClicked } 只要 system.vibrate() 一行程式碼就可以讓設備震動一下
  166. 166. 如何發Email與簡訊
  167. 167. native.showPopup() 功能說明 語法 顯示系統預設的 popup window 可用來發 Email, SMS 簡訊, twitter 訊息等 native.showPopup( name, options ) 點按 [Sample Apps > Netwokring > ComposeEmailSMS] 打開範例
  168. 168. 發 HTML Email -- 發一封 HTML email 給兩位收件人 local options = { to = { "john.doe@somewhere.com", "jane.doe@somewhere.com" }, cc = { "john.smith@somewhere.com", "jane.smith@somewhere.com" }, subject = "My High Score", isBodyHtml = true, body = "<html><body>I scored over <b>9000</b>!!!" "Can you do better?</body></html>", attachment = { { baseDir=system.ResourceDirectory, filename="email.png", type="image" }, { baseDir=system.ResourceDirectory, filename="coronalogo.png", type="image" }, }, } native.showPopup("mail", options)
  169. 169. 執行結果
  170. 170. 發 SMS 簡訊 -- 發一則 SMS 簡訊 (不支援夾檔) local options = { to = { "1234567890", "9876543210" }, body = "I scored over 9000!!! " .. "Can you do better?" } native.showPopup("sms", options)
  171. 171. 保存 Game Settings 1 到這裏 http://bit.ly/1f1lh3O 下載 loadsave.lua loadsave.lua 可以把 Lua table 存成 json 檔,也可以反 過來把 json 檔轉成 Lua table 2 以 saveTable(tableName, filename) 保存設定 3 以 tableName = loadTable(filename) 載入設定
  172. 172. 保存設定 local loadsave = require("loadsave") appSetings = { musicOn = true, score = 80, lives = 1 } loadsave.saveTable(appSettings, "appSettings.json") appSettings.json 會被儲存到 system.DocumentsDirectory 如 /data/data/com.coopermaa.helloworld/appSettings.json
  173. 173. 載入設定 local loadsave = require("loadsave") appSettings = loadsave.loadTable("appSetings.json") if appSettings == nil then appSettings = { musicOn = true, score = 0, lives = 3} loadsave.saveTable(appSettings, "appSetings.json") end 若找不到檔案,loadTable() 會回傳 nil 可判斷回傳值以決定是否使用預設值
  174. 174. 使用自訂字型 (Load Custom Fonts) CustomFont
  175. 175. 不喜歡系統預設字型嗎? -- 使用系統預設字型顯示 Text display.newText("12345", 30, 60, native.systemFont, 90) display.newText("24680", 30, 180, native.systemFont, 90)
  176. 176. 安裝自訂字型 - iOS -- build.settings settings = { iphone = { plist = { UIAppFonts = { "fonts/DS-DIGI.ttf" }, UIApplicationExitsOnSuspend = true } } } 以 DS-Digital 字型為例: http://bit.ly/7dqQ7G 把字型檔 DS-DIGI.ttf 放到一個資料夾下 (e.g. fonts)
  177. 177. 安裝自訂字型 - Mac, Windows, Android Mac: 在字型檔上點按兩下以安裝 Windows: 在字型檔按右鍵,然後選 [安裝] Android: 把字型檔放到專案資料夾裏 注意事項: 1. Windows 裝好字型後,必須重開 Corona Simulator 才能載入字型 3. 在 Android 上,字型檔名大小寫有別,而且副檔名一定要用小寫
  178. 178. 在 Windows 7 上安裝字型
  179. 179. 使用自訂字型 -- 使用自訂字型 DS-Digital 顯示 Text display.newText("12345", 30, 60, "DS-Digital", 100) display.newText("24680", 30, 180, "DS-Digital", 100) 在 Mac 與 Windows 上,字型名稱可能會不一樣 在 Android 上,檔案名稱 (不加副檔名) 就是字型名稱
  180. 180. 讓程式跨平台 -- 同一套字型,在不同平台下名稱可能會不一樣 -- 底下會根據平台調整字型的名稱 local platform = system.getInfo("platformName") local font = "DS-Digital" if platform == "Win" then font = "DS-Digital" elseif platform == "Android" then -- filename with no extension, case sensitive font = "fonts/DS-DIGI" else -- Mac and iOS font = "DS-DIGI" end -- 使用自訂字型 DS-Digital 顯示 Text display.newText("12345", 30, 60, font, 100) display.newText("24680", 30, 180, font, 100)
  181. 181. 在 App 中置入廣告
  182. 182. 廣告目的
  183. 183. Corona SDK 支援的廣告網路
  184. 184. 置入 Google AdMob 廣告的步驟 1 申請 AdMob 帳號 2 到 AdMob 網站新增應用程式 3 整合 AdMob 廣告到你的 App 裏
  185. 185. 1 申請 AdMob 帳號 連到 http://www.google.com.tw/ads/admob/ 點按 [申請 AdMob]
  186. 186. 直接用 Google 帳號登入 點按右上角的 [登入] 直接用 Google 帳號登入 或是填寫表單申請新的 Google 帳號也可以
  187. 187. 輸入 Google 帳密
  188. 188. 填寫個人資料後按 [提交]
  189. 189. 添加第一個應用程式 這是第一次新增 App 的畫面 以後要從 AdMob 首頁進入以新增 App (見下頁)
  190. 190. 新增網站/應用程式 以後新增 App 要從這個位置進入
  191. 191. 輸入稅務資料 在使用 AdMob 前,要先輸入收款的稅務資料 付款詳細資料建議用 PayPal,屆時可轉帳到指定銀行帳號
  192. 192. 2 到 AdMob 網站新增應用程式 點按 [網站與應用程式 > 新增網站/應用程式] 並點按 [Android 應用程式]
  193. 193. 填寫應用程式資料 有關 Android 套裝 URL 請見下頁說明
  194. 194. Android 套裝 URL 把 App 在 Google Play 上的網址(上圖紅框處) 填入Android 套裝 URL 欄位。這只是方便讓使用者移至 App 詳細資料頁面,輸入 個人網站也可以,不寫也沒關係
  195. 195. 下載 AdMob Android SDK (Java User only) 用 Corona SDK 寫 App 的不需下載
  196. 196. 收益報告 點按 [網站與應用程式 >網站與應用程式] 即可看到收益報告
  197. 197. 管理設定 在收益報告頁面上點 App 的 [管理設定]
  198. 198. 取得發佈商 ID 之後 App 要用發佈商 ID 跟 AdMob 整合
  199. 199. 3 整合 AdMob 廣告到你的 App 裏 -- build.settings settings = { plugins = { -- key is the name passed to Lua's 'require()' ["CoronaProvider.ads.admob"] = { -- required publisherId = "com.coronalabs", }, }, } 在 build.settings 檔中加入上列設定 其它廣告網站請參考 http://bit.ly/1eofiHE
  200. 200. 在程式裏加入顯示廣告的程式碼 -- main.lua -- 載入 'ads' library (在 Simualtor 下無法使用廣告) local ads = require "ads" -- 發佈商 ID local appID = "a152396ea402f78" myText = display.newText( "Hello AdMob", 50, 50, "Arial", 32 ) local function adListener(event) -- 收不到廣告時,印出錯誤訊息 if event.isError then print(event.response) end end -- 設定廣告 appID ads.init( "admob", appID, adListener ) -- 在指定位置顯示廣告,每 60 秒更新一次 ads.show( "banner", { x=0, y=250, interval=60 } )
  201. 201. 手機上執行的結果 HelloAdMob
  202. 202. 參考資料 • • • • • • AdMob 帳號申請 申請 AdMob 並設定付款資料 Android 教學之 AdMob與AdSense行動廣告 如何領取 Google AdMob 手機廣告收入 https://github.com/coronalabs/plugins-sample-ads-admob 如何申請 PayPal 帳戶
  203. 203. 申請 PayPal 帳號
  204. 204. 申請 PayPal • • • • • eBay 子公司 線上金流 可用來線上付款 也可以線上收款,包括收取 AdMob 的款項 網站: https://www.paypal.com/tw
  205. 205. 註冊帳號 到 PayPal 網站點右上角的 [立即註冊]
  206. 206. 選擇 [個人] PayPal 帳號 [個人] 不能接受別人信用卡付款,[特選] 可以,但是要手 續費,適合網拍賣家,[商業] 適合公司行號
  207. 207. 填寫個人資料 可以用中文填寫。日後用 email 登入 PayPay
  208. 208. 設定密碼提示
  209. 209. 輸入信用卡卡號 輸入信用卡卡號才可以用 PayPal 線上購物刷卡 若不需要線上購物付款,例如只是用來收 AdMob 款項者 可跳過與信用卡相關的步驟
  210. 210. 確認電子郵件啟用帳號
  211. 211. 完成電子郵件確認 輸入 PayPay 登入密碼後即完成電子郵件確認
  212. 212. 確認信用卡郵件 等收到信用卡月結單時,上面會有 NTD 70 的費用 要找一下 4 位數代碼
  213. 213. 信用卡認證 點按 [獲得認證]。PayPal 會從信用卡帳戶扣除 NTD 70,目 的是確認此信用卡是否為您所有
  214. 214. 輸入 4 位數代碼
  215. 215. 完成認證 會看到「感謝您!我們會在24小時內退還所有費用。」
  216. 216. 帳戶變成 [已認證] 之後便可以用 PayPal 線上付款
  217. 217. 使用 PayPal 領取 AdMob 廣告收入
  218. 218. 收到 AdMob 付款通知
  219. 219. 登入 PayPal
  220. 220. 登入後,前往我的帳戶
  221. 221. 會看到 AdMob 的付款資訊 點按 [接受]
  222. 222. 接受付款
  223. 223. 提領 在 [我的帳戶] 底下點按 [提領]
  224. 224. 選擇提領交易款項的方式 點按 [提領交易款項到你的銀行帳戶]
  225. 225. 輸入銀行帳戶資料
  226. 226. 核對資料
  227. 227. 輸入交易款項金額
  228. 228. 最後按下 [提交]
  229. 229. 完成交易
  230. 230. 會收到轉帳通知郵件 等轉帳完成,就可以在你的銀行帳號看到入帳囉

×