我們從HelloCpp.java開始:
- package org.cocos2dx.hellocpp;
- 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");
- }
- }
package org.cocos2dx.hellocpp;
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");
}
}
HelloCpp是一個Activity,首先會執行靜態代碼塊,加載libhellocpp.so庫,然後就是執行onCreate方法,這裏調用了父類的onCreate方法。我們看看Cocos2dxActivity的onCreate方法,該類在cocos2dx的庫工程libcocos2dx中:
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- sContext = this;
- this.mHandler = new Cocos2dxHandler(this);
- this.init();
- Cocos2dxHelper.init(this, this);
- }
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sContext = this;
this.mHandler = new Cocos2dxHandler(this);
this.init();
Cocos2dxHelper.init(this, this);
}
這裏主要是執行初始化過程,Cocos2dxHandler主要處理顯示Dialog的消息,Cocos2dxHelper是個輔助類,我們主要看init()方法:
- public void init() {
- // FrameLayout
- ViewGroup.LayoutParams framelayout_params =
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.FILL_PARENT);
- FrameLayout framelayout = new FrameLayout(this);
- framelayout.setLayoutParams(framelayout_params);
- // Cocos2dxEditText layout
- ViewGroup.LayoutParams edittext_layout_params =
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- Cocos2dxEditText edittext = new Cocos2dxEditText(this);
- edittext.setLayoutParams(edittext_layout_params);
- // ...add to FrameLayout
- framelayout.addView(edittext);
- // Cocos2dxGLSurfaceView
- this.mGLSurfaceView = this.onCreateView();
- // ...add to FrameLayout
- framelayout.addView(this.mGLSurfaceView);
- // Switch to supported OpenGL (ARGB888) mode on emulator
- if (isAndroidEmulator())
- this.mGLSurfaceView.setEGLConfigChooser(8 , 8, 8, 8, 16, 0);
- this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());
- this.mGLSurfaceView.setCocos2dxEditText(edittext);
- // Set framelayout as the content view
- setContentView(framelayout);
- }
public void init() {
// FrameLayout
ViewGroup.LayoutParams framelayout_params =
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT);
FrameLayout framelayout = new FrameLayout(this);
framelayout.setLayoutParams(framelayout_params);
// Cocos2dxEditText layout
ViewGroup.LayoutParams edittext_layout_params =
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
Cocos2dxEditText edittext = new Cocos2dxEditText(this);
edittext.setLayoutParams(edittext_layout_params);
// ...add to FrameLayout
framelayout.addView(edittext);
// Cocos2dxGLSurfaceView
this.mGLSurfaceView = this.onCreateView();
// ...add to FrameLayout
framelayout.addView(this.mGLSurfaceView);
// Switch to supported OpenGL (ARGB888) mode on emulator
if (isAndroidEmulator())
this.mGLSurfaceView.setEGLConfigChooser(8 , 8, 8, 8, 16, 0);
this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());
this.mGLSurfaceView.setCocos2dxEditText(edittext);
// Set framelayout as the content view
setContentView(framelayout);
}
這裏就是爲Activity綁定View Hierarchy,大家做Android開發的對着一定很熟悉。View Hierarchy的根View是個FrameLayout,FrameLayout又包含一個EditText和一個GLSurfaceView,這個GLSurfaceView就是cocos引擎用來繪製遊戲畫面的關鍵View,我們來詳細分析一下它。首先看一下Cocos2dxActivity的onCreateView方法:
- public Cocos2dxGLSurfaceView onCreateView() {
- return new Cocos2dxGLSurfaceView(this);
- }
public Cocos2dxGLSurfaceView onCreateView() {
return new Cocos2dxGLSurfaceView(this);
}
該方法就是新建一個Cocos2dxGLSurfaceView,Cocos2dxGLSurfaceView又繼承於GLSurfaceView。我們都知道GLSurfaceView的核心就是Renderer,初始化時會調用Renderer的onSurfaceCreated方法,每一幀的繪製是通過調用Renderer的onDrawFrame方法。Cocos2dxGLSurfaceView的Renderer是一個Cocos2dxRenderer對象,我們先來看Cocos2dxRenderer對象的onSurfaceCreated方法:
- @Override
- public void onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig) {
- Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);
- this.mLastTickInNanoSeconds = System.nanoTime();
- }
@Override
public void onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig) {
Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);
this.mLastTickInNanoSeconds = System.nanoTime();
}
這裏調用了一個本地方法nativeInit(final int pWidth, final int pHeight),本地方法的實現在jni/hellocpp/main.cpp中實現的:
- 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();
- }
- else
- {
- ......
- }
- }
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();
}
else
{
......
}
}
CCDirector是遊戲的導演類,一個遊戲只有一個導演類用來控制和管理場景。CCDirector::sharedDirector()是個靜態方法,用來獲取導演類的單例對象:
- CCDirector* CCDirector::sharedDirector(void)
- {
- if (!s_SharedDirector)
- {
- s_SharedDirector = new CCDisplayLinkDirector();
- s_SharedDirector->init();
- }
- return s_SharedDirector;
- }
CCDirector* CCDirector::sharedDirector(void)
{
if (!s_SharedDirector)
{
s_SharedDirector = new CCDisplayLinkDirector();
s_SharedDirector->init();
}
return s_SharedDirector;
}
CCCCDisplayLinkDirector是CCDirector的子類。我們再回到nativeinit方法中,獲取到導演類的單例對象後又調用了它的getOpenGLView()方法:
- inline CCEGLView* getOpenGLView(void) { return m_pobOpenGLView; }
inline CCEGLView* getOpenGLView(void) { return m_pobOpenGLView; }
該方法返回用於遊戲繪製的CCEGLView,在Android平臺下,這個CCEGLView其實沒有什麼作用,因爲遊戲都是繪製在Cocos2dxGLSurfaceView上的。由於我們是初始化過程,所以此時m_pobOpenGLView爲null,所以if (!CCDirector::sharedDirector()->getOpenGLView())條件成立,執行以下的代碼:
- CCEGLView *view = CCEGLView::sharedOpenGLView();
- view->setFrameSize(w, h);
- AppDelegate *pAppDelegate = new AppDelegate();
- CCApplication::sharedApplication()->run();
CCEGLView *view = CCEGLView::sharedOpenGLView();
view->setFrameSize(w, h);
AppDelegate *pAppDelegate = new AppDelegate();
CCApplication::sharedApplication()->run();
同樣,我們先獲取一個CCEGLView的單例對象,接下來又新建了一個AppDelegate對象,大家可能在工程中找不到AppDelegate類。我們打開工程目錄的上一級目錄:
我們的Android工程是在proj.android文件夾中,而AppDelegate類就在Classes文件夾中。因爲cocos2dx是跨平臺的,而AppDelegate在各個平臺之間是通用的不需要修改的,所以就放在一個公用的目錄下。
- #ifndef _APP_DELEGATE_H_
- #define _APP_DELEGATE_H_
- #include "cocos2d.h"
- /**
- @brief The cocos2d Application.
- The reason for implement as private inheritance is to hide some interface call by CCDirector.
- */
- class AppDelegate : private cocos2d::CCApplication
- {
- public:
- AppDelegate();
- virtual ~AppDelegate();
- /**
- @brief Implement CCDirector and CCScene init code here.
- @return true Initialize success, app continue.
- @return false Initialize failed, app terminate.
- */
- virtual bool applicationDidFinishLaunching();
- /**
- @brief The function be called when the application enter background
- @param the pointer of the application
- */
- virtual void applicationDidEnterBackground();
- /**
- @brief The function be called when the application enter foreground
- @param the pointer of the application
- */
- virtual void applicationWillEnterForeground();
- };
- #endif // _APP_DELEGATE_H_
#ifndef _APP_DELEGATE_H_
#define _APP_DELEGATE_H_
#include "cocos2d.h"
/**
@brief The cocos2d Application.
The reason for implement as private inheritance is to hide some interface call by CCDirector.
*/
class AppDelegate : private cocos2d::CCApplication
{
public:
AppDelegate();
virtual ~AppDelegate();
/**
@brief Implement CCDirector and CCScene init code here.
@return true Initialize success, app continue.
@return false Initialize failed, app terminate.
*/
virtual bool applicationDidFinishLaunching();
/**
@brief The function be called when the application enter background
@param the pointer of the application
*/
virtual void applicationDidEnterBackground();
/**
@brief The function be called when the application enter foreground
@param the pointer of the application
*/
virtual void applicationWillEnterForeground();
};
#endif // _APP_DELEGATE_H_
AppDelegate是繼承CCApplication類的,我們看一下CCApplication的構造方法:
- // sharedApplication pointer
- CCApplication * CCApplication::sm_pSharedApplication = 0;
- CCApplication::CCApplication()
- {
- CCAssert(! sm_pSharedApplication, "");
- sm_pSharedApplication = this;
- }
// sharedApplication pointer
CCApplication * CCApplication::sm_pSharedApplication = 0;
CCApplication::CCApplication()
{
CCAssert(! sm_pSharedApplication, "");
sm_pSharedApplication = this;
}
我們看到在新建CCApplication對象時,會把該對象賦給一個全局變量sm_pSharedApplication。所以我們在new AppDelegate()的時候,就把它象賦給全局變量sm_pSharedApplication。我們再看下CCApplication的CCApplication::sharedApplication方法:
- CCApplication* CCApplication::sharedApplication()
- {
- CCAssert(sm_pSharedApplication, "");
- return sm_pSharedApplication;
- }
CCApplication* CCApplication::sharedApplication()
{
CCAssert(sm_pSharedApplication, "");
return sm_pSharedApplication;
}
此時,sm_pSharedApplication指向的是一個AppDelegate對象。所以我們執行CCApplication::sharedApplication()->run()時其實執行的是AppDelegate對象的run方法。現在我們應該明白這個類爲什麼叫AppDelegate了,因爲CCApplication的工作實際都委託給了AppDelegate類了。看一下AppDelegate的方法:
- int CCApplication::run()
- {
- // Initialize instance and cocos2d.
- if (! applicationDidFinishLaunching())
- {
- return 0;
- }
- return -1;
- }
int CCApplication::run()
{
// Initialize instance and cocos2d.
if (! applicationDidFinishLaunching())
{
return 0;
}
return -1;
}
- bool AppDelegate::applicationDidFinishLaunching() {
- // initialize director
- CCDirector* pDirector = CCDirector::sharedDirector();
- CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();
- pDirector->setOpenGLView(pEGLView);
- CCSize frameSize = pEGLView->getFrameSize();
- // Set the design resolution
- #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
- pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionShowAll);
- #else
- pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionNoBorder);
- #endif
- 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;
- }
bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
CCDirector* pDirector = CCDirector::sharedDirector();
CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();
pDirector->setOpenGLView(pEGLView);
CCSize frameSize = pEGLView->getFrameSize();
// Set the design resolution
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionShowAll);
#else
pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionNoBorder);
#endif
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;
}