cocos2dx-2.1.4 例程學習1 HelloCpp

【tonyfield 2013.09.04 】

參考 Linux下搭建 Cocos2d-x-2.1.4 編譯環境 導入 HelloCpp 例程

1. Java 入口 HelloCpp.java

  HelloCpp類很簡單,因爲它繼承的父類 Cocos2dxActivity 攬下了所有的內部操作,並建立了和JNI各類接口的關係,顯示的工作也是通過 Cocos2dxActivity 的OnCreate函數來完成的。具體可以參考其實現。

  System.loadLibrary("hellocpp");這句將載入項目內的 JNI 庫,執行 JNI 中 JNI_OnLoad 函數接口。

import org.cocos2dx.lib.Cocos2dxActivity;
 
import android.os.Bundle;
 
public class HelloCpp extends Cocos2dxActivity{
 
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
    }
    
    static {
         System.loadLibrary("hellocpp");
    }
}

  除了上述所述功能,如果你發佈的應用是收費的,那在這個類型中還需要添加驗證過程,具體請參考 Android 開發文檔。

2. JNI 入口 main.cpp

  main.cpp 路徑是 jni/hellocpp/main.cpp,載入庫時刻,JNI_OnLoad 將被調用 ,它做的很重要的事情就是保存javaVM值,通過這個值你可以在JNI空間任何地方去的有效的JNIEnv環境變量 。相反,試圖保存 JNIEnv在未來調用的做法是危險的。

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    JniHelper::setJavaVM(vm);

    return JNI_VERSION_1_4;
}

  另一件必須完成的工作就是實現虛函數 Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit,顯然 上節提到的 Cocos2dxActivity 將會調用這個函數。

void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)
{
    if (!CCDirector::sharedDirector()->getOpenGLView())
    {
        CCEGLView *view = CCEGLView::sharedOpenGLView();
        view->setFrameSize(w, h);

        AppDelegate *pAppDelegate = new AppDelegate();
        CCApplication::sharedApplication()->run();
    }
}

  函數先檢查 OpenGL View 是否可以正常獲得,對於 Android API版本較低的手機這個函數可能無法通過,這時,在模擬器上看到的是黑屏。你可以自己修改來是上層顯示一點提示,免得用戶以爲是程序有問題。

  下面就是最重要的事情,創建自己的應用代表(Application Delegate)實例。這個實例中你需要做的就是實現初始化,消息響應函數等接口。CCApplication::sharedApplication()->run();會幫你讓程序運轉起來。CCApplication 這個類很簡單,也有些詭異,它繼承的 CCApplicationProtocol 類型就是一個純虛的接口定義,這個父類是爲跨平臺設計的。CCApplication 中有一個靜態函數 sharedApplication(),始終返回最近一次創建該類型對象的 this指針。這意味着 cocos2dx 在創建完這個對象後就想把這個對象的指針交給開發者,再由開發者調用 run成員函數來運轉程序。

int CCApplication::run()
{
    // Initialize instance and cocos2d.
    if (! applicationDidFinishLaunching())
    {
        return 0;
    }    
    return -1;
}
  你有理由相信你獲得的這個指針實際上指向了一個 CCApplication 子類,它來完成實際的消息處理循環過程。

  好了,下面來研究 AppDelegate 類型。

3. AppDelegate 類型

  AppDelegate 類型在 jni/Classes/AppDelegate.h 中定義,在 jni/Classes/AppDelegate.cpp 中實現。先看下面的定義,發現原來上節的 CCApplication 在這裏果然變成了AppDelegate 的父類。你需要實現 applicationDidFinishLaunching 等 3個接口函數。上節中run函數中的調用關係問題到這裏迎刃而解。(我想cocos2dx是否可以象 MFC 接口那樣完成的更優美一些,將接口的調用過程完全隱藏起來。)

class  AppDelegate : private cocos2d::CCApplication
{
public:
    AppDelegate();
    virtual ~AppDelegate();

    /**
    @brief    實現 CCDirector 和 CCScene 初始化代碼
    @return true    初始化成功, app 繼續.
    @return false   初始化失敗, app 終止.
    */
    virtual bool applicationDidFinishLaunching();

    /**
    @brief  當應用進入後臺執行該函數
    @param  the pointer of the application  ?? 我怎麼沒看到參數
    */
    virtual void applicationDidEnterBackground();

    /**
    @brief  當應用即將進入後臺執行該函數
    @param  the pointer of the application
    */
    virtual void applicationWillEnterForeground();
};

AppDelegate的接口函數實現就像一個模版,在建立自己的應用時,你完全可以拿來主義。

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    CCDirector* pDirector = CCDirector::sharedDirector();
    CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();

    pDirector->setOpenGLView(pEGLView);

    // Set the design resolution
    pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionNoBorder);

    CCSize frameSize = pEGLView->getFrameSize();
    
    vector<string> searchPath;

    // In this demo, we select resource according to the frame's height.
    // If the resource size is different from design resolution size, you need to set contentScaleFactor.
    // We use the ratio of resource's height to the height of design resolution,
    // this can make sure that the resource's height could fit for the height of design resolution.

    // if the frame's height is larger than the height of medium resource size, select large resource.
    if (frameSize.height > mediumResource.size.height)
    {
        searchPath.push_back(largeResource.directory);

        pDirector->setContentScaleFactor(MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width));
    }
    // if the frame's height is larger than the height of small resource size, select medium resource.
    else if (frameSize.height > smallResource.size.height)
    {
        searchPath.push_back(mediumResource.directory);
        
        pDirector->setContentScaleFactor(MIN(mediumResource.size.height/designResolutionSize.height, mediumResource.size.width/designResolutionSize.width));
    }
    // if the frame's height is smaller than the height of medium resource size, select small resource.
	else
    {
        searchPath.push_back(smallResource.directory);

        pDirector->setContentScaleFactor(MIN(smallResource.size.height/designResolutionSize.height, smallResource.size.width/designResolutionSize.width));
    }
    
    // set searching path
    CCFileUtils::sharedFileUtils()->setSearchPaths(searchPath);
	
    // turn on display FPS
    pDirector->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    pDirector->setAnimationInterval(1.0 / 60);

    // create a scene. it's an autorelease object
    CCScene *pScene = HelloWorld::scene();

    // run
    pDirector->runWithScene(pScene);

    return true;
}

// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground() {
    CCDirector::sharedDirector()->stopAnimation();

    // if you use SimpleAudioEngine, it must be pause
    // SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() {
    CCDirector::sharedDirector()->startAnimation();

    // if you use SimpleAudioEngine, it must resume here
    // SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();
}

  其中比較重要的是 CCScene *pScene = HelloWorld::scene(); 這個語句,因爲它涉及到另一個自定義類型 HelloWorld。

4. HelloWorld 類型

  HelloWorld 類型在 jni/Classes/HelloWorldScene.h 中定義,在 jni/Classes/HelloWorldScene.cpp 中實現。


class HelloWorld : public cocos2d::CCLayer
{
public:
    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  

    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::CCScene* scene();
    
    // a selector callback
    void menuCloseCallback(CCObject* pSender);
    
    // implement the "static node()" method manually
    CREATE_FUNC(HelloWorld);
};

CREATE_FUNC(HelloWorld) 展開後代碼如下,基本意思就是定義靜態函數create()創建HelloWorld 類對象並初始化。

static HelloWorld* create() \
{ \
    HelloWorld *pRet = new HelloWorld(); \
    if (pRet && pRet->init()) \
    { \
        pRet->autorelease(); \
        return pRet; \
    } \
    else \
    { \
        delete pRet; \
        pRet = NULL; \
        return NULL; \
    } \
}

  在另一個靜態函數 sence中,將創建一個 CCScene 對象 和 HelloWorld 對象,HelloWorld 對象被組合到 CCScene 對象中,它也是 cocos2dx內部操作的對象。






【轉載請註明來自blog.csdn.net/tonyfield 謝謝 2013.09.04 】

發佈了53 篇原創文章 · 獲贊 22 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章