2012-08-27

關閉 "F7" 按鈕開啟 iTunes

mac 的 F6, F7, F8 等 Media Key 可以控制 VLC, Cog,... 等程式播放音樂歌曲。但其中的 F7 按鈕除了 Play / Pause 之外就是會啟動  iTunes。

若要取消這個功能有以下作法 :
1) 關閉 Function Key, 改用 keymapper ( Function key 改由 Fn+F1, F2,... 啟動 )
   a. 到 System Preferences -> Keyboard, 勾選 
        Use all F1, F2, etc. keys as standard function keys
   b. 安裝 keymapper, 自己設定 F6, F7, F8 的功能

2) 更改 itunes 名稱讓 media key 無法啟動之 (參考這裡)
3) 直接 patch rcd daemon (參考這裡)

第3種方法作者用 python 寫了一個程式去改 rcp 執行檔,改完之後除了啟動 itunes 之外的其它功能都還在,若要復原則只要把原來備份的 rcp 執行檔覆蓋回去就行了,似乎是最好的方法。

2012-08-18

Unity 3D 從 AssetBundle 載入 Lightmap

當場景裡的光源與模型皆靜止時,可使用 Lightmapping 預先計算光照結果,下圖為使用 Lightmap 前 (Directional Light) 及使用 Lightmap 後的差異:

All Terrain Tactical Enforcer (Directional Light)

All Terrain Tactical Enforcer (Lightmapping)

1. 製作 AssetBundle
Lightmap Bake 完成之後將 Model 打包成 AssetBundle,使用指令:
BuildPipeline.BuildAssetBundle(
    Selection.activeObject, 
    Selection.objects, 
    path, 
    BuildAssetBundleOptions.CollectDependencies | 
    BuildAssetBundleOptions.CompleteAssets
);
選擇的檔案除了 Prefab/GameObject 之外,Lightmap 圖片也要選擇:

選擇 Prefab 及 Lightmap

2. 載入 AssetBundle
載入 AssetBundle 時先設定 Lightmap 再載入 GameObject,此場景的 Lightmapping 參數如下:
Lightmapping 參數

按照當初 Lightmapping 之參數做對應的設定:
List arrld = new List();
LightmapData ld = new LightmapData();
ld.lightmapFar = 
aa.assetBundle.Load("LightmapFar-0", typeof(Texture2D)) as Texture2D;
ld.lightmapNear = 
aa.assetBundle.Load("LightmapNear-0", typeof(Texture2D)) as Texture2D;
arrld.Add(ld);
 
LightmapSettings.lightmapsMode = LightmapsMode.Dual;
LightmapSettings.lightmaps = arrld.ToArray();

再載入 GameObject :
GameObject go = GameObject.Instantiate(aa.assetBundle.Load("StaticObj", typeof(GameObject))) as GameObject;
此外慶幸的是,GameObject 之 MeshRenderer 內有關 Lightmapping 之參數在存取 AssetBundle 時皆有自動設定,不需再額外寫程式存取設定之。

程式碼可以在:https://github.com/phardera/unity3d_assetbundle_lightmap.git 取得

2012-07-12

Unity 3D + Lua + iOS 實作筆記

這篇文章概略介紹如何把 Lua 當作 Unity3D 在 iOS 平台上的腳本引擎(若要實作於 Windows 平台可以參考另一篇文章)。範例大略分成三個部分:Unity3D C# 部分、Lua C 部分及 Lua Script 部分,整個程式執行的流程是:
  1. C# 啟動 Lua,並註冊 C#  函數給 Lua (讓 Lua Script 可以呼叫)
  2. 從 iOS 載入 Lua Script 檔案並由 Lua 執行
  3. Lua Script 呼叫 C# 函數
  4. C# 函數印出訊息
最後在 Xcode 的 Output 可以看到 C# 函數印出的訊息,此外值得注意的是,Unity3D 產生的程式碼在模擬器上無法呼叫 Plugins ,所以實作的步驟需要真正的實機才能測試(因此在開始之前必須做好 iOS Developer 相關的設定),底下是整個實作的流程:

1. 開啟 Unity3D 並建立一個空的專案,在專案路徑下建立 Plugins/iOS 目錄,如下圖所示:

2. 到 http://www.lua.org/ftp/ 下載原始碼 lua-5.2.1.tar.gz。解開壓縮檔之後可以看到原始碼在 src 目錄下,將該目錄下所有檔案(除了 Makefile、lua.c、luac.c 之外)複製到 Plugins/iOS 。

3. 建立一個新的 C# Script,命名為 luaTest,此時 Unity3D 的專案目錄呈現如下:

luaTest 內容分成三大部分,一是和 Lua 介接的部分,二是和 lua 之間建立 callback 的部分,三是 Unity3D 程式的部分分別敘述如下:

一、和 Lua 介接的部分:
luaL_newstate、luaL_openlibs 和 lua_close 分別為初始化及關閉 Lua 時呼叫使用。
[DllImport ("__Internal")]
public static extern IntPtr luaL_newstate();

[DllImport ("__Internal")]
public static extern void luaL_openlibs(IntPtr lua_State);

[DllImport ("__Internal")]
public static extern void lua_close(IntPtr lua_State);

lua_pushcclosure 和 lua_setglobal 為註冊 C# 函數給 Lua 時使用。
[DllImport ("__Internal")]
public static extern void lua_pushcclosure(IntPtr lua_State, LuaFunction func, int n);

[DllImport ("__Internal")]
public static extern void lua_setglobal(IntPtr lua_State, string s);

其中 LuaFunction 定義如下:
public delegate int LuaFunction(IntPtr pLuaState);

lua_pcallk 和 luaL_loadfilex 為載入及執行 Lua Script 檔案時使用。
[DllImport ("__Internal")]
public static extern int lua_pcallk(IntPtr lua_State, int nargs, int nresults, int errfunc, int ctx, LuaFunction func);

[DllImport ("__Internal")]
public static extern int luaL_loadfilex(IntPtr lua_State, string s, string mode);

luaL_checklstring 為 C# 函數被 Lua 呼叫時,取得 Lua 所給的參數時使用。
[DllImport ("__Internal")] public static extern IntPtr luaL_checklstring(IntPtr lua_State, int idx, IntPtr len);

此外,使用 DllImport 時需要引入 System.Runtime.InteropServices 名稱空間:
using System.Runtime.InteropServices;

使用 IntPter 時需要引用 System 名稱空間:
using System;

上述 Lua API 在註冊 C# 函數及載入/執行 Lua Script 的部分可寫成 lua_register 及 luaL_dofile 分別如下:
public static void lua_register(IntPtr pLuaState, string strFuncName, LuaFunction pFunc)
{
    lua_pushcclosure(pLuaState, pFunc, 0);
    lua_setglobal(pLuaState, strFuncName);
}

public static int luaL_dofile(IntPtr lua_State, string s)
{
    if (luaL_loadfilex(lua_State, s, null) != 0)
        return 1;
 
    return lua_pcallk(lua_State, 0, -1, 0, 0, null);
}

二、和 lua 之間建立 callback 的部分
1. 建立簡單的 Lua Script ( lua.txt ) 檔案,其內容為:
TestDisplay("Hello world");

將檔案置於專案的 LuaScript 路徑底下,如圖所示:

2. 在 luaTest 內加入 callback 函數如下:
[MonoPInvokeCallbackAttribute (typeof (LuaFunction))]
public static int TestDisplay(IntPtr pLuaState)
{
    IntPtr retPtr =luaL_checklstring(pLuaState, 1, IntPtr.Zero);
    string retStr = Marshal.PtrToStringAnsi(retPtr);
  
    Debug.Log("This line was plotted by TestDisplay() : msg ="+retStr);

    return 0;
}

其中 MonoPInvokeCallbackAttribute 可以預防 mono 在傳遞函數指標時啟動 JIT 的功能(相關參考連結),其定義如下:
[System.AttributeUsage(System.AttributeTargets.Method)]
public sealed class MonoPInvokeCallbackAttribute : Attribute {
    private Type type;
    public MonoPInvokeCallbackAttribute (Type t) { type =t;}
}

luaL_checklstring 負責取得 Lua 在呼叫此函數時給的 "Hello world" 字串指標

三、Unity3D 程式的部分
1. 在 Start 函數加入程式碼:
void Start()
{
    m_luaState = luaL_newstate();
    luaL_openlibs(m_luaState);
    lua_register(m_luaState, "TestDisplay", TestDisplay);
    luaL_dofile(m_luaState, GetAppPath() + "LuaScript/lua.txt");
}

程式碼初始化 Lua 並註冊函數 TestDisplay 給 Lua,最後則是載入 lua.txt 並執行。其中 GetAppPath 函數定義如下:
public static string GetAppPath()
{
    return Application.dataPath.Substring(0, Application.dataPath.Length-4);
} 
m_luaState 定義如下:
public static IntPtr m_luaState = IntPtr.Zero;

2. 在 OnApplicationQuit 函數加入程式碼:
void OnApplicationQuit()
{
    lua_close(m_luaState); 
}

3. 將 luaTest 拖曳至 Main Camera 上,此時在 Inspector 可以看到 luaTest 成為 Camera 的 Component:

編譯時需要稍微做一些設定如下:
1. 在 Build Settings 裡 Switch Platform 至 iOS 之後按下 Build,選擇欲產生的目錄之後 Unity3D 將自動產生 Xcode 專案,開啟後觀察專案底下 Libraries 是否引入 Lua 原始碼:

2. 用滑鼠拖曳 LuaScript 目錄到 Unity-iPhone 上出現訊息如下:

記住此處選擇的是 Create folder references for any added folders。按下 Finish 之後 LuaScript 出現如圖所示:

3. 將裝置接上電腦,編譯的目標選擇 Unity-iPhone > (裝置名稱) 之後按下 Run。

4. 此時觀察 output 視窗的訊息應該顯示如下:

由訊息 "This line was plotted by TestDisplay() : msg =Hello world" 可知 Lua Script 執行成功。範例程式碼可以在 https://github.com/phardera/unity3d_lua_ios 取得。

2012-07-03

Unity 3D 列出 AssetBundle 內容

AssetBundle.LoadAll 指令取得的資料型態是 Object[] ,利用 C# Reflection 功能可以把它轉回原型並取得其中某個成員 (Property value) 的值。程式碼列出如下:
[MenuItem("Assets/Get Content List of Assetbundle")]
static void ListABContent()
{
    string strPath = EditorUtility.OpenFilePanel(
            "Open AssetBundle...", 
            Application.dataPath, 
            "unity3d");
    if (System.IO.File.Exists(strPath) == true)
    {
        WWW fileLoader = new WWW("file://" + strPath);
        object[] content = fileLoader.assetBundle.LoadAll();
 
        Debug.Log("total objects =" + content.Length);
 
        for (int i = 0; i < content.Length; ++i)
        {
            System.Type objType = content[i].GetType();
            System.Reflection.PropertyInfo objProperty = 
                objType.GetProperty("name");
 
            string objName = "<error>";
            try
            {
                objName = (string)objProperty.GetValue(content[i], null);
            }
            catch
            {
            }
 
            Debug.Log(
                "obj[" + i + "] : type="+objType.Name+", name=" + objName
                );
 
        }
 
        fileLoader.assetBundle.Unload(true);
        fileLoader.Dispose();
    }
    else
        Debug.LogError("file not found");
 
}

把程式碼儲存在 C# Script,並置於 Editor 目錄之下,沒問題的話,功能表的 Assets 之下會多出一項 "Get Content List of Assetbundle",點擊之後選擇 Assetbundle 檔案,console 視窗將列出此 assetbundle 之下所有物件的型態 (Type) 及其名稱 (name)。

底下另外註記呼叫成員函數 (invoke method) 的方法:( 假設取得的 object 為 Texture2D,則呼叫其 GetPixels Method 的方法)

System.Reflection.MethodInfo GetPixels_Default = 
    objType.GetMethod("GetPixels", new System.Type[0]);
System.Reflection.MethodInfo GetPixels_Mipmap =
    objType.GetMethod("GetPixels", new System.Type[1] {typeof(int)});
Color[] retPixels;
retPixels =(Color[])GetPixels_Default.Invoke(content[i], null);
retPixels = (Color[])GetPixels_Mipmap.Invoke(content[i], new object[1] { 0 });

2012-05-20

Unity 3D 產生 Texture Atlas

使用 Unity3D  內建的 Texture2D.PackTextures 功能來產生 Texture Atlas 圖片,下面是簡單的範例 :

Texture2D texAtlas =new Texture2D(2048, 2048);
Rect[] arrRc =texAtlas.PackTextures(arrTexSrc, 1);

arrTexSrc 是一個 Texture2D[] 型態的變數,texAtlas.PackTextures 將 arrTexSrc 矩陣裡所有的 Texutre 打包在同一張 Texture ( texAtlas ),並回傳所有被打包的圖片在 texAtlas 的 uv 座標位置 (  arrRc )。

arrTexSrc 的取得方式參考範例 :

Object[] arrFoundTex =Selection.GetFiltered(typeof(Texture2D), SelectionMode.DeepAssets);

將取得的 arrFoundTex 轉成 Texture2D[] 型態變數後丟給 PackTextures 使用。
底下的範例是將 Texture2D 另存成 PNG 格式圖檔 :

byte[] bytedata = texAtlas.EncodeToPNG();
if (bytedata != null)
    System.IO.File.WriteAllBytes(strPath, bytedata);

其中 strPath 是檔案路徑,取得的方式參考 :

string strPath =EditorUtility.SaveFilePanel("Save Texture Atlas...", Application.dataPath, Selection.activeObject.name, "png");

此外值得注意的是,欲打包的圖片在 TextureImporter 必須打開 Read/Write Enabled 設定 ( Texture Type 選擇  Advanced )


2012-04-25

iOS 內建字型

參考這篇文章,iOS 內建的字型列出如下 :

Family name: Hiragino Kaku Gothic ProN W3
    Font name: HiraKakuProN-W3

Family name: Courier
    Font name: Courier
    Font name: Courier-BoldOblique
    Font name: Courier-Oblique
    Font name: Courier-Bold

Family name: Arial
    Font name: ArialMT
    Font name: Arial-BoldMT
    Font name: Arial-BoldItalicMT
    Font name: Arial-ItalicMT

Family name: STHeiti TC
    Font name: STHeitiTC-Light
    Font name: STHeitiTC-Medium

Family name: AppleGothic
    Font name: AppleGothic

Family name: Courier New
    Font name: CourierNewPS-BoldMT
    Font name: CourierNewPS-ItalicMT
    Font name: CourierNewPS-BoldItalicMT
    Font name: CourierNewPSMT

Family name: Zapfino
    Font name: Zapfino

Family name: Hiragino Kaku Gothic ProN W6
    Font name: HiraKakuProN-W6

Family name: Arial Unicode MS
    Font name: ArialUnicodeMS

Family name: STHeiti SC
    Font name: STHeitiSC-Medium
    Font name: STHeitiSC-Light

Family name: American Typewriter
    Font name: AmericanTypewriter
    Font name: AmericanTypewriter-Bold

Family name: Helvetica
    Font name: Helvetica-Oblique
    Font name: Helvetica-BoldOblique
    Font name: Helvetica
    Font name: Helvetica-Bold

Family name: Marker Felt
    Font name: MarkerFelt-Thin

Family name: Helvetica Neue
    Font name: HelveticaNeue
    Font name: HelveticaNeue-Bold

Family name: DB LCD Temp
    Font name: DBLCDTempBlack

Family name: Verdana
    Font name: Verdana-Bold
    Font name: Verdana-BoldItalic
    Font name: Verdana
    Font name: Verdana-Italic

Family name: Times New Roman
    Font name: TimesNewRomanPSMT
    Font name: TimesNewRomanPS-BoldMT
    Font name: TimesNewRomanPS-BoldItalicMT
    Font name: TimesNewRomanPS-ItalicMT

Family name: Georgia
    Font name: Georgia-Bold
    Font name: Georgia
    Font name: Georgia-BoldItalic
    Font name: Georgia-Italic

Family name: STHeiti J
    Font name: STHeitiJ-Medium
    Font name: STHeitiJ-Light

Family name: Arial Rounded MT Bold
    Font name: ArialRoundedMTBold

Family name: Trebuchet MS
    Font name: TrebuchetMS-Italic
    Font name: TrebuchetMS
    Font name: Trebuchet-BoldItalic
    Font name: TrebuchetMS-Bold

Family name: STHeiti K
    Font name: STHeitiK-Medium
    Font name: STHeitiK-Light

2012-04-24

Unity 3D 在 iOS 上顯示中文字串


之前使用 Unity3D 寫遊戲程式都是以 Dynamic Font 功能來顯示中文字串,最近才發現這功能不支援 iOS,因此若要在 iOS 上使用 Dynamic Font 就得自己做了,幸運的是實作起來並不複雜,底下敘述如何將中文字串轉成圖片 ( Texture2D ) 的方法 : ( 概略是利用 iOS 內建的 Font Renderer 先把字串畫在主記憶體裡,再利用 OpenGL 指令將記憶體裡字串的圖片轉成貼圖 )

全部範例檔案有三個 :
1. main.cs
    a. 放在 Assets 目錄底下
    b. 此 Script 依附在 Main Camera 上

2. dynaFont.cs
    a. 放在 Assets/Plugins 目錄底下
    b. 此檔案為 unity3d 內部 script 與 plugin 之間的介面

3. dynaFont.m
    a. 放在 Assets/Plugins/iOS 目錄底下 (轉成 xcode project 時將自動引入)
    b. 不需事先編譯

首先看 main.cs 檔案內容 :


using UnityEngine;
using System.Collections;

public class main : MonoBehaviour {

    // Use this for initialization
    void Start ()
    {
        int nWidth =128;
int nHeight =128;

        //產生 128x128 (注意大小為2冪次方)之 texture
Texture2D tex =
            new Texture2D(
                nWidth, 
                nHeight, 
                TextureFormat.Alpha8
                false);

        //把中文字畫在 texture 上
        genTexture(
            tex.GetNativeTextureID(), 
            "中文測試"
            "Arial"
            10
            128
            128);
}
}


dynaFont.cs 檔案內容如下 :


using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
//
//此為 unity3d 內部程式呼叫外部 plugin 函數之間的介面
//
public class dynaFont
{
    //指示 getTexture 為外部 plugin 函數
  [DllImport("__Internal")]
  public static extern bool genTexture(
        int nTexID, 
        string strText, 
        string strFontName, 
        int nFontSz, 
        int nTexWidth, 
        int nTexHeight);
}


dynaFont.m 檔案內容如下 :


#import <Foundation/Foundation.h>
//
// 將 char 指標 (對應 C# 的 string) 轉成 iOS 字串格式 (NSString)
//
NSString* dynaFont_GetString(const char* pChar)
{
  if (pChar ==NULL)
      return [NSString stringWithUTF8String:""];
return [NSString stringWithUTF8String:pChar];
}


//
// 利用 NSString 的 drawInRect 畫出字串後再以 glTexImage2D 產生貼圖
//
bool genTexture( int nTexID, 
                 const char* pStrText, 
                 const char* pStrFontName, 
                 int nFontSz, 
                 int nTexWidth, 
                 int nTexHeight)
{
    unsigned char* pData =
        (unsigned char*)calloc(nTexWidth, nTexHeight);

    CGColorSpaceRef pcs =CGColorSpaceCreateDeviceGray();
    CGContextRef pcon =
        CGBitmapContextCreate(
            pData, 
            nTexWidth, 
            nTexHeight, 
            8
            nTexWidth, 
            pcs, 
            kCGImageAlphaNone);
    CGColorSpaceRelease(pcs);

    if (!pcon)
    {
      free(pData);
      return false;
    }
    else
    {
      CGContextSetGrayFillColor(pcon, 1.0f, 1.0f);

    CGSize rc =CGSizeMake(nTexWidth, nTexHeight);
    UIFont* pf =
            [ UIFont
              fontWithName:dynaFont_GetString(pStrFontName) 
              size:nFontSz];

    UIGraphicsPushContext(pcon);
        [ dynaFont_GetString(pStrText)
          drawInRect:CGRectMake(0,0,rc.width, rc.height) 
          withFont:pf lineBreakMode:UILineBreakModeWordWrap 
          alignment:UITextAlignmentLeft];
    UIGraphicsPopContext();

    glBindTexture(GL_TEXTURE_2D, nTexID);
    glTexImage2D(
            GL_TEXTURE_2D, 
            0
            GL_ALPHA, 
           (GLsizei)nTexWidth, (GLsizei)nTexHeight, 
            0
            GL_ALPHA, 
            GL_UNSIGNED_BYTE, 
            pData);
    CGContextRelease(pcon);

    free(pData);
    }
    return true;
}


2012-04-14

關於 iOS 開發環境設定的兩三事

2012-04-14 :
  1. 若是使用自己的 apple id 取得 ios developer program 則直接參考 此聯結 做設定。
  2. 若是某人已取得 ios developer program ,要讓自己也可以開發 ( 不同/或相同的電腦,作業系統裡使用不同的使用者帳號名稱 ),則按下列步驟設定 :
    • 使用已取得 ios developer program 的 apple id 到此頁面,按下 invite person ,邀請自己,按下後自己將收到邀請函,按下邀請函上面的連結之後,會開啟網頁詢問是否已有 apple id,若已有 apple id,登入過後就會發現自己的 apple id 也加入 ios developer program 了。
    • 以自己的  apple id 參考 此聯結 做後續設定。
  3. ( 尚未測試 ) 若是某人已取得 ios developer program,後來再買了一台電腦,想要在另一台電腦上也可以開發 ( 不同的電腦,作業系統裡使用相同的使用者帳號名稱 ) ,則按下列步驟設定 :
    • 至 applications > utilities >  Keychain Access 選擇左下方 ‘Keys’ 。
    • 找到具有 iOS Development Certificate 的 private key,按下右鍵 (control +左鍵) 選 export ...。最後會得到一個 (.p12) 的檔案。
    • 將檔案複製在另一台電腦並安裝之。
    • 參考 此聯結 並跳至第六項之後做後續設定。
  4. 因為 Snow Leopard 上的 xcode 只到 4.2 版就沒有再更新了,因此若手機上的 iOS 是 5.1 版,則要升級作業系統至 Lion ( 才可安裝 xcode 4.3 以上版本) 或將手機 iOS 降級至 5.0 才可讓 xcode 支援使用。若不想升級作業系統或降級 iOS,還是可以按照下列步驟將 iOS 5.1 SDK 強制安裝至 xcode 4.2 (參考 此聯結 ) :
    • 這裡 下載最新版 xcode。
    • 進入 terminal (applications > utilities > terminal ),依序輸入下列指令 ( 此指令是針對 xcode 4.2 安裝至 /Developer )
sudo cp -R /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/
sudo cp -R /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/
sudo cp -R /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/5.1\ \(9B176\) /Developer/Platforms/iPhoneOS.platform/DeviceSupport/
sudo rm -f /Developer/Platforms/iPhoneOS.platform/DeviceSupport/Latestcd /Developer/Platforms/iPhoneOS.platform/DeviceSupport/
sudo ln -s ./5.1\ \(9B176\) ./Latest

2012-04-06

NodeJS 執行時期更新程式碼

這是一個很酷的特性!nodejs 在執行期間不必重新啟動就可以更新程式碼!例如有個用 nodejs 寫的 http / socket server 正在執行當中,現在要為它修改或是增加新的功能,則直接修改程式碼後儲存,完全不必重新啟動伺服器。
底下是一個簡單的範例,把 main.js 執行起來,它會監控 module0.js ,並定時呼叫 module0.js 的 say function ,當 module0.js 更動後(例如更改 say funciton 裡要顯示出的字串),它會自動重新載入 module0.js 的程式碼:

檔案 main.js :
var l_module =require('./module0');
var l_fs =require('fs');

l_fs.watch('module0.js',
    function(event, pFilename)
    {
        console.log('new event='+event+', filename='+pFilename);
        if (event ==='change')
        {
            var name =require.resolve('./module0');
            delete require.cache[name];
            console.log('resolved modulename ='+name);
               
            try
            {
                l_module =require('./module0');               
            }
            catch(err)
            {
                console.log(err);
                l_module =undefined;
            }
        }
    }
);

var dosomething =
    function()
    {
        if (l_module !==undefined &&
            l_module.hasOwnProperty('say')===true)
        {
            l_module.say();
        }
        else
        {
            console.log('module unavailable');
        }
       
        setTimeout(dosomething, 1000);
    };
   
setTimeout( dosomething, 1000 );


檔案 module0.js :
exports.say =
    function()
    {
        console.log('im module0 -version 0');
    };

2012-03-28

2.x 以後的 connect 把 router 功能移除

參考討論串 https://github.com/senchalabs/connect/issues/262,作者將 router 功能歸類在更上層的 express ,因此 connect 不再維護/提供 router 的功能了,若要繼續使用新版的 connect ,其原本 router 的功能可以從這裡 https://github.com/DamonOehlman/connectables 取得!經過測試,在 node 0.6.14 及 connect 2.0.3 上可正常使用!