Android cocos2dx遊戲開發——示例程序HelloCpp源碼分析

  本文通過分析cocos2dx提供的示例程序HelloCpp來分析cocos2dx的啓動過程。

      我們從HelloCpp.java開始:

  1. package org.cocos2dx.hellocpp;  
  2.   
  3. import org.cocos2dx.lib.Cocos2dxActivity;  
  4.   
  5. import android.os.Bundle;  
  6.   
  7. public class HelloCpp extends Cocos2dxActivity{  
  8.   
  9.     protected void onCreate(Bundle savedInstanceState){  
  10.         super.onCreate(savedInstanceState);  
  11.     }  
  12.       
  13.     static {  
  14.          System.loadLibrary("hellocpp");  
  15.     }  
  16. }  
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中:

  1. @Override  
  2.     protected void onCreate(final Bundle savedInstanceState) {  
  3.         super.onCreate(savedInstanceState);  
  4.         sContext = this;  
  5.         this.mHandler = new Cocos2dxHandler(this);  
  6.   
  7.         this.init();  
  8.   
  9.         Cocos2dxHelper.init(thisthis);  
  10.     }  
@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()方法:

  1. public void init() {  
  2.           
  3.         // FrameLayout  
  4.         ViewGroup.LayoutParams framelayout_params =  
  5.             new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,  
  6.                                        ViewGroup.LayoutParams.FILL_PARENT);  
  7.         FrameLayout framelayout = new FrameLayout(this);  
  8.         framelayout.setLayoutParams(framelayout_params);  
  9.   
  10.         // Cocos2dxEditText layout  
  11.         ViewGroup.LayoutParams edittext_layout_params =  
  12.             new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,  
  13.                                        ViewGroup.LayoutParams.WRAP_CONTENT);  
  14.         Cocos2dxEditText edittext = new Cocos2dxEditText(this);  
  15.         edittext.setLayoutParams(edittext_layout_params);  
  16.   
  17.         // ...add to FrameLayout  
  18.         framelayout.addView(edittext);  
  19.   
  20.         // Cocos2dxGLSurfaceView  
  21.         this.mGLSurfaceView = this.onCreateView();  
  22.   
  23.         // ...add to FrameLayout  
  24.         framelayout.addView(this.mGLSurfaceView);  
  25.   
  26.         // Switch to supported OpenGL (ARGB888) mode on emulator  
  27.         if (isAndroidEmulator())  
  28.            this.mGLSurfaceView.setEGLConfigChooser(8 , 888160);  
  29.   
  30.         this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());  
  31.         this.mGLSurfaceView.setCocos2dxEditText(edittext);  
  32.   
  33.         // Set framelayout as the content view  
  34.         setContentView(framelayout);  
  35.     }  
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方法:

  1. public Cocos2dxGLSurfaceView onCreateView() {  
  2.         return new Cocos2dxGLSurfaceView(this);  
  3.     }  
public Cocos2dxGLSurfaceView onCreateView() {
    	return new Cocos2dxGLSurfaceView(this);
    }

      該方法就是新建一個Cocos2dxGLSurfaceView,Cocos2dxGLSurfaceView又繼承於GLSurfaceView。我們都知道GLSurfaceView的核心就是Renderer,初始化時會調用Renderer的onSurfaceCreated方法,每一幀的繪製是通過調用Renderer的onDrawFrame方法。Cocos2dxGLSurfaceView的Renderer是一個Cocos2dxRenderer對象,我們先來看Cocos2dxRenderer對象的onSurfaceCreated方法:

  1. @Override  
  2.     public void onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig) {  
  3.         Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);  
  4.         this.mLastTickInNanoSeconds = System.nanoTime();  
  5.     }  
@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中實現的:

  1. void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)  
  2. {  
  3.     if (!CCDirector::sharedDirector()->getOpenGLView())  
  4.     {  
  5.         CCEGLView *view = CCEGLView::sharedOpenGLView();  
  6.         view->setFrameSize(w, h);  
  7.   
  8.         AppDelegate *pAppDelegate = new AppDelegate();  
  9.         CCApplication::sharedApplication()->run();  
  10.     }  
  11.     else  
  12.     {  
  13.         ......   
  14.     }  
  15. }  
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()是個靜態方法,用來獲取導演類的單例對象:

  1. CCDirector* CCDirector::sharedDirector(void)  
  2. {  
  3.     if (!s_SharedDirector)  
  4.     {  
  5.         s_SharedDirector = new CCDisplayLinkDirector();  
  6.         s_SharedDirector->init();  
  7.     }  
  8.   
  9.     return s_SharedDirector;  
  10. }  
CCDirector* CCDirector::sharedDirector(void)
{
    if (!s_SharedDirector)
    {
        s_SharedDirector = new CCDisplayLinkDirector();
        s_SharedDirector->init();
    }

    return s_SharedDirector;
}

      CCCCDisplayLinkDirector是CCDirector的子類。我們再回到nativeinit方法中,獲取到導演類的單例對象後又調用了它的getOpenGLView()方法:

  1. 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())條件成立,執行以下的代碼:

  1. CCEGLView *view = CCEGLView::sharedOpenGLView();  
  2. view->setFrameSize(w, h);  
  3.   
  4. AppDelegate *pAppDelegate = new AppDelegate();  
  5. 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在各個平臺之間是通用的不需要修改的,所以就放在一個公用的目錄下。

  1. #ifndef  _APP_DELEGATE_H_  
  2. #define  _APP_DELEGATE_H_  
  3.   
  4. #include "cocos2d.h"  
  5.   
  6. /** 
  7. @brief    The cocos2d Application. 
  8.  
  9. The reason for implement as private inheritance is to hide some interface call by CCDirector. 
  10. */  
  11. class  AppDelegate : private cocos2d::CCApplication  
  12. {  
  13. public:  
  14.     AppDelegate();  
  15.     virtual ~AppDelegate();  
  16.   
  17.     /** 
  18.     @brief    Implement CCDirector and CCScene init code here. 
  19.     @return true    Initialize success, app continue. 
  20.     @return false   Initialize failed, app terminate. 
  21.     */  
  22.     virtual bool applicationDidFinishLaunching();  
  23.   
  24.     /** 
  25.     @brief  The function be called when the application enter background 
  26.     @param  the pointer of the application 
  27.     */  
  28.     virtual void applicationDidEnterBackground();  
  29.   
  30.     /** 
  31.     @brief  The function be called when the application enter foreground 
  32.     @param  the pointer of the application 
  33.     */  
  34.     virtual void applicationWillEnterForeground();  
  35. };  
  36.   
  37. #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的構造方法:

  1. // sharedApplication pointer  
  2. CCApplication * CCApplication::sm_pSharedApplication = 0;  
  3.   
  4. CCApplication::CCApplication()  
  5. {  
  6.     CCAssert(! sm_pSharedApplication, "");  
  7.     sm_pSharedApplication = this;  
  8. }  
// 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方法:

  1. CCApplication* CCApplication::sharedApplication()  
  2. {  
  3.     CCAssert(sm_pSharedApplication, "");  
  4.     return sm_pSharedApplication;  
  5. }  
CCApplication* CCApplication::sharedApplication()
{
    CCAssert(sm_pSharedApplication, "");
    return sm_pSharedApplication;
}

      此時,sm_pSharedApplication指向的是一個AppDelegate對象。所以我們執行CCApplication::sharedApplication()->run()時其實執行的是AppDelegate對象的run方法。現在我們應該明白這個類爲什麼叫AppDelegate了,因爲CCApplication的工作實際都委託給了AppDelegate類了。看一下AppDelegate的方法:

  1. int CCApplication::run()  
  2. {  
  3.     // Initialize instance and cocos2d.  
  4.     if (! applicationDidFinishLaunching())  
  5.     {  
  6.         return 0;  
  7.     }  
  8.       
  9.     return -1;  
  10. }  
int CCApplication::run()
{
    // Initialize instance and cocos2d.
    if (! applicationDidFinishLaunching())
    {
        return 0;
    }
    
    return -1;
}
  1. bool AppDelegate::applicationDidFinishLaunching() {  
  2.     // initialize director  
  3.     CCDirector* pDirector = CCDirector::sharedDirector();  
  4.     CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();  
  5.   
  6.     pDirector->setOpenGLView(pEGLView);  
  7.     CCSize frameSize = pEGLView->getFrameSize();  
  8.   
  9.     // Set the design resolution  
  10. #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)  
  11.     pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionShowAll);  
  12. #else  
  13.     pEGLView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, kResolutionNoBorder);  
  14. #endif  
  15.   
  16.       
  17.     vector<string> searchPath;  
  18.   
  19.     // In this demo, we select resource according to the frame's height.  
  20.     // If the resource size is different from design resolution size, you need to set contentScaleFactor.  
  21.     // We use the ratio of resource's height to the height of design resolution,  
  22.     // this can make sure that the resource's height could fit for the height of design resolution.  
  23.   
  24.     // if the frame's height is larger than the height of medium resource size, select large resource.  
  25.     if (frameSize.height > mediumResource.size.height)  
  26.     {  
  27.         searchPath.push_back(largeResource.directory);  
  28.   
  29.         pDirector->setContentScaleFactor(MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width));  
  30.     }  
  31.     // if the frame's height is larger than the height of small resource size, select medium resource.  
  32.     else if (frameSize.height > smallResource.size.height)  
  33.     {  
  34.         searchPath.push_back(mediumResource.directory);  
  35.           
  36.         pDirector->setContentScaleFactor(MIN(mediumResource.size.height/designResolutionSize.height, mediumResource.size.width/designResolutionSize.width));  
  37.     }  
  38.     // if the frame's height is smaller than the height of medium resource size, select small resource.  
  39.     else  
  40.     {  
  41.         searchPath.push_back(smallResource.directory);  
  42.   
  43.         pDirector->setContentScaleFactor(MIN(smallResource.size.height/designResolutionSize.height, smallResource.size.width/designResolutionSize.width));  
  44.     }  
  45.   
  46.   
  47.     // set searching path  
  48.     CCFileUtils::sharedFileUtils()->setSearchPaths(searchPath);  
  49.       
  50.     // turn on display FPS  
  51.     pDirector->setDisplayStats(true);  
  52.   
  53.     // set FPS. the default value is 1.0/60 if you don't call this  
  54.     pDirector->setAnimationInterval(1.0 / 60);  
  55.   
  56.     // create a scene. it's an autorelease object  
  57.     CCScene *pScene = HelloWorld::scene();  
  58.   
  59.     // run  
  60.     pDirector->runWithScene(pScene);  
  61.   
  62.     return true;  
  63. }  
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;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章