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方法就是这个起点的入口。

Cocos2dxActivity的入口方法oncreate
protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    onLoadNativeLibraries();//这句话是去加载.so文件。主要代码是System.loadLibrary(libName)        
    sContext = this;
    this.mHandler = new Cocos2dxHandler(this);//初始化Cocos2dxHandler句柄,这个类做的主要工作是负责弹出Dialog
    
    Cocos2dxHelper.init(this);//初始化如包名,apk安装路径,音乐
    
    this.mGLContextAttrs = getGLContextAttrs();//getGLContextAttrs是一个Native方法,具体实现在C++部分,返回的是一个int数组,将返回的值设置到setEGLConfigChooser中,获取不同depth buffer的Surface
    this.init();//主要工作是创建一个GLSurfaceView,并且自定义设置这个Surface的每个channel的depth,同时给这个view设置渲染工具

    if (mVideoHelper == null) {
        mVideoHelper = new Cocos2dxVideoHelper(this, mFrameLayout);//把mFrameLayout赋值到Cocos2dxVideoHelper中,方便如果需要Video的时候添加到mFrameLayout中
    }
    
    if(mWebViewHelper == null){
        mWebViewHelper = new Cocos2dxWebViewHelper(mFrameLayout);
    }
}  >	Cocos2dxActivity中getGLContextAttrs的做了啥事情
private static native int[] getGLContextAttrs();//这就是natvie方法,下面就是具体实现 jintArray Java_org_cocos2dx_lib_Cocos2dxActivity_getGLContextAttrs(JNIEnv* env, jobject thiz)
{
	cocos_android_app_init(env, thiz);//这句话就是告诉c++们,准备好了啊,给我初始化AppDelegate,顺便提下这方法就在main.cpp中
	cocos2d::Application::getInstance()->initGLContextAttrs(); //初始化完了AppDelegate,就调用AppDelegate的initGLContextAttrs方法,同时将设置的值赋值给GLView中的_glContextAttrs
	GLContextAttrs _glContextAttrs = GLView::getGLContextAttrs();//获取上面的赋值

	int tmp[6] = {_glContextAttrs.redBits, _glContextAttrs.greenBits, _glContextAttrs.blueBits,
                       _glContextAttrs.alphaBits, _glContextAttrs.depthBits, _glContextAttrs.stencilBits};//把_glContextAttrs的值保存到int中,传递到java层


	jintArray glContextAttrsJava = env->NewIntArray(6);
    env->SetIntArrayRegion(glContextAttrsJava, 0, 6, tmp); 

	return glContextAttrsJava;
}
Cocos2dxActivity中this.init()方法,具体实现
public void init() {
    // FrameLayout
    ViewGroup.LayoutParams framelayout_params =
        new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                   ViewGroup.LayoutParams.MATCH_PARENT);
    mFrameLayout = new FrameLayout(this);//创建一个FrameLayout
    mFrameLayout.setLayoutParams(framelayout_params);

    // Cocos2dxEditText layout
    ViewGroup.LayoutParams edittext_layout_params =
        new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                   ViewGroup.LayoutParams.WRAP_CONTENT);
    Cocos2dxEditText edittext = new Cocos2dxEditText(this);
    edittext.setLayoutParams(edittext_layout_params);

    // ...add to FrameLayout
    mFrameLayout.addView(edittext);//将Cocos2dxEditText添加到FrameLayout

    // Cocos2dxGLSurfaceView
    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.

    // ...add to FrameLayout
    mFrameLayout.addView(this.mGLSurfaceView);//将Cocos2dxGLSurfaceView添加到mFrameLayout

    // Switch to supported OpenGL (ARGB888) mode on emulator
    if (isAndroidEmulator())//如果是模拟器,则重新设置
       this.mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);

    this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());//设置渲染,主要渲染工作就在Cocos2dxRenderer类中
    this.mGLSurfaceView.setCocos2dxEditText(edittext);

    // Set framelayout as the content view
    setContentView(mFrameLayout);//将FrameLayout添加到到View中
}
Cocos2dxActivity中onCreateView()方法具体实现,创建GLSurfaceView
public Cocos2dxGLSurfaceView onCreateView() {
    Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSurfaceView(this);//创建Cocos2dxGLSurfaceView
    //this line is need on some device if we specify an alpha bits
    if(this.mGLContextAttrs[3] > 0) //GLSurfaceView 缺省创建为RGB_565 颜色格式的Surface ,如果需要支持透明度,可以调用getHolder().setFormat(PixelFormat.TRANSLUCENT).
    
    glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);

    Cocos2dxEGLConfigChooser chooser = new Cocos2dxEGLConfigChooser(this.mGLContextAttrs);
    glSurfaceView.setEGLConfigChooser(chooser);//指定red ,green, blue, alpha, depth ,stencil 支持的位数,缺省为RGB_565 ,16 bit depth buffer.必须在setRenderer()方法之前设置

    return glSurfaceView;
}  >话说在创建Cocos2dxGLSurfaceView的时候,初始化主要做了啥工作呢?
this.setEGLContextClientVersion(2);//设置opengl es
    this.setFocusableInTouchMode(true);//设置GLSurfaceView可以获取触摸事件
在上面的一系列方法中,我们已经创建了GLSurfaceView,但还需要通过Cocos2dxRenderer绘制东西到GLSurfaceView上面。Cocos2dxRenderer实现了GLSurfaceView.Renderer这个接口,具体方法如下:
@Override
public void onSurfaceCreated(final GL10 GL10, final EGLConfig EGLConfig) {
    Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);//这个方法做了好多的工作,稍候具体详解
    this.mLastTickInNanoSeconds = System.nanoTime();
    mNativeInitCompleted = true;
}

@Override
public void onSurfaceChanged(final GL10 GL10, final int width, final int height) {
    Cocos2dxRenderer.nativeOnSurfaceChanged(width, height);//surface 的尺寸发生改变时该方法被调用
}

@Override
public void onDrawFrame(final GL10 gl) {
    /*
     * No need to use algorithm in default(60 FPS) situation,
     * since onDrawFrame() was called by system 60 times per second by default.
     */
    if (sAnimationInterval <= 1.0 / 60 * Cocos2dxRenderer.NANOSECONDSPERSECOND) {
        Cocos2dxRenderer.nativeRender();//渲染工作,会一直回调
    } else {
        final long now = System.nanoTime();
        final long interval = now - this.mLastTickInNanoSeconds;
    
        if (interval < Cocos2dxRenderer.sAnimationInterval) {
            try {
                Thread.sleep((Cocos2dxRenderer.sAnimationInterval - interval) / Cocos2dxRenderer.NANOSECONDSPERMICROSECOND);
            } catch (final Exception e) {
            }
        }
        /*
         * Render time MUST be counted in, or the FPS will slower than appointed.
        */
        this.mLastTickInNanoSeconds = System.nanoTime();
        Cocos2dxRenderer.nativeRender();
    }
}
当SurfaceView创建的时候,会去调用onSurfaceCreated,而我们关心的就是Cocos2dxRenderer.nativeInit这个方法
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)
{
	auto director = cocos2d::Director::getInstance();//实例化导演类
	auto glview = director->getOpenGLView();//获取glview
	if (!glview)
	{
    	glview = cocos2d::GLViewImpl::create("Android app");//GLViewImpl这个类是GLView的子类,在不同的平台有不同的实现
    	glview->setFrameSize(w, h);//设置屏幕大小
    	director->setOpenGLView(glview);//把glview赋值给导演类

    	//cocos_android_app_init(env, thiz);

    	cocos2d::Application::getInstance()->run();//这个方法其实主要就做了就是回调applicationDidFinishLaunching()这个方法,而这个方法其实对于我们开发者来说相当熟悉
	}
	else//重新初始化各参数
	{
    	cocos2d::GL::invalidateStateCache();
    	cocos2d::GLProgramCache::getInstance()->reloadDefaultGLPrograms();
    	cocos2d::DrawPrimitives::init();
    	cocos2d::VolatileTextureMgr::reloadAllTextures();

    	cocos2d::EventCustom recreatedEvent(EVENT_RENDERER_RECREATED);
    	director->getEventDispatcher()->dispatchEvent(&recreatedEvent);
    	director->setGLDefaultValues();
	}
} >	接下来就得说说onDrawFrame中的这方法Cocos2dxRenderer.nativeRender()


JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeRender(JNIEnv* env) 	{
    cocos2d::Director::getInstance()->mainLoop();//这方法肯定又是很熟悉,全都跑到Director上了,当然这方法的实现是DisplayLinkDirector这类上方法。每一次回调onDrawFrame,真正运行的就是mainLoop()方法。
} >	还是继续扯下mainLoop()方法


	void DisplayLinkDirector::mainLoop()
{
	if (_purgeDirectorInNextLoop)//这值默认都是false,只有运行了Director::end()才被设置为true,可见要结束游戏,真正的关键是这
	{
    	_purgeDirectorInNextLoop = false;
    	purgeDirector();//根据不同的平台运行GLViewImpl::end(),在android中调用的是terminateProcessJNI,而这个方法就是通过调用jni,回调java层实现的方法terminateProcess(),杀掉当前游戏的进程
	}
	else if (_restartDirectorInNextLoop)//当重新执行Director的时候_restartDirectorInNextLoop为true
	{
    	_restartDirectorInNextLoop = false;
    	restartDirector();
	}
	else if (! _invalid)//默认为false,当运行DisplayLinkDirector::stopAnimation()方法为true
	{
    	drawScene();//绘制场景了
 
    // release the objects
    	PoolManager::getInstance()->getCurrentPool()->clear();//释放AutoreleasePool
	}
}

好了,差不多也讲完主要流程了,现在总结下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

//Cocos2dxActivity的两个方法
 @Override
protected void onResume() {//再一次进去
    super.onResume();

    Cocos2dxHelper.onResume();//Cocos2dxHelper.sCocos2dxAccelerometer.enable();
    this.mGLSurfaceView.onResume();//GLSurfaceView中resume一系列工作,具体看下列方法
}

@Override
protected void onPause() {//启动Cocos2dxHelper.sCocos2dxAccelerometer.enable();
    super.onPause();
    
    Cocos2dxHelper.onPause();//暂停Cocos2dxHelper.sCocos2dxAccelerometer.disable();
    this.mGLSurfaceView.onPause();//GLSurfaceView中pause一系列工作,具体看下列方法
}
//Cocos2dxGLSurfaceView的两个方法 @Override
public void onResume() {
    super.onResume();
    this.setRenderMode(RENDERMODE_CONTINUOUSLY);//设置渲染模式,不停地渲染。默认是 RENDERMODE_CONTINUOUSLY
    this.queueEvent(new Runnable() {
        @Override
        public void run() {
            Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleOnResume();//处理Resume操作, Cocos2dxHelper.onEnterForeground();Cocos2dxRenderer.nativeOnResume();//c++中实现
        }
    });
}

@Override
public void onPause() {
    this.queueEvent(new Runnable() {
        @Override
        public void run() {
            Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleOnPause();//处理暂停操作
        }
    });
    this.setRenderMode(RENDERMODE_WHEN_DIRTY);//设置渲染模式,根据需要来渲染,当运行requestRender()方法之后渲染
    //super.onPause();
}

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