来自:http://xiebaochun.github.io/
cocos2d-x Android环境搭建
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++库所用。
$(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来进行的显示。
这里不具体介绍。假设有兴趣。能够看一下《剖析游戏开发用view还是surfaceView》,View类似传统的二维静态界面,数据驱动显示,而SurfaceView则类似三维机制,实时渲染。
由于Cocos2d是OpenGL的。这也好解释。
对于整个框架事实上要说的也非常多,只是我对Java还不太了解。所以有些东西看的不一定透。也难免有一些问题。
Renderer
Renderer类负责每一帧的渲染驱动,调用步骤如图里面的1和2。在2中调用jni里面的nativeRender实现一帧的渲染。而GLSurfaceView则负责UI交互的监听。
这样的机制的优点是在Java中Renderer渲染器是独立线程调用。因此和UI之间没有交互性。这样既保证了用户体验(用户的事件通过GLSurfaceView监听,终于通过Renderer传递至C++层面来响应),也保证了渲染过程的抗干扰,依然通过C++层面进行渲染。
,整个显示过程用到的jni封装主要例如以下:
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仅仅是一个虚的窗体,并没有实质功能。仅仅是为了便于架构理解。
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);