本文为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的做了啥事情
{
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;
}
public void init() {Cocos2dxActivity中this.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中
}
public Cocos2dxGLSurfaceView onCreateView() {Cocos2dxActivity中onCreateView()方法具体实现,创建GLSurfaceView
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.setFocusableInTouchMode(true);//设置GLSurfaceView可以获取触摸事件
@Override在上面的一系列方法中,我们已经创建了GLSurfaceView,但还需要通过Cocos2dxRenderer绘制东西到GLSurfaceView上面。Cocos2dxRenderer实现了GLSurfaceView.Renderer这个接口,具体方法如下:
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()这方法主要干了啥?
- 加载.so文件
- 初始化Cocos2dxHandler,弹出dialog做铺垫。
- 初始化Cocos2dxHelper中的各个参数
- 初始化AppDelegate
- 指定red ,green, blue, alpha, depth ,stencil 支持的位数,也就是initGLContextAttrs
- 创建Cocos2dxGLSurfaceView
- 创建Cocos2dxRenderer,当然还有onSurfaceCreated,onSurfaceChanged,onDrawFrame三个方法
- 设置渲染
以上的方法讲的一系列都是从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一系列工作,具体看下列方法
}
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,再在上面不停的绘制东西,而真正绘制的实现在平台不相关代码上。
青春是一场大雨,即使感冒了,还盼回头再淋一次......微笑永远是一个人身上最好看的东西...