cocos2d-x怎么实现跨平台

| 分类 cocos2d-x  | 标签 cocos2d-x 

本文为xiedantibu在学习cocos2d-x的笔记,转载请注明作者及出处! ###目录 —-     前言
    Cocos2dxActivity的oncreate
    Cocos2dxActivity的onResume和onPause


####前言 — 本文其实讲的不是跨平台的事情,所以标题有点忽悠。。。Duang~Duang~Duang~…我其实是想透过本文,理解下cocos2d-x,他是怎么干活的。好了,下面就开始吧…以android代码为例子…


####Cocos2dxActivity的oncreate

android世界的起点在activity,cocos2d-x起点也就在Cocos2dxActivity。而oncreate方法就是这个起点的入口。

  1. Cocos2dxActivity的入口方法oncreate
  1. protected void onCreate(final Bundle savedInstanceState) {
  2. super.onCreate(savedInstanceState);
  3. onLoadNativeLibraries();//这句话是去加载.so文件。主要代码是System.loadLibrary(libName)
  4. sContext = this;
  5. this.mHandler = new Cocos2dxHandler(this);//初始化Cocos2dxHandler句柄,这个类做的主要工作是负责弹出Dialog
  6. Cocos2dxHelper.init(this);//初始化如包名,apk安装路径,音乐
  7. this.mGLContextAttrs = getGLContextAttrs();//getGLContextAttrs是一个Native方法,具体实现在C++部分,返回的是一个int数组,将返回的值设置到setEGLConfigChooser中,获取不同depth buffer的Surface
  8. this.init();//主要工作是创建一个GLSurfaceView,并且自定义设置这个Surface的每个channel的depth,同时给这个view设置渲染工具
  9. if (mVideoHelper == null) {
  10. mVideoHelper = new Cocos2dxVideoHelper(this, mFrameLayout);//把mFrameLayout赋值到Cocos2dxVideoHelper中,方便如果需要Video的时候添加到mFrameLayout中
  11. }
  12. if(mWebViewHelper == null){
  13. mWebViewHelper = new Cocos2dxWebViewHelper(mFrameLayout);
  14. }
  15. } > Cocos2dxActivitygetGLContextAttrs的做了啥事情
private static native int[] getGLContextAttrs();//这就是natvie方法,下面就是具体实现 jintArray Java_org_cocos2dx_lib_Cocos2dxActivity_getGLContextAttrs(JNIEnv* env, jobject thiz)
  1. {
  2. cocos_android_app_init(env, thiz);//这句话就是告诉c++们,准备好了啊,给我初始化AppDelegate,顺便提下这方法就在main.cpp中
  3. cocos2d::Application::getInstance()->initGLContextAttrs(); //初始化完了AppDelegate,就调用AppDelegate的initGLContextAttrs方法,同时将设置的值赋值给GLView中的_glContextAttrs
  4. GLContextAttrs _glContextAttrs = GLView::getGLContextAttrs();//获取上面的赋值
  5. int tmp[6] = {_glContextAttrs.redBits, _glContextAttrs.greenBits, _glContextAttrs.blueBits,
  6. _glContextAttrs.alphaBits, _glContextAttrs.depthBits, _glContextAttrs.stencilBits};//把_glContextAttrs的值保存到int中,传递到java层
  7. jintArray glContextAttrsJava = env->NewIntArray(6);
  8. env->SetIntArrayRegion(glContextAttrsJava, 0, 6, tmp);
  9. return glContextAttrsJava;
  10. }
  1. Cocos2dxActivitythis.init()方法,具体实现
public void init() {
  1. // FrameLayout
  2. ViewGroup.LayoutParams framelayout_params =
  3. new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
  4. ViewGroup.LayoutParams.MATCH_PARENT);
  5. mFrameLayout = new FrameLayout(this);//创建一个FrameLayout
  6. mFrameLayout.setLayoutParams(framelayout_params);
  7. // Cocos2dxEditText layout
  8. ViewGroup.LayoutParams edittext_layout_params =
  9. new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
  10. ViewGroup.LayoutParams.WRAP_CONTENT);
  11. Cocos2dxEditText edittext = new Cocos2dxEditText(this);
  12. edittext.setLayoutParams(edittext_layout_params);
  13. // ...add to FrameLayout
  14. mFrameLayout.addView(edittext);//将Cocos2dxEditText添加到FrameLayout
  15. // Cocos2dxGLSurfaceView
  16. this.mGLSurfaceView = this.onCreateView();//创建Cocos2dxGLSurfaceView,修改GLSurfaceView的设置。如setEGLConfigChooser(int, int, int, int, int, int) 指定red ,green, blue, alpha, depth ,stencil 支持的位数,缺省为RGB_565 ,16 bit depth buffer.
  17. // ...add to FrameLayout
  18. mFrameLayout.addView(this.mGLSurfaceView);//将Cocos2dxGLSurfaceView添加到mFrameLayout
  19. // Switch to supported OpenGL (ARGB888) mode on emulator
  20. if (isAndroidEmulator())//如果是模拟器,则重新设置
  21. this.mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
  22. this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());//设置渲染,主要渲染工作就在Cocos2dxRenderer类中
  23. this.mGLSurfaceView.setCocos2dxEditText(edittext);
  24. // Set framelayout as the content view
  25. setContentView(mFrameLayout);//将FrameLayout添加到到View中
  26. }
  1. Cocos2dxActivityonCreateView()方法具体实现,创建GLSurfaceView
public Cocos2dxGLSurfaceView onCreateView() {
  1. Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSurfaceView(this);//创建Cocos2dxGLSurfaceView
  2. //this line is need on some device if we specify an alpha bits
  3. if(this.mGLContextAttrs[3] > 0) //GLSurfaceView 缺省创建为RGB_565 颜色格式的Surface ,如果需要支持透明度,可以调用getHolder().setFormat(PixelFormat.TRANSLUCENT).
  4. glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
  5. Cocos2dxEGLConfigChooser chooser = new Cocos2dxEGLConfigChooser(this.mGLContextAttrs);
  6. glSurfaceView.setEGLConfigChooser(chooser);//指定red ,green, blue, alpha, depth ,stencil 支持的位数,缺省为RGB_565 ,16 bit depth buffer.必须在setRenderer()方法之前设置
  7. return glSurfaceView;
  8. } >话说在创建Cocos2dxGLSurfaceView的时候,初始化主要做了啥工作呢?
this.setEGLContextClientVersion(2);//设置opengl es
  1. this.setFocusableInTouchMode(true);//设置GLSurfaceView可以获取触摸事件
  1. 在上面的一系列方法中,我们已经创建了GLSurfaceView,但还需要通过Cocos2dxRenderer绘制东西到GLSurfaceView上面。Cocos2dxRenderer实现了GLSurfaceView.Renderer这个接口,具体方法如下:
@Override
  1. public void onSurfaceCreated(final GL10 GL10, final EGLConfig EGLConfig) {
  2. Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);//这个方法做了好多的工作,稍候具体详解
  3. this.mLastTickInNanoSeconds = System.nanoTime();
  4. mNativeInitCompleted = true;
  5. }
  6. @Override
  7. public void onSurfaceChanged(final GL10 GL10, final int width, final int height) {
  8. Cocos2dxRenderer.nativeOnSurfaceChanged(width, height);//surface 的尺寸发生改变时该方法被调用
  9. }
  10. @Override
  11. public void onDrawFrame(final GL10 gl) {
  12. /*
  13. * No need to use algorithm in default(60 FPS) situation,
  14. * since onDrawFrame() was called by system 60 times per second by default.
  15. */
  16. if (sAnimationInterval <= 1.0 / 60 * Cocos2dxRenderer.NANOSECONDSPERSECOND) {
  17. Cocos2dxRenderer.nativeRender();//渲染工作,会一直回调
  18. } else {
  19. final long now = System.nanoTime();
  20. final long interval = now - this.mLastTickInNanoSeconds;
  21. if (interval < Cocos2dxRenderer.sAnimationInterval) {
  22. try {
  23. Thread.sleep((Cocos2dxRenderer.sAnimationInterval - interval) / Cocos2dxRenderer.NANOSECONDSPERMICROSECOND);
  24. } catch (final Exception e) {
  25. }
  26. }
  27. /*
  28. * Render time MUST be counted in, or the FPS will slower than appointed.
  29. */
  30. this.mLastTickInNanoSeconds = System.nanoTime();
  31. Cocos2dxRenderer.nativeRender();
  32. }
  33. }
  1. SurfaceView创建的时候,会去调用onSurfaceCreated,而我们关心的就是Cocos2dxRenderer.nativeInit这个方法
  1. void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thiz, jint w, jint h)
  2. {
  3. auto director = cocos2d::Director::getInstance();//实例化导演类
  4. auto glview = director->getOpenGLView();//获取glview
  5. if (!glview)
  6. {
  7. glview = cocos2d::GLViewImpl::create("Android app");//GLViewImpl这个类是GLView的子类,在不同的平台有不同的实现
  8. glview->setFrameSize(w, h);//设置屏幕大小
  9. director->setOpenGLView(glview);//把glview赋值给导演类
  10. //cocos_android_app_init(env, thiz);
  11. cocos2d::Application::getInstance()->run();//这个方法其实主要就做了就是回调applicationDidFinishLaunching()这个方法,而这个方法其实对于我们开发者来说相当熟悉
  12. }
  13. else//重新初始化各参数
  14. {
  15. cocos2d::GL::invalidateStateCache();
  16. cocos2d::GLProgramCache::getInstance()->reloadDefaultGLPrograms();
  17. cocos2d::DrawPrimitives::init();
  18. cocos2d::VolatileTextureMgr::reloadAllTextures();
  19. cocos2d::EventCustom recreatedEvent(EVENT_RENDERER_RECREATED);
  20. director->getEventDispatcher()->dispatchEvent(&recreatedEvent);
  21. director->setGLDefaultValues();
  22. }
  23. } > 接下来就得说说onDrawFrame中的这方法Cocos2dxRenderer.nativeRender()
  24. JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeRender(JNIEnv* env) {
  25. cocos2d::Director::getInstance()->mainLoop();//这方法肯定又是很熟悉,全都跑到Director上了,当然这方法的实现是DisplayLinkDirector这类上方法。每一次回调onDrawFrame,真正运行的就是mainLoop()方法。
  26. } > 还是继续扯下mainLoop()方法
  27. void DisplayLinkDirector::mainLoop()
  28. {
  29. if (_purgeDirectorInNextLoop)//这值默认都是false,只有运行了Director::end()才被设置为true,可见要结束游戏,真正的关键是这
  30. {
  31. _purgeDirectorInNextLoop = false;
  32. purgeDirector();//根据不同的平台运行GLViewImpl::end(),在android中调用的是terminateProcessJNI,而这个方法就是通过调用jni,回调java层实现的方法terminateProcess(),杀掉当前游戏的进程
  33. }
  34. else if (_restartDirectorInNextLoop)//当重新执行Director的时候_restartDirectorInNextLoop为true
  35. {
  36. _restartDirectorInNextLoop = false;
  37. restartDirector();
  38. }
  39. else if (! _invalid)//默认为false,当运行DisplayLinkDirector::stopAnimation()方法为true
  40. {
  41. drawScene();//绘制场景了
  42. // release the objects
  43. PoolManager::getInstance()->getCurrentPool()->clear();//释放AutoreleasePool
  44. }
  45. }

好了,差不多也讲完主要流程了,现在总结下oncreate()这方法主要干了啥?

  1. 加载.so文件
  2. 初始化Cocos2dxHandler,弹出dialog做铺垫。
  3. 初始化Cocos2dxHelper中的各个参数
  4. 初始化AppDelegate
  5. 指定red ,green, blue, alpha, depth ,stencil 支持的位数,也就是initGLContextAttrs
  6. 创建Cocos2dxGLSurfaceView
  7. 创建Cocos2dxRenderer,当然还有onSurfaceCreated,onSurfaceChanged,onDrawFrame三个方法
  8. 设置渲染

以上的方法讲的一系列都是从oncreate中引申出来的,下面讲讲onResume(),onPause()方法


####Cocos2dxActivity的onResume和onPause

  1. //Cocos2dxActivity的两个方法
  2. @Override
  3. protected void onResume() {//再一次进去
  4. super.onResume();
  5. Cocos2dxHelper.onResume();//Cocos2dxHelper.sCocos2dxAccelerometer.enable();
  6. this.mGLSurfaceView.onResume();//GLSurfaceView中resume一系列工作,具体看下列方法
  7. }
  8. @Override
  9. protected void onPause() {//启动Cocos2dxHelper.sCocos2dxAccelerometer.enable();
  10. super.onPause();
  11. Cocos2dxHelper.onPause();//暂停Cocos2dxHelper.sCocos2dxAccelerometer.disable();
  12. this.mGLSurfaceView.onPause();//GLSurfaceView中pause一系列工作,具体看下列方法
  13. }
//Cocos2dxGLSurfaceView的两个方法 @Override
  1. public void onResume() {
  2. super.onResume();
  3. this.setRenderMode(RENDERMODE_CONTINUOUSLY);//设置渲染模式,不停地渲染。默认是 RENDERMODE_CONTINUOUSLY
  4. this.queueEvent(new Runnable() {
  5. @Override
  6. public void run() {
  7. Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleOnResume();//处理Resume操作, Cocos2dxHelper.onEnterForeground();Cocos2dxRenderer.nativeOnResume();//c++中实现
  8. }
  9. });
  10. }
  11. @Override
  12. public void onPause() {
  13. this.queueEvent(new Runnable() {
  14. @Override
  15. public void run() {
  16. Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleOnPause();//处理暂停操作
  17. }
  18. });
  19. this.setRenderMode(RENDERMODE_WHEN_DIRTY);//设置渲染模式,根据需要来渲染,当运行requestRender()方法之后渲染
  20. //super.onPause();
  21. }

this.queueEvent方法是将一个线程放到ArrayList列表中,在GLThread线程中,会将ArrayList列表中的线程取出来运行,GLThread线程可以和GLSurfaceView渲染界面交互信息。Cocos2dxActivity中的runOnGLThread方法就是封装的queueEvent()方法。

上面一系列讲解了关于在android平台中,cocos2d-x是怎么开展工作的,其实也很简单。就是要创建一个GLSurfaceView,而GLSurfaceView的创建需要设置一些参数,比如setEGLConfigChooser(red ,green, blue, alpha, depth ,stencil),表示这个View,每一个渲染点的支持的位数,其次就是创建了GLSurfaceView了,那需要在view上面绘制东西啊,就需要Cocos2dxRenderer,他一直调用onDrawFrame方法,最终就有东西了。

本文其实没有讲到怎么跨平台,但是其实不同的平台,都差不多。都需要一个View,再在上面不停的绘制东西,而真正绘制的实现在平台不相关代码上。

青春是一场大雨,即使感冒了,还盼回头再淋一次...image...微笑永远是一个人身上最好看的东西...


PREVIOUS     NEXT