來自:http://xiebaochun.github.io/html
cocos2d-x Android環境搭建java
cocos2d-x環境搭建比較簡單,但是小問題仍是很多,我儘可能都涵蓋的全面一些。
簡單說主要是資源拷貝和代碼編譯。
資源拷貝在個人cygwin裏面發現有問題。拷貝後的文件是錯誤的,且不能刪除我沒有深究,本身手動拷貝了一下。和shell一致,很是easy理解,再也不深究。
ndk-build編譯HelloWorldproject。編譯jni目錄如下的Android.mk,和makefile基本類似,指定需要編譯的文件。include路徑,依賴projectcocos2dx_static。進行編譯,好比HelloWorld的makefile大體例如如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := helloworld_shared
LOCAL_MODULE_FILENAME := libhelloworld
LOCAL_SRC_FILES := helloworld/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)
LOCAL_PATH := $(call my-dir):指定當前路徑爲爲LOCAL_PATH
include $(CLEAR_VARS):清空除LOCAL_PATH以外的其它環境變量的干擾
LOCAL_MODULE&LOCAL_MODULE_FILENAME:模塊名稱&生成庫名稱
LOCAL_SRC_FILES:編譯的C++ Source
LOCAL_WHOLE_STATIC_LIBRARIES:依賴的靜態庫
BUILD_SHARED_LIBRARY:生成的爲共享庫。因爲Android的動態庫都爲JNI所用,因此稱爲共享庫。而靜態庫僅僅爲其它C++庫所用。android
$(call import-module,<name>):經過NDK_MODULE_PATH環境變量引用的模塊<name>的文件夾列表。並且將其本身主動包括到Android.mk中
這樣,一個編譯環境的include,library,target基本指定。則編譯出終於的目標文件,和makefile思路上沒什麼差異,另外這裏需要編譯出cocos2dx.a,靜態庫,是經過cocos2d目錄中的make編譯而成。這個腳本則要複雜一些,只是思想並沒有不一樣。不少其它NDK Make可以參考:《Android Make》
JNI交互
C++接口封裝完成後,咱們就開始看一下Java代碼,瞭解一下終於實現的流程和效果,Java代碼例如如下:
Java層的框架也很是easy。這裏並無多Accelerometer和Music、Sound等進行分析,僅僅是對涉及到顯示相關的進行分析。Java層面流程例如如下:
如上,假設熟悉Android界面開發,可以從基類瞭解到Java層面是經過Activity、GLSuffaceView來進行的顯示。c++
這裏不具體介紹。假設有興趣。可以看一下《剖析遊戲開發用view仍是surfaceView》,View相似傳統的二維靜態界面,數據驅動顯示,而SurfaceView則相似三維機制,實時渲染。git
因爲Cocos2d是OpenGL的。這也好解釋。
對於整個框架事實上要說的也很是多,只是我對Java還不太瞭解。因此有些東西看的不必定透。也不免有一些問題。
Renderer
Renderer類負責每一幀的渲染驅動,調用步驟如圖裏面的1和2。在2中調用jni裏面的nativeRender實現一幀的渲染。而GLSurfaceView則負責UI交互的監聽。
這樣的機制的優勢是在Java中Renderer渲染器是獨立線程調用。所以和UI之間沒有交互性。這樣既保證了用戶體驗(用戶的事件經過GLSurfaceView監聽,終於經過Renderer傳遞至C++層面來響應),也保證了渲染過程的抗干擾,依然經過C++層面進行渲染。github
,整個顯示過程用到的jni封裝主要例如如下:
shell
private static native void nativeTouchesBegin(int id, float x, float y); private static native void nativeTouchesEnd(int id, float x, float y); private static native void nativeTouchesMove(int[] id, float[] x, float[] y); private static native void nativeTouchesCancel(int[] id, float[] x, float[] y); private static native boolean nativeKeyDown(int keyCode); private static native void nativeRender(); private static native void nativeInit(int w, int h); private static native void nativeOnPause(); private static native void nativeOnResume();
第二點,cocos2d主要是遊戲引擎。因此基本所有功能都是由C++層面來實現,一幀的渲染,事件的處理,而Java層主要負責邏輯處理,終於經過jni調用C++接口來實現。第三點來講,cocos2d自己封裝的仍是很是簡潔的,這點我認爲作的仍是很是優雅的,在設計這塊,是以Java的邏輯爲根據來進行劃分。我認爲這個很是可取,儘管cocos2d是C++作起來的。但是並無爲了保證各個平臺的一致性而強迫接口的一致。而是在jni層依照SDK在詳細平臺的應用特色來進行封裝,這樣減低了實現難度。提升了代碼的易用度。犧牲就是應用平臺接口的局部不一致性。jni層面主要是事件傳遞和窗體渲染部分的接口封裝,針對遊戲開發人員而言,最核心的部分都可以在Windows平臺下完畢,而後在Android部分完畢特有事件的傳遞,渲染部分直接採用cocos2d給出的標準範例實現就能夠。大大簡化了開發人員本身封裝jni的工做。
窗體綁定
窗體綁定我理解的並不太透徹,首先,我以爲CCEGLView_Android僅僅是一個虛的窗體,並無實質功能。僅僅是爲了便於架構理解。
bash
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thiz, jint w, jint h) { if (!cocos2d::CCDirector::sharedDirector()->getOpenGLView()) { cocos2d::CCEGLView *view = &cocos2d::CCEGLView::sharedOpenGLView(); view->setFrameWidthAndHeight(w, h); // if you want to run in WVGA with HVGA resource, set it // view->create(480, 320); Please change it to (320, 480) if you're in portrait mode. cocos2d::CCDirector::sharedDirector()->setOpenGLView(view); AppDelegate *pAppDelegate = new AppDelegate(); cocos2d::CCApplication::sharedApplication().run(); } } void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeRender(JNIEnv* env) { cocos2d::CCDirector::sharedDirector()->mainLoop(); }
bool getBitmapFromJava(const char *text, int nWidth, int nHeight, CCImage::ETextAlign eAlignMask, const char * pFontName, float fontSize) { JniMethodInfo methodInfo; if (! JniHelper::getStaticMethodInfo(methodInfo, "org/cocos2dx/lib/Cocos2dxBitmap", "createTextBitmap", "(Ljava/lang/String;Ljava/lang/String;IIII)V")) { CCLOG("%s %d: error to get methodInfo", __FILE__, __LINE__); return false; } jstring jstrText = methodInfo.env->NewStringUTF(text); jstring jstrFont = methodInfo.env->NewStringUTF(pFontName); methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, jstrText, jstrFont, (int)fontSize, eAlignMask, nWidth, nHeight); methodInfo.env->DeleteLocalRef(jstrText); methodInfo.env->DeleteLocalRef(jstrFont); methodInfo.env->DeleteLocalRef(methodInfo.classID); return true; } static bool getStaticMethodInfo_(cocos2d::JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode) { jmethodID methodID = 0; JNIEnv *pEnv = 0; if (! getEnv(&pEnv)) { break; } jclass classID = getClassID_(className, pEnv); methodID = pEnv->GetStaticMethodID(classID, methodName, paramCode);參照裏面的凝視,C++驅動Java實現繪製,Java完畢繪製後,調用Java_org_cocos2dx_lib_Cocos2dxBitmap_nativeInitBitmapDC接口,實現內存的拷貝,而s_BmpDC中的m_pData用來保存,進行下一步的紋理貼圖,完畢整改流程的傳遞. 總結 介紹完成,整個過程當中,cocos2d使用的技術並不神奇,主要是一個熟悉的過程.最值得稱讚的是JNI封裝的比較使用,自己作遊戲開發,基本所有功能都會在C++中封閉實現,僅僅需要提供一個規範的Java外殼就可以,既跨平臺有高效.另外,就是cocos2d對各個平臺的語言取捨,哪些用Java方便,哪些用C++ 保持平臺一致,都作的仍是很是合理的.