市場上可用於跨平台遊戲開發的工具已經愈來愈多,Corona,Unity3D 等等,現在又來了一個 Game Closure,號稱用 HTML5 來開發遊戲的它,到底有什麼特別之處呢?其官網就提到,100﹪ Javascript 以及擁有和原生遊戲一樣的速度,為什麼它可以用 HTML5 都做到原生速度呢?原來它在 iOS 和 Android 都研發了自家的引擎,加入了硬件加速,所以即使是運行 HTML5 亦能做到原生速度一樣。
本文將會使用 Game Closure 來開發一款簡單遊戲﹣是男人就堅持 20 秒,以此來體驗一下 Game Closure。
先說一下結論,覺得沒有用的可以不看。
結論:用來做網頁遊戲還可以(不過如果只做網頁遊戲用 canvas 就已經可以了吧...),用來做 iOS 和 Android 遊戲就自求多福了。
安裝過程不算困難,有些時候可能會安裝不了,只要跟著說明執行 command 就可以解決了。
官網說 Git 要版本要新於 1.7.10,但我 1.7.9 都能安裝,其實應該只要可以從 Github 拿 project 就可以了吧。
第一步先從 Github clone 一份檔案下來
git clone https://github.com/gameclosure/devkit
然後執行安裝
cd devkit ./install.sh
安裝途中我曾經遇到過這個錯誤:
其實就跟它執行一下 chown 這句就解決了,為什麼它不一早就提醒我呢?
就這樣就安裝完成,還有問題就看官網!
安裝完成後就來建立一個新 Project 玩玩,只需輸入以下 command。
basil init man20
新 Project man20 就建立好了。
或者你會注意到 command line 有這樣的一行:
[register] adding man20何謂 register?你可以想像成 basil 是一個遊戲平台,在你建立新 Project 時,它還會把這個 Project 自動登記到這個平台上,就像介面所示。
因此要記住:當你想移除一個 Project 時,除了執行 "rm" 把檔案系統中的 Project 移除之外,還要叫 basil 清理一下平台上的資料庫。
basil clean-register
亦因此,如果你從網上下載了別人的 Project,你也要把這個 Project register 到平台上才可以運行。這一步其實很奇怪,為什麼要把遊戲平台和開發平台結合在一起而不是兩者分開呢?西杰想不通!
建立了新 Project 後就要運行了,執行一下:
basil serve -p 8080
用了 -p 8080 就會把平台運行在 8080 port 之上。
按一下 Simulate 就會開始運行遊戲。
好,一切運作正常,開始寫遊戲!學習新事物,最好當然是動手玩玩,現在就開始寫代碼。
第一步當然是載入遊戲中的自己:
import device; import ui.TextView as TextView; import ui.ImageView as ImageView; exports = Class(GC.Application, function () { this.initUI = function () { var me = new ImageView({ superview: this.view, x: device.width / 2, y: device.height / 2, layout: "box", autoSize: true, image: "resources/images/me.gif" }); }; this.launchUI = function () {}; });
注意事項:
- superview 是指這個 View 應該是哪個 view 的 child view
- device 的闊和高是 device.width 及 device.height
- layout 是用來控制 child view 如何 render,這裏應該沒有影響
- autoSize 為 false 的話 ImageView 會擴大到整個 superview 的大小
- image 中的 path 是按照以下結構設定
簡單易明吧!還有一樣,就是要要角色的位置糾正好,把它真正的“置中”,GC 的 view 提供了 offsetX, offsetY 的屬性:
//regulating the position me.style.offsetX = - me.style.width / 2; me.style.offsetY = - me.style.height / 2;
第二步,讓角色跟著手指走。GC 提供了 Input* 的 event 來解決跨平台的需要(本來在手機要用 touch*,在桌面電腦要用 mouse*),加一個 InputMove 的 event 吧!
this.view.on("InputMove", function (event, point){ me.style.x = point.x; me.style.y = point.y; });
這樣角色就會跟著手指走了,而且還會置中!好了,下一步就是製造敵人,這個要放在 Game Loop 中處理了,跟據官方文件,Game Loop 應該放在 this.launchUI 之中。每個人天生就有對手(不是左手跟右手),遊戲裏的角色當然也有對手,這是由電腦產生的,會從上下左右四個方向進入遊戲畫面。
var Config = { enemyInterval: 130, gameLoopInterval: 1000 / 60 }; var enemies = []; var EnemyBuilder = { lastEnemyCreateTime: 0, buildWhenAppropriate: function (view){ if (new Date - this.lastEnemyCreateTime > Config.enemyInterval){ //create a new enemy var newEnemy = new ImageView({ superview: view, layout: "box", autoSize: true, image: "resources/images/enemy.gif" }); newEnemy.velocity = { x: (Math.random() < 0.5 ? 1 : -1) * (Math.random() * 200 + 200) / 1000, y: (Math.random() < 0.5 ? 1 : -1) * (Math.random() * 200 + 200) / 1000 }; var rand = Math.random(); if (rand < 0.25){ //left newEnemy.style.x = - newEnemy.style.width; newEnemy.style.y = Math.random() * device.height; if (newEnemy.velocity.x < 0){ newEnemy.velocity.x *= -1; } }else if (rand < 0.5){ //top //... }else if (rand < 0.75){ //right //... }else{ //bottom //... } enemies.push(newEnemy); this.lastEnemyCreateTime = + new Date; } } }; this.launchUI = function () { var tht = this; setInterval(function (){ //Game Loop EnemyBuilder.buildWhenAppropriate(tht.view); }, Config.gameLoopInterval); };
注意事項:
- velocity 就是對手的移動速度及方向
- 每隔 130 ms (隨機選擇的一個常數而已) 就會有新對手出現
- Game Loop 要放在 this.launchUI 之中
下一步是要令對手動起來!
var lastUpdateTime = + new Date; setInterval(function (){ //Game Loop var now = + new Date; var delta = now - lastUpdateTime; EnemyBuilder.buildWhenAppropriate(tht.view); //starting from last one such that we can remove from array at any time for (var i = enemies.length - 1; i >= 0; i--){ var enemy = enemies[i]; enemy.style.x += enemy.velocity.x * delta; enemy.style.y += enemy.velocity.y * delta; if (enemy.style.x < -Config.removeBound || enemy.style.x > device.width + Config.removeBound || enemy.style.y < -Config.removeBound || enemy.style.y > device.height + Config.removeBound){ enemy.removeFromSuperview(); enemies.splice(i, 1); } } lastUpdateTime = now; }, Config.gameLoopInterval);
在 Game Loop 中,所有對手的位置都會更新一次,如果超出了界限就當然要移除掉,不然會愈用愈多記憶體,而且愈來愈慢......對手會動,角色也會動,下一步就是撞擊檢查,GC 提供了一個簡單的 library 來做數學運算,其中包括多種撞擊檢查,雖然我們的角色和對手都是圓形,理論上可以有更簡單更有效率的檢查方法,但為了測試 GC,這裏就當它們是長方形來檢查!
if (intersect.rectAndRect(me.getBoundingShape(), enemy.getBoundingShape())){ //collision console.log("collision"); }
很好很簡單,另外亦可看到,使用 GC 的話大家可以直接在瀏覽器中 debug 或 log message,這就是使用 HTML5 的力量了!下一步,加個計時器。
timeLabel = new TextView({ superview: this.view, x: device.width / 2, y: device.height / 2, layout: "box", color: "#CCC", fontFamily: "Georgia", size: 24, text: "test" }); ... timeLabel.setText("Time: " + ((now - gameStartTime) / 1000).toFixed(2) + "s");
奇怪了,計時器在哪?這個時候可以開一開平台中內置的 UI Inspector(不能用瀏覽器的 Inspector,因為這是 canvas...),看看有什麼錯。
一目了然,修改一下。
timeLabel = new TextView({ superview: this.view, x: device.width / 2, y: 20, width: 200, height: 100, offsetX: -100, offsetY: -50, zIndex: 1, layout: "box", color: "#CCC", fontFamily: "Georgia", size: 24, text: "test" });
出來了!
最後加個結局就完成了。
var restartBtn = new ImageView({ superview: tht.view, layout: "box", x: device.width / 2, y: device.height / 2, zIndex: 1, autoSize: true, image: "resources/images/restart.png" }); restartBtn.style.offsetX = - restartBtn.style.width / 2; restartBtn.style.offsetY = - restartBtn.style.height / 2; restartBtn.on("InputSelect", function (event, point){ this.removeFromSuperview(); gameStartTime = + new Date; lastUpdateTime = + new Date; end = false; for (var i = 0, l = enemies.length; i < l; i++){ var enemy = enemies[i]; enemy.removeFromSuperview(); } enemies = []; me.style.x = device.width / 2; me.style.y = device.height / 2; });所謂的結局其實就是一個重新開始按鈕
![](http://dukeland.hk/wp-content/plugins/wp-monalisa/icons/770478.gif)
var xDiff = me.style.x - enemy.style.x; var yDiff = me.style.y - enemy.style.y; var rSum = (me.style.width + enemy.style.width) / 2; if (xDiff * xDiff + yDiff * yDiff < rSum * rSum){
下一步就當然要驗証一下跨平台能力嚕!要在 iOS 中測試,第一步是先讓 basil 在 Xcode 注入它的東西,我也不知道是什麼東西,反正我就信了。
basil install native-ios
然後執行這句 command 就會把你的 project 變為 Xcode project 了。
basil debug native-ios
一 Run!
好像能夠運行,但...變了低清,大概是因為它沒有處理好 Retina 的東西吧。放到 iPhone 中如何呢?
扁過陳水扁...iOS 測試 Fail,Google 了一分鐘也找不到答案,看來相關文檔不多。同事提醒,試試打直又如何?
完美運行,而且也沒變低清,而是圖片縮小了!那麼 Android 如何呢?首先要安裝 SDK 和 NDK,教學在這裏找,由於西杰之前已經安裝了 SDK,現在只需把 SDK path 加到 PATH 中,NDK 我就選擇在官網直接下載。好了,忙完一大輪,是白花了十五分鐘的
結論:用來做網頁遊戲還可以(不過如果只做網頁遊戲用 canvas 就已經可以了吧...),用來做 iOS 和 Android 遊戲就自求多福了。