1、cocos2d-x跨平臺html
cocos2d-x究竟是怎樣實現跨平臺的呢?這裏以Win32和Android爲例。html5
1. 跨平臺項目目錄結構java
先看一下一個項目建立後的目錄結構吧!這仍是以HelloCpp爲例。python
從左邊目錄能夠看到,Classes和Resource已經平臺無關了,而Classes中包含了AppDelegate類,所以咱們能夠認爲AppDelegate是與平臺最接近的類,在它以上就要區分平臺了。linux
2. Win32下的實現android
在前一篇就介紹了Win32怎麼開始cocos2dx,Win32平臺下main.cpp就是程序入口:c++
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // create the application instance AppDelegate app;//建立應用實例 CCEGLView* eglView = CCEGLView::sharedOpenGLView(); eglView->setViewName("HelloCpp"); eglView->setFrameSize(2048, 1536); eglView->setFrameZoomFactor(0.4f); return CCApplication::sharedApplication()->run();//運行程序 }
Win32下的實現比較簡單,就是正常的建立實例,運行就能夠了。編程
3.Android下的實現瀏覽器
3.1.cocos2d-x程序入口網絡
咱們先看一下Android下cocos2d-x程序入口點在哪,咱們知道Android是採用Java編寫的,而cocos2d-x是c++編寫的,因此若是要在Java中調用c++代碼,那就須要採用JNI技術,看起來好像高端大氣上檔次,其實程序就是函數調用,也就是輸入→處理→輸出,因此JNI實際上簡單抽象出來就這麼回事:
java輸入→Jni→c++輸入→c++處理(API實現)→c++輸出→Jni→java輸出
在\proj.android\jni\hellocpp文件夾下能夠找到main.cpp,這就是cocos2d-x的入口:
jint JNI_OnLoad(JavaVM *vm, void *reserved) { JniHelper::setJavaVM(vm); return JNI_VERSION_1_4; } 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 { ccGLInvalidateStateCache(); CCShaderCache::sharedShaderCache()->reloadDefaultShaders(); ccDrawInit(); CCTextureCache::reloadAllTextures(); CCNotificationCenter::sharedNotificationCenter()->postNotification(EVENT_COME_TO_FOREGROUND, NULL); CCDirector::sharedDirector()->setGLDefaultValues(); } }
裏面包含了2個函數,JNI_OnLoad和Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit。咱們看一下功能而先無論它在哪裏被調用。
(1)JNI_OnLoad,這個函數主要是用來告訴Android VM當前使用的是什麼版本是Jni,若是不提供此函數,則默認使用Jni1.1版本。
(2)Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit,這個函數很明顯就是運行一個cocos2d-x的應用實例了,這和Win32是同樣的,固然它多了一個openGlView的檢測。一旦調用了它那麼cocos2d-x遊戲啓動。
接下來再看看它們是在哪裏被調用的。
在Android.mk文件內容以下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hellocpp_shared LOCAL_MODULE_FILENAME := libhellocpp LOCAL_SRC_FILES := hellocpp/main.cpp \ ../../Classes/AppDelegate.cpp \ ../../Classes/HelloWorldScene.cpp LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static include $(BUILD_SHARED_LIBRARY) $(call import-module,cocos2dx)
3.2 JNI_OnLoad的調用
在proj.android\src\org\cocos2dx\hellocpp目錄下,能夠看到Android的入口Activity,也就是HelloCpp,它繼承自Cocos2dxActivity。
public class HelloCpp extends Cocos2dxActivity{ protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); } static { System.loadLibrary("hellocpp"); } }
很簡單的代碼,由於功能都被封裝到Cocos2dxActivity中了,因此OnCreate中調用了父類的OnCreate就把功能都實現了,而system.LoadLibrary就是載入編譯出來的.so文件,此時就會執行JNI_OnLoad。
3.3 Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit的調用
那最重要的Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit是在哪調用呢?這就比較麻煩了,先大體瞭解一下Cocos2dxActivity作了一些什麼事。
直接進入Cocos2dxActivity的OnCreate函數,它調用了一個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佈局,這一個跟GLSurfaceView兼容的edittext 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); // 添加到framelaout
framelayout.addView(edittext);
// 建立Cocos2dxGLSurfaceView this.mGLSurfaceView = this.onCreateView(); // 添加到framelaout framelayout.addView(this.mGLSurfaceView);
// Switch to supported OpenGL (ARGB888) mode on emulator if (isAndroidEmulator()) this.mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); //設置Cocos2dxRenderer和Cocos2dxEditText this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer()); this.mGLSurfaceView.setCocos2dxEditText(edittext); // 設置framelayout做爲內容視圖 setContentView(framelayout); }
在這裏Cocos2dxActivity作的就是建立Cocos2dxGLSurfaceView,並設置了Cocos2dxRenderer和Cocos2dxEditText,而後添加到FramLayout。具體的各部分實現這裏就不貼代碼了,畫了個圖:
2、 AppDelegate 析造函數沒有被調用
怎麼樣使用 Cocos2d-x 快速開發遊戲,方法很簡單,你能夠看看其自帶的例程,或者從網上搜索教程,運行起第一個 Scene HelloWorldScene,而後在HelloWorldScene 裏面寫相關邏輯代碼,添加咱們的層、精靈等 ~ 咱們並不必定須要知道 Cocos2d-x 是如何運行或者在各類平臺之上運行,也不用知道 Cocos2d-x 的遊戲是如何運行起來的,它又是如何渲染界面的 ~~~
咱們只用知道 Cocos2d-x 的程序是由 AppDelegate 的方法 applicationDidFinishLaunching 開始,在其中作些必要的初始化,並建立運行第一個 CCScene 便可,正如咱們第一次使用各類編程語言寫 Hello World! 的程序同樣,如 Python 打印:
print(‘Hello World!’)
咱們能夠不用關心其是怎麼實現的,咱們只要知道這樣就能打印一句話就夠了,這就是封裝所帶來的好處 。Cocos2d-x 自帶的例程已經足夠豐富,可是有些問題並非看看例子,調用其方法就能明白的事情,在這裏遇到了以下問題:
// AppDelegate.cpp 文件 AppDelegate::AppDelegate() { CCLog("AppDelegate()"); // AppDelegate 構造函數打印 } AppDelegate::~AppDelegate() { CCLog("AppDelegate().~()"); // AppDelegate 析構函數打印 } // 程序入口 bool AppDelegate::applicationDidFinishLaunching() { // initialize director CCDirector *pDirector = CCDirector::sharedDirector(); pDirector->setOpenGLView(CCEGLView::sharedOpenGLView()); // 初始化,資源適配,屏幕適配,運行第一個場景等代碼 ... ... ... return true; } void AppDelegate::applicationDidEnterBackground() { CCDirector::sharedDirector()->pause(); } void AppDelegate::applicationWillEnterForeground() { CCDirector::sharedDirector()->resume(); }
此時我並不知道程序運行時,什麼時候調用 AppDelegate 的構造函數,析構函數和程序入口函數,咱們只要知道,程序在這裏調用了其構造函數,而後進入入口函數執行其過程,最後再調用其析構函數便可。然而事與願違,在實際執行的過程當中,發現程序只調用其構造函數和入口函數,而直到程序結束運行,都沒有調用其析構函數。要驗證此說法很簡單,只要如上在析構函數中調用打印日誌即可驗證。
發生這樣的狀況,讓我在構造函數建立[資源],而且在析構函數中釋放[資源] 的想法不能完成!!! 咱們知道它是從哪裏開始運行,但殊不知道它在哪裏結束!疑問,惟有疑問!
兩個入口
程序入口的概念是相對的,AppDelegate 做爲跨平臺程序入口,在這之上作了另外一層的封裝,封裝了不一樣平臺的不一樣實現,好比咱們一般認爲一個程序是由 main 函數開始運行,那咱們就去找尋,咱們看到了在 proj.linux 目錄下存在 main.cpp 文件,這就是咱們要看的內容,以下:
#include "main.h" #include "../Classes/AppDelegate.h" #include "cocos2d.h" #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string> USING_NS_CC; // 500 is enough? #define MAXPATHLEN 500 int main(int argc, char **argv) { // get application path int length; char fullpath[MAXPATHLEN]; length = readlink("/proc/self/exe", fullpath, sizeof(fullpath)); fullpath[length] = '\0'; std::string resourcePath = fullpath; resourcePath = resourcePath.substr(0, resourcePath.find_last_of("/")); resourcePath += "/../../../Resources/"; // create the application instance AppDelegate app; CCApplication::sharedApplication()->setResourceRootPath(resourcePath.c_str()); CCEGLView* eglView = CCEGLView::sharedOpenGLView(); eglView->setFrameSize(720, 480); // eglView->setFrameSize(480, 320); return CCApplication::sharedApplication()->run(); }
在這裏咱們看見了程序的真正入口,包含一個 main 函數,今後進入,執行 cocos2d-x 程序。咱們看到 main 就知道其是入口函數,那麼沒有 main 函數就沒有入口了嗎?顯然不是,以 Android 平臺啓動 cocos2d-x 程序爲例。咱們找到 Android 平臺與上面等價的入口點,proj.android/jni/hellocpp/main.cpp:
#include "cocos2d.h" #include "AppDelegate.h" #include "platform/android/jni/JniHelper.h" #include <jni.h> #include <android/log.h> #define LOG_TAG "main" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) using namespace cocos2d; extern "C" { jint JNI_OnLoad(JavaVM *vm, void *reserved) { JniHelper::setJavaVM(vm); return JNI_VERSION_1_4; } 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 { ccDrawInit(); ccGLInvalidateStateCache(); CCShaderCache::sharedShaderCache()->reloadDefaultShaders(); CCTextureCache::reloadAllTextures(); CCNotificationCenter::sharedNotificationCenter()->postNotification(EVNET_COME_TO_FOREGROUND, NULL); CCDirector::sharedDirector()->setGLDefaultValues(); } }
咱們並無看到所謂的 main 函數,這是因爲不一樣的平臺封裝因此有着不一樣的實現,在 Android 平臺,默認是使用 Java 開發,可使用 Java 經過 Jni 調用 C++ 程序,而這裏也正式如此。咱們暫且只需知道,由 Android 啓動一個應用,經過各類峯迴路轉,最終執行到了 Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit 函數,由此,便開始了咱們 cocos2d-x Android 平臺的程序入口處。對於跨平臺的 cocos2d-x 來講,除非必要,不然可沒必要深究其理,好比想要使用 Android 平臺固有的特性等,那就須要更多的瞭解 Jni 使用方法,以及 Android 操做系統的更多細節。
因此說程序的入口是相對的,正如博文開始的 print(‘Hello World’) 同樣,不一樣的語言,不一樣平臺總有着不一樣的實現。
這裏咱們參考了兩個不一樣平臺的實現, Linux 和 Android 平臺 cocos2d-x 程序入口 main.cpp的實現,那麼其它平臺呢,如 iOS ,Win32 等 ~~~ 異曲同工,其它平臺程序的入口必然包含着其它平臺的不一樣封裝實現 ,知道有等價在此兩平臺的程序入口便可。而經過這兩個平臺也足夠解決咱們的疑問,程序的開始與結束 ~
咱們就從 Linux 和 Android 這兩個平臺的入口函數開始,看看 cocos2d-x 的執行流程到底爲什麼?何以發生只執行了 AppDelegate 的構造函數,而沒有析構函數。在查看 cocos2d-x 程序代碼時,咱們只關注必要的內容,何謂必要,只要能解決咱們此時的疑問便可!在兩個平臺的入口函數,咱們看到以下內容:
// Linux 平臺關鍵代碼 int main(int argc, char **argv) { // 初始化等內容 ... ... // 建立 app 變量 AppDelegate app; ... ... // 執行 核心 run() 方法 return CCApplication::sharedApplication()->run(); } // Android 平臺關鍵代碼 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 對象 AppDelegate *pAppDelegate = new AppDelegate(); // 執行 核心 run() 方法 CCApplication::sharedApplication()->run(); } else { ... ... } }
不一樣的平臺,卻實現相同操做,建立 AppDelegate 變量和執行 run 方法。下面將以 Linux 平臺爲例,來講明程序是如何開始與結束的,由於 Linux 的內部實現要簡單一點,而 Android 平臺的實現稍顯麻煩,Jni 之間來回調用,對咱們理解 cocos2d-x 的執行流程反而有所 阻礙,何況 cocos2d-x 自己就是跨平臺的程序。沒必要拘泥於特有平臺的專有特性。
程序的流程 (這裏以 Linux 的實現爲主,其它平臺舉一反三便可)
AppDelegate 與 CCApplication關係
咱們從 main.cpp 中 CCApplication::sharedApplication()->run(); 這一句看起,這一句標誌着, cocos2d-x 程序正式開始運行,一點點開始分析,咱們定位到 sharedApplication() 方法的實現,這裏只給出必要的代碼,具體看一本身直接看源碼:
// [cocos2dx-path]/cocos2dx/platform/linux/CCApplication.cpp ... // 此變量爲定義了一個 CCApplication 的靜態變量,也及時本身類型自己,實現單例模式 CCApplication * CCApplication::sm_pSharedApplication = 0; ... // 構造函數,將所建立的 對象直接付給其靜態變量 CCApplication::CCApplication() { // 斷言在此決定着此構造函數只能運行一次 CC_ASSERT(! sm_pSharedApplication); sm_pSharedApplication = this; } CCApplication::~CCApplication() { CC_ASSERT(this == sm_pSharedApplication); sm_pSharedApplication = NULL; m_nAnimationInterval = 1.0f/60.0f*1000.0f; } // run 方法,整個 cocos2d-x 的主循環在這裏開始 int CCApplication::run() { // 首次啓動調用初始化函數 if (! applicationDidFinishLaunching()) { return 0; } // 遊戲主循環,這裏 Linux 的實現相比其它平臺的實現,簡單明瞭 for (;;) { long iLastTime = getCurrentMillSecond(); // 在循環以內調用每一幀的邏輯,組織而且控制 cocos2d-x 之中各個組件 CCDirector::sharedDirector()->mainLoop(); long iCurTime = getCurrentMillSecond(); // 這裏的幾個時間變量,能夠控制每一幀所運行的 最小 時間,從而控制遊戲的幀率 if (iCurTime-iLastTime<m_nAnimationInterval){ usleep((m_nAnimationInterval - iCurTime+iLastTime)*1000); } } // 注意,這裏的 for 循環,並無退出循環條件,這也決定着 run() 方法永遠也不會返回 return -1; } // 方法直接返回了靜態對象,而且作了斷言,也既是在調用此方法以前, // 必須事先建立一個 CCApplication 的對象,以保證其靜態變量可以初始化,不然返回空 CCApplication* CCApplication::sharedApplication() { CC_ASSERT(sm_pSharedApplication); return sm_pSharedApplication; }
從上面的內容能夠看出,從 sharedApplication() 方法,到 run() 方法,在這以前,咱們須要調用到它(CCApplication)的構造函數,不然不能運行,這就是爲何在 CCApplication::sharedApplication()->run(); 以前,咱們首先使用了 AppDelegate app; 建立 AppDelegate 變量的緣由! 嗯 !! AppDelegate 和 CCAppliation 是什麼關係? 由 AppDelegate 的定義咱們能夠知道,它是 CCApplication 的子類,在建立子類對象的時候,調用其構造函數的同時,父類構造函數也會執行,而後就將 AppDelegate 的對象賦給了 CCApplication 的靜態變量,而在 AppDelegate 之中咱們實現了 applicationDidFinishLaunching 方法,因此在 CCApplication 中 run 方法的開始處調用的就是 AppDelegate 之中的實現。而咱們在此方法中咱們初始化了一些變量,建立了第一個 CCScene 場景等,以後的控制權,便全權交給了 CCDirector::sharedDirector()->mainLoop(); 方法了。
(這裏的實現機制,不作詳細說明,簡單說來:applicationDidFinishLaunching 是由 CCApplicationProtocol 定義,CCApplication 繼承, AppDelegate 實現的 ~)
比較重要的所在,for 循環並無循環退出條件,因此 run 方法永遠不會返回。那麼是怎麼結束的呢?
從 CCApplication 到 CCDirector
cocos2d-x 程序已經運行起來了,咱們繼續下一步,mainLoop 函數:
// [cocos2dx-path]/cocos2dx/CCDirector.cpp ... // 定義靜態變量,實現單例模式 static CCDisplayLinkDirector *s_SharedDirector = NULL; ... // 返回 CCDirector 實例 CCDirector* CCDirector::sharedDirector(void) { // 判斷靜態變量,以保證只有一個實例 if (!s_SharedDirector) { s_SharedDirector = new CCDisplayLinkDirector(); s_SharedDirector->init(); } // CCDisplayLinkDirector 爲 CCDirector 的子類,這裏返回了其子類 return s_SharedDirector; } // mainLoop 方法的具體實現 void CCDisplayLinkDirector::mainLoop(void) { // 此變量是咱們須要關注,而且跟蹤的,由於它決定着程序的結束時機 if (m_bPurgeDirecotorInNextLoop) { m_bPurgeDirecotorInNextLoop = false; // 運行到此,說明程序的運行,已經沒有邏輯代碼須要處理了 purgeDirector(); } else if (! m_bInvalid) { // 屏幕繪製,並作一些相應的邏輯處理,其內部處理,這裏暫且不作過多探討 drawScene(); // 這裏實現了 cocos2d-x CCObject 對象的內存管理機制,對此有興趣者,能夠深刻下去 CCPoolManager::sharedPoolManager()->pop(); } } // 彈出場景 CCScene void CCDirector::popScene(void) { CCAssert(m_pRunningScene != NULL, "running scene should not null"); m_pobScenesStack->removeLastObject(); unsigned int c = m_pobScenesStack->count(); if (c == 0) { // 若是沒有場景,調用 end() 方法 end(); } else { m_bSendCleanupToScene = true; m_pNextScene = (CCScene*)m_pobScenesStack->objectAtIndex(c - 1); } } void CCDirector::end() { // 在 end 方法中,設置了變量爲 true,這所致的結果,在 mainLoop 函數中,達成了運行 purgeDirector 方法的條件 m_bPurgeDirecotorInNextLoop = true; } // 此方法作些收尾清理的工做 void CCDirector::purgeDirector() { ... if (m_pRunningScene) { m_pRunningScene->onExit(); m_pRunningScene->cleanup(); m_pRunningScene->release(); } // 作一些清理的工做 ... // OpenGL view // ###此句代碼關鍵### m_pobOpenGLView->end(); m_pobOpenGLView = NULL; // delete CCDirector release(); } // 設置 openglview void CCDirector::setOpenGLView(CCEGLView *pobOpenGLView) { CCAssert(pobOpenGLView, "opengl view should not be null"); if (m_pobOpenGLView != pobOpenGLView) { // EAGLView is not a CCObject delete m_pobOpenGLView; // [openGLView_ release] // 爲當前 CCDirector m_pobOpenGLView 賦值 m_pobOpenGLView = pobOpenGLView; // set size m_obWinSizeInPoints = m_pobOpenGLView->getDesignResolutionSize(); createStatsLabel(); if (m_pobOpenGLView) { setGLDefaultValues(); } CHECK_GL_ERROR_DEBUG(); m_pobOpenGLView->setTouchDelegate(m_pTouchDispatcher); m_pTouchDispatcher->setDispatchEvents(true); } }
遊戲的運行以場景爲基礎,每時每刻都有一個場景正在運行,其內部有一個場景棧,遵循後進後出的原則,當咱們顯示的調用 end() 方法,或者彈出當前場景之時,其自動判斷,若是沒有場景存在,也會觸發 end() 方法,以說明場景運行的結束,而遊戲若是沒有場景,就像演出沒有了舞臺,程序進入最後收尾的工做,經過修改變量 m_bPurgeDirecotorInNextLoop 促使在程序 mainLoop 方法以內調用 purgeDirector 方法。
CCEGLView 的收尾工做
purgeDirector 方法以內,經過猜想與排查,最終定位到 m_pobOpenGLView->end(); 方法,在這裏結束了 cocos2d-x 遊戲進程。而 m_pobOpenGLView 什麼時候賦值,它的具體實現又在哪裏呢?咱們能夠在 AppDelegate 的 applicationDidFinishLaunching 方法中找到以下代碼:
// AppDelegate.cpp CCDirector *pDirector = CCDirector::sharedDirector(); pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());
咱們終於走到最後一步,看 CCEGLView 是若是負責收尾工做的:
// [cocos2dx-path]/cocos2dx/platform/linux.CCEGLView.cpp ... CCEGLView* CCEGLView::sharedOpenGLView() { static CCEGLView* s_pEglView = NULL; if (s_pEglView == NULL) { s_pEglView = new CCEGLView(); } return s_pEglView; } ... // openglview 結束方法 void CCEGLView::end() { /* Exits from GLFW */ glfwTerminate(); delete this; exit(0); }
end() 方法很簡單,只須要看到最後一句 exit(0); 就明白了。
cocos2d-x 程序的結束流程
程序運行時期,由 mainLoop 方法維持運行着遊戲以內的各個邏輯,當在彈出最後一個場景,或者直接調用 CCDirector::end(); 方法後,觸發遊戲的清理工做,執行 purgeDirector 方法,從而結束了 CCEGLView(不一樣平臺不一樣封裝,PC使用OpenGl封裝,移動終端封裝的爲 OpenGl ES) 的運行,調用其 end() 方法,從而直接執行 exit(0); 退出程序進程,從而結束了整個程序的運行。(Android 平臺的 end() 方法內部經過Jni 方法 terminateProcessJNI(); 調用 Java 實現的功能,其功能同樣,直接結束了當前運行的進程)
從程序的 main 方法開始,再建立 AppDelegate 等對象,運行過程當中倒是經過 exit(0); 來退出程序。因此咱們看到了 AppDelegate 構造函數被調用,而其析構函數沒有被調用的現象。exit(0); 的執行,意味着咱們的程序徹底結束,固然咱們的進程資源也會被操做系統釋放。可是注意,這裏的"在構造函數建立[資源],而且在析構函數中釋放[資源]"並不是絕對意義上的程序進程資源,在程序退出的時候,程序所使用的資源固然會被系統回收. 可是若是我在構造函數調用網絡接口初始化,析構再調用一次通知,所影響到的相似這種 非本地資源 邏輯上的處理,便會留下隱患。而經過理解 cocos2d-x 的運行機制,能夠減小這種可能存在的隱患。
cocos2d-x 的總體把握
在本文經過解決一個小疑問,而去分析 cocos2d-x 遊戲的運行流程,固然其中不少細緻末葉咱們並無深刻下去。不去解決這個疑問也能夠,知道沒有調用析構函數,那我就不調用即是 (這也是簡單的解決方法,也不用以爲這不可行 )。這裏只是藉着這個疑問,對 cocos2d-x 的流程稍做探尋而已。也沒有貼一堆 cocos2d-x 源碼去分析,其思路也有跡可循。
什麼是 cocos2d-x ,它是 cocos2d 一個 C++ 的實現,除 C++ 以外,有 python ,Objective-C 等其它語言的實現,那該怎麼去理解 cocos2d ,能夠這麼理解,cocos2d 是一個編寫 2D 遊戲的通用形框架,這種框架提供了一個通用模型,而這種模型或者說架構是 無關語言與平臺 的,說 cocos2d-x 使用 C++ 編寫,其跨平臺能力很強,但它能跑在瀏覽器上麼?cocos2d 仍是有着 html5 的實現,固然平臺決定着語言的選擇,而 cocos2d 可以適應這麼多不一樣的語言和平臺,其良好的設計,清晰的結構功不可沒。 而對不一樣語言,對相同功能有着不一樣的封裝,正如在本文問題中,在不一樣平臺(Linux 和 Android),對相同功能有着不一樣的封裝殊途同歸。那麼封裝到最後,咱們對 cocos2d 的理解就只剩下了,咱們要寫遊戲,那麼須要導演,場景、層、精靈、動做等 ~~ 組織好這些之間的關係便可 ~
【轉自】http://game.dapps.net/gamedev/game-engine/9515.html