【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 】