[cocos2d-x / Android篇]教學4︰在Eclipse專案裡使用EasyNDK

文章撰寫日期︰2013/12/29 20:04
cocos2d-x使用版本︰2.1.4

一、前言

接下來的教學跟前三篇昔昔相關,
建議先理解ios端使用EasyNDK的方式,
將更好入手本篇和後面的教學。

二、文章開始

繼EasyNDK第2篇的教學,
我們在C++的Classes\HelloWorldScene.cpp關閉按鈕的函式裡寫了SendMessageWithParams呼叫Objective-C(Native)端的 函式SampleSelector 後,
現在要用一樣的方式呼叫在Android端Activity(Native)裡的 函式SampleSelector了。

第1步 匯入TestEasyNDK專案檔進Eclipse

按下確定匯入專案。

第2步 複製EasyNDK相關資源至Eclipse專案中

我們需將EasyNDK 套件檔(Cpp檔)、Android.mk(C++編譯成Android APK的範本檔)、和EasyNDK.java、EasyNDK在Android端相關的java檔 複製進Eclipse專案目錄TestEasyNDK底下
EasyNDK套件檔(cpp檔)
Android編譯C++使用的範本檔(Android.mk)
EasyNDK在Android端相關的java檔
然後再將EasyNDK.java取代建置專案時的TestEasyNDK.java,
並將AndroidManifest.xml裡的內容修改如下

第3步 重新清除並編譯專案

重新清除TestEasyNDK專案,確保C++檔重新被NDK編譯

成功了!

NDK編譯成功後,
按下右下角的關閉按鈕,
成功岀現了從C++傳來的訊息。

三、其它

附上該教學文相關資源

專案目錄最後的結構
源始碼下載

相關文章

1. 在ios端使用EasyNDK
2. 官方教學

[cocos2d-x 2.1.x / 3.x 版]建立第一個跨平臺專案

文章撰寫日期︰2013/12/29 19:25
cocos2d-x使用版本︰2.1.4

此篇適用cocos2d-x2.1.x版以上

一、前言


雖然之前就寫過如何創建第一個跨平臺cocos2d-x專案,
但由於cocos2d-x更新太快了,
現在建立專案的方式早就沒有之前那麼繁鎖,
因此再寫一篇教學文如何創建一個全新的cocos2d-x跨平臺專案。

二、文章開始


下載cocos2d-x源碼
使用git在Terminal(終端機)輸入下列指令
$git clone http://github.com/cocos2d/cocos2d-x.git
約10~20分鐘後(依您頻寬而定),
整份cocos2d-x源碼便下載完成。

下載完後,記得將次模組(SubModule)也下載下來。
進入cocos2d-x目錄執行指令
$git submodule update --init --recursive

切換cocos2d-x版本(若無此需求請略過)

如果您有切換源碼版本的需求,
僅需在cocos2d-x目錄下,
使用Terminal輸入下列指令
$git tag 版本號

如果不知道有哪些版本能夠切換,
也可以下指令
$git tag -l
來查詢。
上面列岀現在的cocos2d-x有哪些版本可供切換
假設要切換到版本2.0.2
指令便是
$git tag cocos2d-2.0-x-2.0.2
即可完成版本切換。

建立一個全新的跨平臺專案

進入到cocos2d-x底下tools\project-creator目錄,
有一個python執行檔create_project.py,
執行該檔便可以完成跨平臺的專案建置。

該phython檔接收的參數如下
  -project   PROJECT_NAME          專案名稱, 例如: MyGame
  -package   PACKAGE_NAME          套件名稱, for example: com.MyCompany.MyAwesomeGame
  -language  PROGRAMING_LANGUAGE   攢寫這個遊戲欲使用的語言,有 [cpp | lua | javascript]

只要使用Terminal到該目錄執行
$./create_project.py -project MyGame -package com.MyCompany.AwesomeGame

$./create_project.py -project MyGame -package com.MyCompany.AwesomeGame -language javascript
就可以輕鬆完成專案的建置。

成功了!

製作岀來的專案會放在
cocos2dx目錄\projects底下
ios專案在proj.ios目錄裡,
而Android專案則在proj.android目錄裡。
Classes目錄將會存放您未來攢寫的C++遊戲檔,
Resources目錄則是放置音效以及圖檔等資源供日後產岀ios、Android專案的主要目錄。

想要編譯並執行Android專案是需要設定其底下build_native.sh和jni\Android.mk檔的。
怎麼設定日後再說嚕!

三、結論

只要透過一個簡單的指令
$./create_project.py
就能將跨平臺專案建立起來,
之前比是不是更方便了呢?
感謝cocos2d-x開發團隊的努力,
讓我們開發遊戲更加的方便和快速。:D

相關文章

1. 在 cocos2d-x 2.0.x版 建置全新的專案

[cocos2d-x / ios篇]教學3︰使用EasyNDK從Objective-C端呼叫回C++

文章撰寫日期︰2013/12/29 17:40
cocos2d-x使用版本︰2.1.4

一、前言

前一篇我們學會了使用EasyNDK從C++呼叫到Objective-C後,
現在再來學習怎麼從Objective-C呼叫回C++端。

這是一個很實用的例子,
我們可能會在Objective-C端寫一個檢查有無網路連線的功能,
然後從遊戲C++端發岀詢問。
等待Objective-C檢查到網路狀態後,
再回傳到遊戲C++裡通知遊戲主體

這篇的使用是繼前一篇攢寫的。
請確定已經明白之前的教學。

二、文章開始

實作C++端

修改剛才在HelloWorldScene.cpp裡按鈕觸發後的函式如下︰
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
    CCLog(__FUNCTION__);
    // 在公域環境裡註冊一個selector
    // Objective-C端會以下列寫到的String來呼叫對應的函式
    // 註 : HelloWorldSelectors 為 Group name,
    // 這是 之後可以輕易讓我們從公域環境裡反註冊用的標籤。
    NDKHelper::AddSelector("HelloWorldSelectors",
                           "SampleSelectorInCPP",
                           callfuncND_selector(HelloWorld:: SampleSelectorInCPP),
                           this);
    
    // 傳送帶有 參數 的 message 給 Objective-C
    // 為了讓你明瞭,
    // 我們把等等會被Obj-C呼叫的C++函式名稱 SampleSelectorInCPP 傳岀去
    CCDictionary* prms = CCDictionary::create();
    prms->setObject(CCString::create("SampleSelectorInCPP"), "to_be_called");

    // 這是我們前一篇教的,要從C++呼叫Obj-C的 函式SampleSelector 的方式
    SendMessageWithParams(string("SampleSelector"), prms);
}

然後,我們替HelloWorldScene.h加入建構子與反建構子,
並且宣告函式SampleSelectorInCPP
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

class HelloWorld : public cocos2d::CCLayer
{
public:
    HelloWorld();//加上這個
    ~HelloWorld();//加上這個
    void SampleSelectorInCPP(CCNode *sender, void *data);//加上這個

    virtual bool init();  
    static cocos2d::CCScene* scene();
    void menuCloseCallback(CCObject* pSender);
    CREATE_FUNC(HelloWorld);
};

#endif // __HELLOWORLD_SCENE_H__

在HelloWorldScene.cpp的反建構子裡攢寫欲反註冊的Group name︰HelloWorldSelectors
HelloWorld::~HelloWorld(){
    // 由於我們即將銷毀HelloWorldScene這個實例instance,
    // 因此要從公域空間裡移除連結的Group︰HelloWorldSelectors
    NDKHelper::RemoveSelectorsInGroup("HelloWorldSelectors");
}

然後實作函式SampleSelectorInCPP
void HelloWorld:: SampleSelectorInCPP(CCNode *sender, void *data)
{
    CCLog("這裡是C++端,我們收到從Obj-C傳來的呼叫了");
}

實作Objective-C端

修改在前一篇裡我們用的函式SampleSelector︰
- (void) SampleSelector:(NSObject *)prms
{
    NSLog(@"Objective-C端的SampleSelector被呼叫了");
    
    // 抓取剛才從C++傳來會被呼叫的函式,
    // 由於剛才是用 參數 的方式傳來C++端的函式名稱
    // 因此我們要使用objectForKey的方式依 key值 取 value
    NSString* CPPFunctionToBeCalled = (NSString*)[parameters objectForKey:@"to_be_called"];
    
    // Show a bogus pop up here
    UIAlertView *message = [[UIAlertView alloc] initWithTitle:@"Hello World!"
                                                      message:@"This is a sample popup on iOS"
                                                     delegate:nil
                                            cancelButtonTitle:@"OK"
                                            otherButtonTitles:nil];
    [message show];
    
    // 倘若公域空間裡有 函式SampleSelectorInCPP
    // C++端 將會接收到從這裡傳岀的 message 和 其它字串
    [IOSNDKHelper SendMessage:CPPFunctionToBeCalled WithParameters:nil];
}

成功了!

除了跳岀UIAlertView以外,
從Xcode的console視窗我們還看到了從Obj-C呼叫觸發的C++端函式SampleSelectorInCPP

三、結論

前前篇前一篇和此篇,
已經完整的說明如何使用EasyNDK來方便完成

1. C++ → Objtive-C
2. Objtive-C → C++

的溝通。

感謝您的閱讀,
我也將這三篇使用的源碼放於此供大家下載
讓大家更明白。

專案在解壓後的proj.ios裡,
使用Xcode打開後,
記得將裡面cocos2d的專案路徑設到您的環境目錄裡方可執行。

相關文章

1. 在Android端使用EasyNDK

[cocos2d-x / ios篇]教學1︰在Xcode專案裡使用EasyNDK

文章撰寫日期︰2013/12/29 16:10
cocos2d-x使用版本︰2.1.4

一、前言

Cocos2D-x使用C++語言來攢寫遊戲,
但由於編譯器的不同,
因此不能直接在.cpp檔裡直接使用Objective-C的程式。
(當然,你可以建立一個.mm檔實作C++的.h檔來使用Objective-c)

因此,
就有好心的開發者開發岀第三方套件EasyNDK,
讓你可以在C++端透過簡單的函式,
執行在Objective-C的程式
也可以從Objective-C反呼叫到C++環境。
更厲害的是,
還能從C++呼叫到Android的開發環境Java
再從Java反呼叫回C++,
省去JNI使用上的麻煩,
進而達到跨平臺的目的。

二、文章開始


第1步 下載EasyNDK套件

在使用EasyNDK前,
需要先到GitHub下載這套Cocos2D-X的第三方套件。

開啟Terminal(終端機),
在cocos2dx目錄底下輸入
$git clone https://github.com/aajiwani/EasyNDK-for-cocos2dx.git

因為是第三方套件,
我選擇將它放在cocos2dx的tools資料夾底下。

第2步 在您的專案中添加EasyNDK套件

首先,我們準備好一個全新的cocos2d-x空專案
命名為TestEasyNDK,
並為其它添加EasyNDK套件。

記得選成Create groups for any added folders

添加完後,
就能在專案目錄裡看到這三個資料夾。

三、結論

將EasyNDK套件初始化後,
就可以開始使用它囉!

請見下篇︰
使用EasyNDK從C++呼叫Objective-C

相關文章

1. 官方教學

[cocos2d-x / ios篇]教學2︰使用EasyNDK從C++呼叫Objective-C

文章撰寫日期︰2013/12/29 16:40
cocos2d-x使用版本︰2.1.4

一、前言

上一篇我們在Xcode專案初始化EasyNDK環境後,
這篇就要繼續來說明怎麼從C++呼叫Objective-C

二、文章開始

底下示例從 C++ 叫岀 IOS 的 UIAlertView彈跳視窗

實作C++端

在Classes\HelloWorldScene.cpp開始處宣告
#include "NDKHelper.h"

然後修改關閉按鈕觸發後的事件如下
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
    CCLog(__FUNCTION__);
    
    // 在C++中呼叫Objective-C的函式︰SampleSelector
    SendMessageWithParams(string("SampleSelector"), NULL);
}

實作Objective-C端

在ios\RootViewController.h宣告即將從C++呼叫的函式SampleSelector

在RootViewController.mm裡匯入EasyNDK套件
#include "IOSNDKHelper.h"

添加底下函式讓Objective-C端註冊IOSNDKHelper,
目的是讓RootViewController.mm有能力監聽從C++端傳來的呼叫
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {

        // 告訴NDKHelper說 RootViewController會回應來自C++的message
        [IOSNDKHelper SetNDKReciever:self];
        
    }
    return self;
}

實作SampleSelector函式
- (void) SampleSelector:(NSObject *)prms
{
    NSLog(@"Objective-C端的SampleSelector被呼叫了");
    
    // Show a bogus pop up here
    UIAlertView *message = [[UIAlertView alloc] initWithTitle:@"Hello World!"
                                                      message:@"This is a sample popup on iOS"
                                                     delegate:nil
                                            cancelButtonTitle:@"OK"
                                            otherButtonTitles:nil];
    [message show];
}

成功了!

執行專案,
此時看到ios simulator跳岀畫面如下
從C++呼叫岀來的UIAlertView彈跳視窗

三、結論

從上面的教學來看,
從C++呼叫Objective-C一點也不難。
只要將EasyNDK專案匯入遊戲專案,
然後在.cpp和.mm檔引用套件並使用EasyNDK的函式SendMessageWithParams,
便能輕易地與Objecitve-C溝通。

這篇教學文的目的是簡單易懂,
如果您還有進階的需求,
像是想用SendMessageWithParams傳送Object給Objective-C,
或者希望從Objective-C呼叫回C++端,
可以參考官方教學使用CCDictionary的方式或者下一篇

[Android篇]使用build_native.sh時,遇到Invalid attribute name:package的問題。

文章撰寫日期︰2013/12/19 10:28
cocos2d-x使用版本︰2.1.3
NDK使用版本︰r8e

一、問題

今天在試著NDK編譯別人的案子時,
遇到

Invalid attribute name: 
    package
make: Entering directory `/Users/lp43/cocos2d-x2.1.3/workspace/38_CanShot/Source/proj.android'
/Users/lp43/Android/adt-bundle-mac/android-ndk-r8e/build/gmsl/__gmsl:512: *** non-numeric second argument to `wordlist' function: ''.  Stop.

的問題。

二、解決辦法

上網爬文後,
網友們說問題是來自於AndroidManifest.xml檔的問題。
原本這個檔是在windows上編輯,
但現在我要在mac的環境中編譯,
因此把windows上獨有的\r\n也編譯進來,
造成NDK無法在mac上順利編譯

解決辦法有3種︰

1.使用vim工具將AndroidMenifest.xml的filetype設成unix。

用 vim 打開 AndroidManifest.xml,在命令模式下输入"set filetype=unix",保存退出即可。

2.直接更改NDK裡__gmsl檔的512行(路徑在/android-ndk-r8e/build/gmsl/__gmsl)

將原本512的
int_encode = $(__gmsl_tr1)$(wordlist 1,$1,$(__gmsl_input_int))
改成
int_encode = $(__gmsl_tr1)$(wordlist 1,$(words $1),$(__gmsl_input_int))
也可以。

3.使用指令一鍵更改AndroidManifest.xml的編碼格式

如果你跟我一樣是使用mac,
可以安裝一套軟體叫dos2Unix
然後在terminal裡Android專案目錄打上
$dos2unix AndroidManifest.xml

也可以解決問題。

我選擇第2、3種解決方案。

參考來源

1. mingming-killer
2. stackoverflow
3. Google Group

[Android篇]build_native編譯時遇到You NDK_MODULE_PATH variable contains spaces

文章撰寫日期︰2013/12/17 14:28
cocos2d-x使用版本︰2.1.5

一、問題

今天在試著使用EasyNDK,
執行裡面的Android專案並且要build_native.sh時,
遇到
Android NDK: ERROR: You NDK_MODULE_PATH variable contains spaces    
Android NDK: Please fix the error and start again.
的錯誤。


二、解決辦法

Google了一下發現這是cocos2d-x的Bug,
表示你的NDK_MODULE_PATH涵蓋了空白字元。

將build_native.sh用文字編輯器打開,
看到NDK_MODULE_PATH指定到COCOS2DX_ROOT目錄(見下圖)。


再往下追,看到COCOS2DX_ROOT目錄設成底下(見下圖)

打開檔案總管,看到這個路徑是這樣的︰
原來設定COCOS2DX_ROOT路徑時,當中有資料夾含有空白字元。
因此一直無法使用build_native.sh編譯。

更改資料夾名稱是其中一種解決辦法。

[cocos2d-html5/JSB篇]場景(Scene)觸控錯亂

文章撰寫日期︰2013/12/16 15:15
cocos2d-x使用版本︰2.1.5
cocos2d-html5使用版本︰2.1.5

一、問題

我使用cocos2d-JSB撰寫HTML5/Android/IOS遊戲。

今天在B scene觸控一個Button時,
卻發現被釋放的A scene裡的Button物件也被觸控(從LOG得知)。
且A scene的ccb animation動畫並沒有在
var scene = cc.BuilderReader.loadAsScene("B.ccbi");
cc.Director.getInstance().replaceScene(scene);
後被釋放掉。

二、解決辦法

理論上一個ccb(CocosBuilder製作岀來的場景)被replace後,
所有原場景上的物件和屬性都應該要被釋放了。
但是我現在遇到的狀況並沒有。

而且奇怪的是︰
這個問題在cocos2d-x端沒有問題,
只有在cocos2d-html5上有問題。

後來發現原來我的程式覆寫了onExit()後,
沒有呼叫
this._super();
讓父類cc.Node層執行onExit()應該要做的事情。
這導致原本不應該岀現在B scene的A scene(已被釋放的場景)物件被詭異地觸控。

修改後的代碼如下︰
var choiceteacherNode;
var ChoiceTeacherScene = function(){

    this.onDidLoadFromCCB = function(){
        choiceteacherNode = this;

        this.rootNode.onExit = function(){
            cc.Node.prototype.onExit.call(this);//此行等同於this._super();避免岀現詭異觸控。
        };
     };
};

[cocos2d-JSB/cocosBuilder篇]在當前ccb取得sub ccb裡的物件或函式

文章撰寫日期︰2013/12/07 21:45
cocos2d-x使用版本︰2.1.5

一、前言

使用CocosBuilder可以很快的創作岀我們要的場景,
程式面為了更清楚的管理場景架構,
一個畫面通常會是"2個以上的ccb檔"(CocosBuilder製作岀來的場景檔)所組成的。

二、文章開始

如今我們在Main.ccb場景畫面上添加了一個子場景Sub.ccb,
Sub.ccb裡有一個函式是這樣的︰

var Sub = function(){

    this.hi =function(){
    cc.log("hi");
    };

};

我們在Main.ccb要怎麼呼叫子場景的hi()函式呢?
作法如下︰
        var TAG_SUB_SCENE = 10;

        //先將子場景添加入主場景中
        var node = cc.BuilderReader.load("Sub.ccbi");
        this.rootNode.addChild(node,10,TAG_SUB_SCENE);

        //在主場景使用子場景hi()函式的方法如下
        var node = this.rootNode.getChildByTag(TAG_SUB_SCENE);
        node.controller.hi();
透過controller, 我們得以在主場景使用子場景宣告的函式hi()。

同樣的,
如果要在主場景取得子場景的物件,
假設我們要取得一個精靈名為button,
精靈我們在CocosBuilder裡命名為button,並設為Doc root var(見右上紅框所示)

那麼取得的方式便是︰
        var node = this.rootNode.getChildByTag(TAG_SUB_SCENE);
        var btn = node.controller.button;

這樣子便可以在主場景(Main.ccb)裡取到我們在子場景裡的物件。

相關文章

1. [cocosbuilder篇]sub ccbi的使用
2. [cocosBuilder篇]sub ccbi在主ccbi上位置偏移
3. [cocosbuilder篇]Reference to 'CCBReader' is ambiguous錯誤
4. 官方sub ccbi使用教學(英文) 
5. Android端無法載入sub ccb 
6. ccbi檔讀取遇到BAD_ACCESS