[cocosBuilder篇]CocosBuilder的callback: onNodeLoaded / onAssignCCBMemberVariable沒有被調用

文章撰寫日期︰2013/04/16 18:40
cocos2dx使用版本︰v 2.0.4
cocosBuilder使用版本︰v 2.0 alpha 1

一、問題

今天遇到onNodeLoaded和onAssignCCBMemberVariable這兩個回調函式被有被呼叫的問題。

二、解決辦法

原來是忘了將ccb的Layer指定給cocos2d-x要被綁定的class。
必須要將CCLayer指派custom class
指定custom class後,
onNodeLoaded和onAssignCCBMemberVariable這兩個callback回調函式就被啟動了。

[Android篇]call to OpenGL ES API with no current context (logged once per thread)

文章撰寫日期︰2013/04/16 13:25
cocos2dx使用版本︰v 2.0.4
cocosBuilder使用版本︰v 2.0 alpha 1

一、問題

今天試圖使用JNI從Java(Android)層呼叫C++(Cocos2d-x)層,
讓Cocos2d-x換場景(replaceScene),
卻遇到Eclipse報
  1. Fatal signal 11 (SIGSEGV) at xxxxxxxx (code=1), thread xxxx (xxxxxx)
  2. call to OpenGL ES API with no current context (logged once per thread)
的錯誤。

二、解決辦法

這個問題是因為Android在啟動cocos2d-x的Thread時,
不是用context的主Thread,
而是另外產生OpenGL的Thread,
所以我們不能用主Thread去讓cocos2dx做OpenGL Thread原本應該做的工作(replaceScene),
要用OpenGL的Thread去完成︰

JAVA端-Cocos2dxActivity.java
//要用Cocos2dxActivty這個Activity去調用runOnGLThread!
Cocos2dxActivity.this.runOnGLThread(new Runnable(){

    @Override
    public void run() {
           replaceScene();
        }
    });

    public static native void replaceScene();
    static {
        System.loadLibrary("game");
   }

C++端
JNIEXPORT void JNICALL Java_com_hardworking_millioinschool_ios_Cocos2dxActivity_replaceScene(JNIEnv *env, jobject thiz)
{
    
    //切到主遊戲頁
    CCScene *pScene = TitleScene::scene();
    CCDirector::sharedDirector()->replaceScene(pScene);
    
}

相關文章

1. 雜物聚集地

[cocosBuilder篇]signal SIGABRT錯誤-狀況1

文章撰寫日期︰2013/04/15 11:30
cocos2dx使用版本︰v 2.0.4
cocosBuilder使用版本︰v 2.0 alpha 1

一、問題

今天在將cocosBuilder的變數與cocos2dx做綁定時,
遇到了 signal SIGABRT的錯誤。

二、解決方法

經查看才發現我將綁定的元件類型指派錯誤(見下圖)
如圖所示,
在cocosBuilder小妹妹的圖像是CCSprite,
名稱取為userPic,
但在cocos2d-x綁定時,
我卻將userPic指派給CCLabelTTF型別,
因此出現了signal SIGABRT的錯誤。

只要將cocos2d-x的CCLabelTTF改成CCSprite即可。

相關文章

1. [cocosBuilder篇]signal SIGABRT錯誤-狀況2

[cocosBuilder篇]ccbi檔讀不進來,遇到EXC_BAD_ACCESS

文章撰寫日期︰2013/03/14 16:11
cocos2dx使用版本︰v 2.0.4
cocosBuilder使用版本︰v 2.0 alpha 1

一、問題

今天在載入ccbi檔時,
遇到了CCNodeLoader.cpp裡parsePropTypeSpriteFrame函式在getContentSize時遇到EXC_BAD_ACCESS的問題。

二、解決辦法

這是因為CCNodeLoader無法順利的將ccbi裡的圖檔資源載入

第1種處理方法

處理辦法是確認專案資料夾是否已將ccbi裡要用到的圖檔資源reference進來,
如果仍無法解決問題則執行第2種處理方法

第2種處理方法

圖檔重新重製並重新命名,重新製作更名後的ccbi檔

相關文章

1. Androd端無法載入sub ccb
2. sub ccbi的使用

[cocosBuilder篇]CocosBuilder設定Sprite為invisible無效

文章撰寫日期︰2013/04/14 16:00
文章修改時間︰2013/06/30 09:52
文章撰寫日期︰文章修改次數︰2
cocos2dx使用版本︰v 2.0.4
cocosBuilder使用版本︰v 2.0 alpha 1

一、問題

今天在使用cocosBuilder時,
執行程式遇到了unsupported property now的錯誤。


二、解決辦法

我使用的
cocosBuilder版本為2.1
cocos2d-x版本為2.0.4

原來是因為這一版的CCBReader(cocos2d-x官方內建的cocosBuilder解析器),
官方忘了將物件visible的屬性判斷寫進來。

只要在libs\extentions\CCBReader\CCBAnimationManager.cpp的setAnimatedProperty函式
加上以下的code即可解決
            //加入以下的code
            else if (strcmp(pPropName, "visible") == 0)
            {
                bool visible = ((CCBValue*)pValue)->getBoolValue();
                ((CCSprite*)pNode)->setVisible(visible);
            }
這是cocos2d-x 2.0.4版CCBAnimationManager.cpp->setAnimatedProperty函式最後的樣子
void CCBAnimationManager::setAnimatedProperty(const char *pPropName, CCNode *pNode, CCObject *pValue, float fTweenDuraion)
{
    if (fTweenDuraion > 0)
    {
        // Create a fake keyframe to generate the action from
        CCBKeyframe *kf1 = new CCBKeyframe();
        kf1->autorelease();
        kf1->setValue(pValue);
        kf1->setTime(fTweenDuraion);
        kf1->setEasingType(kCCBKeyframeEasingLinear);
        
        // Animate
        CCActionInterval *tweenAction = getAction(NULL, kf1, pPropName, pNode);
        pNode->runAction(tweenAction);
    }
    else 
    {
        // Just set the value
        
        if (strcmp(pPropName, "position") == 0)
        {
            // Get position type
            CCArray *array = (CCArray*)getBaseValue(pNode, pPropName);
            int type = ((CCBValue*)array->objectAtIndex(2))->getIntValue();
            
            // Get relative position
            CCArray *value = (CCArray*)pValue;
            float x = ((CCBValue*)value->objectAtIndex(0))->getFloatValue();
            float y = ((CCBValue*)value->objectAtIndex(1))->getFloatValue();
            
            pNode->setPosition(getAbsolutePosition(ccp(x,y), type, getContainerSize(pNode->getParent()), pPropName));
        }
        else if (strcmp(pPropName, "scale") == 0)
        {
            // Get scale type
            CCArray *array = (CCArray*)getBaseValue(pNode, pPropName);
            int type = ((CCBValue*)array->objectAtIndex(2))->getIntValue();
            
            // Get relative scale
            CCArray *value = (CCArray*)pValue;
            float x = ((CCBValue*)value->objectAtIndex(0))->getFloatValue();
            float y = ((CCBValue*)value->objectAtIndex(1))->getFloatValue();
            
            setRelativeScale(pNode, x, y, type, pPropName);
        }
        else 
        {
            // [node setValue:value forKey:name];

            // TODO only handle rotation, opacity, displayFrame, color
            if (strcmp(pPropName, "rotation") == 0)
            {
                float rotate = ((CCBValue*)pValue)->getFloatValue();
                pNode->setRotation(rotate);
            }
            else if (strcmp(pPropName, "opacity") == 0)
            {
                int opacity = ((CCBValue*)pValue)->getByteValue();
                (dynamic_cast(pNode))->setOpacity(opacity);
            }
            else if (strcmp(pPropName, "displayFrame") == 0)
            {
                ((CCSprite*)pNode)->setDisplayFrame((CCSpriteFrame*)pValue);
            }
            else if (strcmp(pPropName, "color") == 0)
            {
                ccColor3BWapper *color = (ccColor3BWapper*)pValue;
                ((CCSprite*)pNode)->setColor(color->getColor());
            }
            //加入以下的code
            else if (strcmp(pPropName, "visible") == 0)
            {
                bool visible = ((CCBValue*)pValue)->getBoolValue();
                ((CCSprite*)pNode)->setVisible(visible);
            }
            else
            {
                CCLog("unsupported property name is %s", pPropName);
                CCAssert(false, "unsupported property now");
            }
        }
    }
}

記得,
除了專案裡的extension\CCBReader\CCBAnimationManager.cpp要改以外,
cocos2dx安裝目錄底下extensions/CCBReader\CCBAnimationManager.cpp也要改,
Android那邊才會顯示正常。

[cocosBuilder篇]cocos2dx2.0.4+cocosBuilder2.1使用下,比較穩定的CCBReader source

文章撰寫日期︰2013/04/10 19:00
cocos2dx使用版本︰v 2.0.4
cocosBuilder使用版本︰v 2.0 alpha 1

如果跟我一樣抓官方2.0.4版cocos2dx的人
應該會遇到當cocosBuilder將一個CCSprite設為invisible時,
程式就無法執行的問題。

這是2.0.4版CCBReader的問題
這裡有官方後來修改
git commit編號的版本是1a3c5f8eb741ee35debe584944ce8f13dd35668b
下載CCBReader

這個版本有改善CCSprite不能設為invisible的問題。
請覆蓋掉你專案底下原本在lib\extension\的CCBReader資料夾
和cocos2dx\extensions底下的CCBReader資料夾

[cocosbuilder篇]sub ccbi的使用

文章撰寫日期︰2013/04/10 15:30
cocos2dx使用版本︰v 2.0.4
cocosBuilder使用版本︰v 2.0 alpha 1

一、前言

我們知道,
在cocos2dx的世界,
是以CCNode(節點)為概念,
遊戲畫面可以藉由一層一層的堆疊,
來做出完整的畫面呈現,
更棒的是,
分層式的概念,
在程式碼的分類上,
給了我們很好的管理空間。

最常見的CCLayer,
就是很常被我們使用的CCNode。
而cocosBuiler也使用了相同概念,
讓我們能將ccbi(cocosBuilder製作出來的圖層檔)藉由CCBReader產生成CCLayer。

有了這個方便管理的分層概念,
我們當然不要放過。

今天,
我有一頁遊戲主頁A,
上面希望壓一層玩家的遊戲狀態B,
因此我們很容易去聯想到︰
我要畫面A+B=C。
然後,各自管理各個畫面裡的變數或元件。


 要怎麼做?

二、本文

cocosBuilder要做的事
sub ccb只能自訂義class來接收cocosBuilder裡定義的物件
Anchor point記得要設成x=0,y=0,
否則會遇到我之前提的sub ccbi執行起來的位置不在你指定的位置上,
產生偏移的問題。

Target設成Document root(一定要!)

將sub ccb檔拖曳至主ccb裡

這樣子我們就完成了在cocosBuilder裡的屬性變數定義。

接下來,
我們把目光往cocos2d-x裡瞧。

我們需要建立CCBReader的Loader, 也就是要將cocos2d-x和cocosBuilder做綁定,
所以這個Loader裡, 將會定義cocosBuilder裡的變數的工作為何。

這是HeaderLayer.h檔
#ifndef _HEADERLAYER_H_
#define _HEADERLAYER_H_

#include "cocos2d.h"
#include "cocos-ext.h"


class HeaderLayer
    : public cocos2d::CCLayer
    , public cocos2d::extension::CCBSelectorResolver
{
    public:
        CCB_STATIC_NEW_AUTORELEASE_OBJECT_WITH_INIT_METHOD(HeaderLayer, create);

        virtual cocos2d::SEL_MenuHandler onResolveCCBCCMenuItemSelector(cocos2d::CCObject * pTarget, cocos2d::CCString * pSelectorName);
        virtual cocos2d::extension::SEL_CCControlHandler onResolveCCBCCControlSelector(cocos2d::CCObject * pTarget, cocos2d::CCString * pSelectorName);

        void onHeadIconPressed(cocos2d::CCObject * pSender);
};


class HeaderLayerLoader : public cocos2d::extension::CCLayerLoader {
public:
    CCB_STATIC_NEW_AUTORELEASE_OBJECT_METHOD(HeaderLayerLoader, loader);
    
protected:
    CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(HeaderLayer);
};
#endif
這是HeaderLayer.cpp檔
#include "HeaderLayer.h"

USING_NS_CC;
USING_NS_CC_EXT;

SEL_MenuHandler HeaderLayer::onResolveCCBCCMenuItemSelector(CCObject * pTarget, CCString * pSelectorName) {

    return NULL;    
}

SEL_CCControlHandler HeaderLayer::onResolveCCBCCControlSelector(CCObject * pTarget, CCString * pSelectorName) {
    CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onHeadIconPressed", HeaderLayer::onHeadIconPressed);
    return NULL;
}

void HeaderLayer::onHeadIconPressed(cocos2d::CCObject *pSender) {
//    CCDirector::sharedDirector()->popScene();
    CCLog("into onHeadIconPressed");
}

我們看到了在
SEL_CCControlHandler HeaderLayer::onResolveCCBCCControlSelector(CCObject * pTarget, CCString * pSelectorName) {
    CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "onHeadIconPressed", HeaderLayer::onHeadIconPressed);
    return NULL;
}
}
裡面,我們實作了剛才在cocosBuilder裡定義的︰
小綠人的按鈕按下後,要做onHeadIconPressed函式裡要做的事。
而onHeadIconPressed函式要做的事很簡單,
印出LOG而己。
void HeaderLayer::onHeadIconPressed(cocos2d::CCObject *pSender) {
    CCLog("into onHeadIconPressed");
}
}

將cocosBuilder的變數與cocos2d-x綁定後,
再來就是很單純的將這個圖層檔(ccbi)讓cocos2d-x裡的extension\CCBReader元件載入
//這是遊戲主頁面類的scene函式
CCScene* SchoolMapScene::scene(){

    CCScene* scene = CCScene::create();
    
    //原本遊戲主頁用到的ccbi
    CCNodeLoaderLibrary *ll = CCNodeLoaderLibrary::newDefaultCCNodeLoaderLibrary();
    ll->registerCCNodeLoader("SchoolMapScene", SchoolMapSceneLayerLoader::loader());
    
    //為了要能使用sub-ccbi的元件,需要多註冊HeaderLayer這組Loader
    ll->registerCCNodeLoader("HeaderLayer", HeaderLayerLoader::loader());
    
    CCBReader *ccbReader = new CCBReader(ll);
    
    mAnimationManager = NULL;

    CCNode *node = ccbReader->readNodeGraphFromFile("SchoolMap.ccbi",this,&mAnimationManager);

    mAnimationManager->setDelegate(this);
    
    //获取AnimationManger 并传给AnimationsLayer
    ((SchoolMapScene*)(node))->setAnimationManager(ccbReader->getAnimationManager());

    ccbReader->autorelease();
    if(node != NULL)
    {
        
        scene->addChild(node);
    }
    
    return scene;
}

完成後,
我們就能同時監聽2層ccbi圖層的點擊事件,
而不同圖層的管理,
也很明確的區分出來,
彼此不衝突,
遊戲狀態圖層還能任意被任何其它遊戲畫面使用。

三、結論

經由cocosBuilder的設定和cocos2d-x的綁定,
我們很有邏輯的將各個圖層該有什麼功能做了很有效率的分類了。
以後如果要改遊戲狀態圖層B的內容,
也完全不會和原本的遊戲主頁面A扯上關係,
這就是使用sub ccbi的好處。

還在等什麼,
快點試看看!

四、後記

官方也有Sub ccb使用的Sample︰TestCpp專案裡有Sample範例,
相關Class請參照
cocos2dx/samples/TestCpp//Classes/ExtensionsTest/CocosBuilderTest資料夾,

而使用到的cocosbuilder專案檔則放在
cocos2dx/samples/TestCpp/Resources/CocosBuilderExample.ccbproj
如果有安裝cocosBuilder,
點2下就能開起來了。

相關文章

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

[cocosbuilder篇]Reference to 'CCBReader' is ambiguous錯誤

文章撰寫日期︰2013/04/10 15:15
cocos2dx使用版本︰v 2.0.4
cocosBuilder使用版本︰v 2.0 alpha 1

一、問題

今天要做sub ccbi的控件程式碼綁定,
在cocos2dx的Sample資料夾底下,
將TestCPP專案裡class\ExtensionsTest\TestHeader資料夾複製出來用時,
遇到 Reference to 'CCBReader' is ambiguous的錯誤。

二、解決辦法

將TestHeaderLayerLoader.h裡第7行︰
class CCBReader;
刪掉即可。


相關文章

1. [cocosBuilder篇]sub ccbi在主ccbi上位置偏移
2. [cocosbuilder篇]sub ccbi的使用

[cocosBuilder篇]sub ccbi在主ccbi上位置偏移

文章撰寫日期︰2013/04/10 19:44
cocos2dx使用版本︰v 2.0.4
cocosBuilder使用版本︰v 2.0 alpha 1

一、問題

今天在使用sub ccbi時,
遇到sub ccbi放在主ccbi上,
位置偏移的問題。

二、解決辦法

通常是因為sub ccbi沒有定義Anchor Point或ignore了Anchor Point,
造成主ccbi在放置sub ccbi時,
以sub ccbi的中心點為預設Anchor Point所致。

相關文章

1. [cocosbuilder篇]Reference to 'CCBReader' is ambiguous錯誤
2. [cocosbuilder篇]sub ccbi的使用