顯示具有 LimeJS 標籤的文章。 顯示所有文章
顯示具有 LimeJS 標籤的文章。 顯示所有文章

2012-10-03

LimeJS - Node 與繼承

Google Closure Library 提供了繼承的功能。

Round.js
goog.provide('HelloLimeJS.Round');

goog.require('lime.Circle');

/** Constructor */
HelloLimeJS.Round = function(r) {
  // call parents constructor
  goog.base(this);
  
  this.setRadius(r);
};

/** 繼承*/
goog.inherits(HelloLimeJS.Round, lime.Circle);

/** 新增 function */
HelloLimeJS.Round.prototype.setRadius = function(r) {    
  this.setSize(r*2, r*2);
};

2012-10-02

終於關掉 LimeJS 左上角的數字了(FPS)

每個新建的 LimeJS 專案左上角都有個數字在那跳啊跳,今天終於搞清楚他是什麼並關掉了。


原來它是 FPS,也就是 Frame Per Second,這是在影片都會遇到的名詞。

有以下 API 可以用。
director.setDisplayFPS(false);
director.isDisplayFPS();
alert(lime.Director.FPS_INTERVAL); // 100 ms by default
---
---
---

近看 LimeJS 的 Viewport

遊戲設計最累的一個地方在於,要適合各種尺寸的螢幕,不只是桌機的各種尺寸,還有手持行動裝置,基本上應該是列不完的尺寸,根本不可能一一去指定。

如果可以指定遊戲長寬比例後,然後在各種裝置上以放到最大的前提下自動縮放,那不是很完美嗎?這就是 LimeJS 的超能力,而使用這超能力只有兩個地方要注意。
HelloLimeJS.gameW = 600;
HelloLimeJS.gameH = 400;

/** 程式進入點 */
HelloLimeJS.start = function() {
  // 每個遊戲只會有一個導演 director,所以要 keep 起來
  HelloLimeJS.director = new lime.Director(document.body, HelloLimeJS.gameW, HelloLimeJS.gameH);
  HelloLimeJS.director.makeMobileWebAppCapable();
  // 切入主場景
  HelloLimeJS.mainScene();
};
這樣就是一個 3:2 的遊戲 Viewport,可以隨著瀏覽器縮放,但有一個前提,就是傳入 lime.Driector 的第一個參數,必須是一個會隨著瀏覽器縮放的 Dom 物件,body 就是一個很好的選項。

LimeJS - Director, Scene, and scheduleManager

演練 Director、Scene 與 scheduleManager。
HelloLimeJS.html

加入 jQuery 幫忙在迴圈裡傳參數。
<!DOCTYPE HTML>

<html>
<head>
<title>HelloLimeJS</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript" src="../closure/closure/goog/base.js"></script>
<script type="text/javascript" src="HelloLimeJS.js"></script>
<style type="text/css">
#game {
    width: 600px;
    height: 400px;
    margin: 0 auto;
    border: 1px solid #eee;
}
</style>
</head>

<body onload="HelloLimeJS.start()">
<div id="game"></div>
</body>

</html>

2012-09-29

近看 LimeJS 專案管理(create & update)

新建 LimeJS 專案的指令:
python bin/lime.py create HelloLimeJS
除了建立一個 HelloLimeJS 目錄與兩個檔案 HelloLimeJS.html 與 HelloLimeJS.js,還發生了兩件事情:
  • 將專案註冊到 LimeJS 裡。
  • 將專案資訊寫到 closure\closure\goog\deps.js。

2012-09-28

LimeJS 學習筆記

以下筆記主要來自 LimeJS Programming Guide

基礎
UI
應用
參考

Hello LimeJS

在 Windows 安裝 LimeJS 安裝 LimeJS 與建立 HelloLimeJS 後,就來看看 LimeJS 怎麼運作的。

HelloLimeJS 只有兩個檔案,HelloLimeJS.html 與 HelloLimeJS.js。

前面忘了講,LimeJS 必須使用 HTML 5,也就是說瀏覽器必須支援 HTML 5 才能正確執行 Lime JS,README.md 裡提到瀏覽器的支援狀況。

在 Windows 安裝 LimeJS

下載 LimeJS

到 https://github.com/digitalfruit/limejs,這一頁看到的是解開的檔案與目錄,可以點上方的「ZIP」得到壓縮檔。

Windows 安裝

解壓縮後,開啟 README.md,參考 Windows users 部份。

下載與安裝 Git Client

到 http://code.google.com/p/msysgit/downloads/list,下載 Git-1.7.11-preview[.....].exe,安裝時注意要選擇「Run Git from the Windows Command Prompt」。

2012-09-19

LimeJS 在迴圈的 callback 裡傳值

這問題不會只發生在 LimeJS 上,只是 LimeJS 需要多一點的處理。

先看看標準的錯誤方式。
for (...) {
 var fKey = ...;
 var friend = new lime.Sprite()...; 
 $(friend.getDeepestDomElement()).click(function(){
  // 會得到很怪的 fKey
  // 所有的 click 都會得到同一個 fKey
  // 通常應該是迴圈中最後一個物件的 fKey
  alert(fKey);
 });
}
再來就是正確的方式。
for (...) {
 var fKey = ...;
 var friend = new lime.Sprite()...; 
 // friend 本身不是 Dom 物件,不能用來藏值
 $(friend.getDeepestDomElement()).attr('fKey', fKey);
 $(friend.getDeepestDomElement()).click(function(){
  // 在迴圈的 callback 裡讀值,一定得透過 this
  var fKey = $(this).attr('fKey');
  alert(fKey);
 });
}
---

LimeJS 沒有 input, textarea, checkbox, radio...

這真是一個不好的消息,翻遍 LimeJS 文件就是沒看到這些工具,就算是作為一個遊戲的 framework,也總會需要使用者輸入些什麼東西吧!

好消息是,LimeJS 物件可以接受 Dom 物件
var input = new lime.Sprite().setAnchorPoint(0.5,0).setPosition(0,0).setSize(300,100);

// 這樣子解套
var textarea = document.createElement('textarea');
input.appendChild(textarea);

// 因為是 HTML Dom 物件,無法使用 LimeJS 來設定 style,只能回到 CSS 的方式
$(textarea).css('width', '300px').css('height', '100px').css('position', 'relative').css('left', '-150px').css('border', '1px solid #eee');

// 接上軌道
sprite.appendChild(input);

// ...事後可以直接讀值
var val = $(textarea).val();
---

2012-09-18

LimeJS Project 快速瀏覽

如何在 Windows 安裝 LimeJS,可以在下載的 zip 檔裡的 README.md 得到詳細資訊,這裡要紀錄的是,管理 LimeJS Project 常用的指令。
列出所有可用參數。
python bin/lime.py --help
初始化,只要執行一次,會下載 Google Closure Library 與 Closure Compiler,LimeJS 是架構在 Google Closure 上開發出來的。
python bin/lime.py init
建立專案。
python bin/lime.py create AProject
輸出單一的最佳化 Javascript 檔(刪除不必要的空白,置換 local 變數名稱),以預設的範例為例,檔案為 221 KB。
python bin/lime.py build AProject -o AProject/AProject-compiled.js
輸出單一的最佳化進階版 Javascript 檔(置換屬性名稱,有些 coding 上的規定要遵守),以預設的範例為例,檔案為 58 KB。
python bin/lime.py build AProject -o AProject/AProject-compiled-a.js -a
至於 lime.py 會將專案資料寫到 closure/closure/goog/deps.js,這只對別的專案會用到這個專案時,才有關系,因為在 build 別個專案時,lime.py 需要可以讀取的到這個專案的 js 檔才行。 ---

使用 Google ClosureBuilder 產出最佳化的 Javascript 檔

最佳化的 Javascript 指的是「將多個 Javascript 檔組合成單一個 Javascript 檔,並刪除註解等無用的部份,以及最小化變數名稱」,這些動作的目的在於產生一個可以「快速下載」的精簡大檔案。

但是,這個精簡大檔案適用於正式環境,開發時還是用「適合閱讀」的檔案比較好。

ClosureBuilder 只能用來精簡 Google Closure 產生的檔案。

依照官方範例建立程式 start.js。

2012-09-14

LimeJS 的 lime.ui.Scroller 沒有 ScrollBar!

lime.ui.Scroller 預設只能用游標按下拖拉滑動,比較像是觸控螢幕的使用行為,但是桌機還是比較習慣用 ScrollBar 啊!

goog.provide('silent');

goog.require('lime.Director');
goog.require('lime.Scene');
goog.require('lime.Layer');
goog.require('lime.ui.Scroller');
goog.require('lime.scheduleManager');

silent.start = function() {

  var director = new lime.Director(document.body, 1024, 768);
  var scene = new lime.Scene();

  // 加上向左 scroll 的功能
  var left = new lime.Sprite().setAnchorPoint(0,0).setPosition(0,0).setSize(30,30).setFill('#0c0');
  scene.appendChild(left);
  // 游標移上後,連續向左 scroll
  $(left.getDeepestDomElement()).mouseenter(function(){
    lime.scheduleManager.scheduleWithDelay(silent.scrollLeft, scroller, 100);
  });
  $(left.getDeepestDomElement()).mouseleave(function(){
    lime.scheduleManager.unschedule(silent.scrollLeft, scroller);
  });

  // 加上向右 scroll 的功能
  var right = new lime.Sprite().setAnchorPoint(0,0).setPosition(330,0).setSize(30,30).setFill('#0c0');
  scene.appendChild(right);
  // 游標移上後,連續向右 scroll
  $(right.getDeepestDomElement()).mouseenter(function(){
    lime.scheduleManager.scheduleWithDelay(silent.scrollRight, scroller, 100);
  });
  $(right.getDeepestDomElement()).mouseleave(function(){
    lime.scheduleManager.unschedule(silent.scrollRight, scroller);
  });
  
  // 加上 scroller
  var scroller = new lime.ui.Scroller().setAnchorPoint(0,0).setPosition(30,0).setSize(300,30).setDirection(lime.ui.Scroller.Direction.HORIZONTAL);
  scene.appendChild(scroller);
  for (var i=0; i<20; i++) {
    var block = new lime.Sprite().setAnchorPoint(0,0).setPosition(i*30+2,2).setSize(26,26).setFill(i*10,i*10,i*10);
    scroller.appendChild(block);
  }
  
  director.makeMobileWebAppCapable();
  director.replaceScene(scene);

};

silent.scrollLeft = function() {
  // 抽出共用的 silent.scroll
  // 但是 silent.scrollLeft 或 silent.scrollRight 裡的 this 很重要
  // 指的是呼叫 scheduleWithDelay 時傳進去的第二個參數,也就是執行第一個參數的 context 物件
  // 就是 scroller,用來操作 scroll 的動作
  // 但是在抽出時,不使用 call 或 apply 的話,會導致 silent.scroll 裡的 this 不是 silent.scrollLeft 裡的 this
  // 那就傷腦筋了
  silent.scroll.call(this, true);
};

silent.scrollRight = function() {
  silent.scroll.call(this, false);
};

silent.scroll = function(leftOrRight) {
  // 這是座標
  var x = this.moving_.getPosition().x;

  // 接下來是很重要的地方
  // 透過 moving_.getPosition() 得到的是 moving_ 的左上角座標
  // 這個座標和 scroll 的位置是不一樣的東西
  // 舉例說,以 x 軸來看,當 scroll 到 100 時,這時 moving_ 的 x 座標是 -100
  // 就是說,scroll 到 100,等於將 100 移到本來 0 的位置,那原本的 0 就會移到 -100
  
  // 正負互轉後,座標變成 scroll 的位置
  x = -x;
  if (leftOrRight) {
    x -= 10;
  }
  else {
    x += 10;
  }
  this.scrollTo(x);
};

goog.exportSymbol('silent.start', silent.start);
噹,完成!
---

2012-09-13

在 LimeJS 連續播放音樂(Loop Audio)

官方文件沒提到的事情,偷喵原始碼才知道的秘密。

lime/src/audio/audio.js
this.baseElement = document.createElement('audio');
this.baseElement.preload = true;
this.baseElement.loop = false;
兩個重點,第一,原來這是 HTML5 的功能,第二,HTML5 支援連續播放。

那就比照辦理。
var snd = new lime.audio.Audio(path);
snd.baseElement.loop = true;
playAudio(snd);
只要將 baseElement.loop 設為 true 就可以了,playAudio 請看 在 LimeJS 播放音樂的問題(lime.audio.Audio)

另外如果想知道,音樂什麼時候播完,可以這麼做。
var snd = new lime.audio.Audio(path);
goog.events.listen(snd.baseElement, "ended", function() {
 alert('done');
});
playAudio(snd);
---