cocos2d-x 游戏引擎的处理流程 MainLoop主循环(下)

来源:互联网 发布:淘宝三阶魔方 编辑:程序博客网 时间:2024/03/29 14:58

http://blog.163.com/shiyanchunyee@126/blog/static/12667909820131191434362/

3.Android

Android平台的游戏是从一个Activity开始的。(话说好像Android的所有应用都是从Activity开始的吧)。

在引擎源码下有个目录是android的java代码,是模板代码,几乎所有的游戏都用这个,不怎么变。不信可以你可以看

YourCocos2dxDir/cocos2dx/platform/android/java这个目录,就是创建android工程的时候会去这个目录拷贝java代码作为模板。

来看看HelloCpp的代码

[java] view plaincopy
  1. package org.cocos2dx.hellocpp;  
  2. import org.cocos2dx.lib.Cocos2dxActivity;  
  3. import android.os.Bundle;  
  4. public class HelloCpp extends Cocos2dxActivity{  
  5.     protected void onCreate(Bundle savedInstanceState){  
  6.         super.onCreate(savedInstanceState);  
  7.     }  
  8.     static {  
  9.          System.loadLibrary("hellocpp");  
  10.     }  
  11. }  
很简单,对吧。几行代码而已,这里说明了两个问题

1. Cocos2dxActivity才是核心的Activity。

2. 游戏的C++部分包括引擎部分,被编译成了动态链接库hellocpp。这里就是加载了hellocpp动态链接库。

这个动态链接库是在用NDK编译的时候生成的,就是libs/armeabi/libhellocpp.so。(扯远了)


还是来看看Cocos2dxActivity这个Activity。

[java] view plaincopy
  1. public abstract class Cocos2dxActivity extends Activity implements Cocos2dxHelperListener {  
  2.     // ===========================================================  
  3.     // Constants  
  4.     // ===========================================================  
  5.  
  6.     private static final String TAG = Cocos2dxActivity.class.getSimpleName();  
  7.   
  8.     // ===========================================================  
  9.     // Fields  
  10.     // ===========================================================  
  11.       
  12.     private Cocos2dxGLSurfaceView mGLSurfaceView;//注意这个SurfaceView  
  13.     private Cocos2dxHandler mHandler;  
  14.   
  15.     // ===========================================================  
  16.     // Constructors  
  17.     // ===========================================================  
  18.   
  19.     @Override  
  20.     protected void onCreate(final Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.           
  23.         this.mHandler = new Cocos2dxHandler(this);  
  24.   
  25.         this.init();  
  26.   
  27.         Cocos2dxHelper.init(thisthis);  
  28.     }  
  29.   
  30.     // ===========================================================  
  31.     // Getter & Setter  
  32.     // ===========================================================  
  33.   
  34.     // ===========================================================  
  35.     // Methods for/from SuperClass/Interfaces  
  36.     // ===========================================================  
  37.   
  38.     @Override  
  39.     protected void onResume() {  
  40.         super.onResume();  
  41.   
  42.         Cocos2dxHelper.onResume();  
  43.         this.mGLSurfaceView.onResume();  
  44.     }  
  45.   
  46.     @Override  
  47.     protected void onPause() {  
  48.         super.onPause();  
  49.   
  50.         Cocos2dxHelper.onPause();  
  51.         this.mGLSurfaceView.onPause();  
  52.     }  
  53.   
  54.     @Override  
  55.     public void showDialog(final String pTitle, final String pMessage) {  
  56.         Message msg = new Message();  
  57.         msg.what = Cocos2dxHandler.HANDLER_SHOW_DIALOG;  
  58.         msg.obj = new Cocos2dxHandler.DialogMessage(pTitle, pMessage);  
  59.         this.mHandler.sendMessage(msg);  
  60.     }  
  61.   
  62.     @Override  
  63.     public void showEditTextDialog(final String pTitle, final String pContent, final int pInputMode, final int pInputFlag, final int pReturnType, final int pMaxLength) {   
  64.         Message msg = new Message();  
  65.         msg.what = Cocos2dxHandler.HANDLER_SHOW_EDITBOX_DIALOG;  
  66.         msg.obj = new Cocos2dxHandler.EditBoxMessage(pTitle, pContent, pInputMode, pInputFlag, pReturnType, pMaxLength);  
  67.         this.mHandler.sendMessage(msg);  
  68.     }  
  69.       
  70.     @Override  
  71.     public void runOnGLThread(final Runnable pRunnable) {  
  72.         this.mGLSurfaceView.queueEvent(pRunnable);  
  73.     }  
  74.   
  75.     // ===========================================================  
  76.     // Methods  
  77.     // ===========================================================  
  78.     public void init() {  
  79.           
  80.         // FrameLayout  
  81.         ViewGroup.LayoutParams framelayout_params =  
  82.             new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,  
  83.                                        ViewGroup.LayoutParams.FILL_PARENT);  
  84.         FrameLayout framelayout = new FrameLayout(this); // 帧布局,可一层一层覆盖  
  85.         framelayout.setLayoutParams(framelayout_params);  
  86.   
  87.         // Cocos2dxEditText layout  
  88.         ViewGroup.LayoutParams edittext_layout_params =  
  89.             new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,  
  90.                                        ViewGroup.LayoutParams.WRAP_CONTENT);  
  91.         Cocos2dxEditText edittext = new Cocos2dxEditText(this);  
  92.         edittext.setLayoutParams(edittext_layout_params);  
  93.   
  94.         // ...add to FrameLayout  
  95.         framelayout.addView(edittext);  
  96.   
  97.         // Cocos2dxGLSurfaceView  
  98.         this.mGLSurfaceView = this.onCreateView();  
  99.   
  100.         // ...add to FrameLayout  
  101.         framelayout.addView(this.mGLSurfaceView);// 添加GLSurfaceView  
  102.   
  103.         this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());//注意这行,一个渲染器  
  104.         this.mGLSurfaceView.setCocos2dxEditText(edittext);  
  105.   
  106.         // Set framelayout as the content view  
  107.         setContentView(framelayout);  
  108.     }  
  109.       
  110.     public Cocos2dxGLSurfaceView onCreateView() {  
  111.         return new Cocos2dxGLSurfaceView(this);  
  112.     }  
  113.   
  114.     // ===========================================================  
  115.     // Inner and Anonymous Classes  
  116.     // ===========================================================  
  117. }  
代码很多,呵呵。其实核心就是那个mGLSurfaceView和它的渲染器new Cocos2dxRenderer()。在Android上,OpenGL的渲染是由一个GLSurfaceView和其渲染器Render组成。GLSurfaceView显示界面,Render渲染更新。这个Render其实是一个渲染线程,不停再跑,由框架层维护。这里不多讲。

来看这个Cocos2dxRenderer

[java] view plaincopy
  1. package org.cocos2dx.lib;  
  2.   
  3. import javax.microedition.khronos.egl.EGLConfig;  
  4. import javax.microedition.khronos.opengles.GL10;  
  5.   
  6. import android.opengl.GLSurfaceView;  
  7.   
  8. public class Cocos2dxRenderer implements GLSurfaceView.Renderer {  
  9.     // ===========================================================  
  10.     // Constants  
  11.     // ===========================================================  
  12.   
  13.     private final static long NANOSECONDSPERSECOND = 1000000000L;  
  14.     private final static long NANOSECONDSPERMICROSECOND = 1000000;  
  15.   
  16.     private static long sAnimationInterval = (long) (1.0 / 60 * Cocos2dxRenderer.NANOSECONDSPERSECOND);  
  17.   
  18.     // ===========================================================  
  19.     // Fields  
  20.     // ===========================================================  
  21.   
  22.     private long mLastTickInNanoSeconds;  
  23.     private int mScreenWidth;  
  24.     private int mScreenHeight;  
  25.   
  26.     // ===========================================================  
  27.     // Constructors  
  28.     // ===========================================================  
  29.   
  30.     // ===========================================================  
  31.     // Getter & Setter  
  32.     // ===========================================================  
  33.   
  34.     public static void setAnimationInterval(final double pAnimationInterval) {  
  35.         Cocos2dxRenderer.sAnimationInterval = (long) (pAnimationInterval * Cocos2dxRenderer.NANOSECONDSPERSECOND);  
  36.     }  
  37.   
  38.     public void setScreenWidthAndHeight(final int pSurfaceWidth, final int pSurfaceHeight) {  
  39.         this.mScreenWidth = pSurfaceWidth;  
  40.         this.mScreenHeight = pSurfaceHeight;  
  41.     }  
  42.   
  43.     // ===========================================================  
  44.     // Methods for/from SuperClass/Interfaces  
  45.     // ===========================================================  
  46.   
  47.     @Override //注意这里  
  48.     public void onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig) {  
  49.         Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);//初始化窗口  
  50.         this.mLastTickInNanoSeconds = System.nanoTime();  
  51.     }  
  52.   
  53.     @Override  
  54.     public void onSurfaceChanged(final GL10 pGL10, final int pWidth, final int pHeight) {  
  55.     }  
  56.   
  57.     @Override //注意这里  
  58.     public void onDrawFrame(final GL10 gl) {  
  59.         /* 
  60.          * FPS controlling algorithm is not accurate, and it will slow down FPS 
  61.          * on some devices. So comment FPS controlling code. 
  62.          */  
  63.           
  64.         /* 
  65.         final long nowInNanoSeconds = System.nanoTime(); 
  66.         final long interval = nowInNanoSeconds - this.mLastTickInNanoSeconds; 
  67.         */  
  68.   
  69.         // should render a frame when onDrawFrame() is called or there is a  
  70.         // "ghost"  
  71.         Cocos2dxRenderer.nativeRender();//特别注意这个  
  72.         /* 
  73.         // fps controlling 
  74.         if (interval < Cocos2dxRenderer.sAnimationInterval) { 
  75.             try { 
  76.                 // because we render it before, so we should sleep twice time interval 
  77.                 Thread.sleep((Cocos2dxRenderer.sAnimationInterval - interval) / Cocos2dxRenderer.NANOSECONDSPERMICROSECOND); 
  78.             } catch (final Exception e) { 
  79.             } 
  80.         } 
  81.  
  82.         this.mLastTickInNanoSeconds = nowInNanoSeconds; 
  83.         */  
  84.     }  
  85.   
  86.     // ===========================================================  
  87.     // Methods  
  88.     // ===========================================================  
  89.   
  90.     private static native void nativeTouchesBegin(final int pID, final float pX, final float pY);  
  91.     private static native void nativeTouchesEnd(final int pID, final float pX, final float pY);  
  92.     private static native void nativeTouchesMove(final int[] pIDs, final float[] pXs, final float[] pYs);  
  93.     private static native void nativeTouchesCancel(final int[] pIDs, final float[] pXs, final float[] pYs);  
  94.     private static native boolean nativeKeyDown(final int pKeyCode);  
  95.     private static native void nativeRender();  
  96.     private static native void nativeInit(final int pWidth, final int pHeight);  
  97.     private static native void nativeOnPause();  
  98.     private static native void nativeOnResume();  
  99.   
  100.     public void handleActionDown(final int pID, final float pX, final float pY) {  
  101.         Cocos2dxRenderer.nativeTouchesBegin(pID, pX, pY);  
  102.     }  
  103.   
  104.     public void handleActionUp(final int pID, final float pX, final float pY) {  
  105.         Cocos2dxRenderer.nativeTouchesEnd(pID, pX, pY);  
  106.     }  
  107.   
  108.     public void handleActionCancel(final int[] pIDs, final float[] pXs, final float[] pYs) {  
  109.         Cocos2dxRenderer.nativeTouchesCancel(pIDs, pXs, pYs);  
  110.     }  
  111.   
  112.     public void handleActionMove(final int[] pIDs, final float[] pXs, final float[] pYs) {  
  113.         Cocos2dxRenderer.nativeTouchesMove(pIDs, pXs, pYs);  
  114.     }  
  115.   
  116.     public void handleKeyDown(final int pKeyCode) {  
  117.         Cocos2dxRenderer.nativeKeyDown(pKeyCode);  
  118.     }  
  119.   
  120.     public void handleOnPause() {  
  121.         Cocos2dxRenderer.nativeOnPause();  
  122.     }  
  123.   
  124.     public void handleOnResume() {  
  125.         Cocos2dxRenderer.nativeOnResume();  
  126.     }  
  127.   
  128.     private static native void nativeInsertText(final String pText);  
  129.     private static native void nativeDeleteBackward();  
  130.     private static native String nativeGetContentText();  
  131.   
  132.     public void handleInsertText(final String pText) {  
  133.         Cocos2dxRenderer.nativeInsertText(pText);  
  134.     }  
  135.   
  136.     public void handleDeleteBackward() {  
  137.         Cocos2dxRenderer.nativeDeleteBackward();  
  138.     }  
  139.   
  140.     public String getContentText() {  
  141.         return Cocos2dxRenderer.nativeGetContentText();  
  142.     }  
  143.   
  144.     // ===========================================================  
  145.     // Inner and Anonymous Classes  
  146.     // ===========================================================  
  147. }  

代码很多,一副貌似很复杂的样子。其实脉络很清晰的,我们只看脉络,不考虑细节哈。我们顺藤摸瓜来...

首先要知道GLSurfaceView的渲染器必须实现GLSurfaceView.Renderer接口。就是上面的三个Override方法。

onSurfaceCreated在窗口建立的时候调用,onSurfaceChanged在窗口建立和大小变化是调用,onDrawFrame这个方法就跟普通View的Ondraw方法一样,窗口建立初始化完成后渲染线程不停的调这个方法。这些都是框架决定的,就是这个样子。下面分析下代码几处标记的地方:

看标记,窗口建立,这个时候要进行初始化。这个时候它调用了一个native函数,就是标记。看到这个函数形式是不是能想到什么呢,等下再说。

看标记,前面说了,这个函数会被渲染线程不停调用(像不像主循环的死循环啊)。然后里面有个很牛擦的函数

这又是一个native的函数,呵呵。

native的代码是神马啊,就是C++啊。知之为知之,不知谷歌之。

既然是java调用C++,那就是jni调用了。

我们来看看jni/hellocpp/下的main.cpp

[cpp] view plaincopy
  1. #include "AppDelegate.h"  
  2. #include "platform/android/jni/JniHelper.h"  
  3. #include <jni.h>  
  4. #include <android/log.h>  
  5.   
  6. #include "HelloWorldScene.h"  
  7.   
  8. #define  LOG_TAG    "main"  
  9. #define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)  
  10.   
  11. using namespace cocos2d;  
  12.   
  13. extern "C"  
  14. {  
  15.   
  16. jint JNI_OnLoad(JavaVM *vm, void *reserved)  
  17. {  
  18.     JniHelper::setJavaVM(vm);  
  19.   
  20.     return JNI_VERSION_1_4;  
  21. }  
  22.   
  23. void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)  
  24. {  
  25.     if (!CCDirector::sharedDirector()->getOpenGLView())  
  26.     {  
  27.         CCEGLView *view = CCEGLView::sharedOpenGLView();  
  28.         view->setFrameSize(w, h);  
  29.         CCLog("with %d,height %d",w,h);  
  30.   
  31.         AppDelegate *pAppDelegate = new AppDelegate();  
  32.         CCApplication::sharedApplication()->run(); // 看这里  
  33.     }  
  34.     else  
  35.     {  
  36.         ccDrawInit();  
  37.         ccGLInvalidateStateCache();  
  38.           
  39.         CCShaderCache::sharedShaderCache()->reloadDefaultShaders();  
  40.         CCTextureCache::reloadAllTextures();  
  41.         CCNotificationCenter::sharedNotificationCenter()->postNotification(EVNET_COME_TO_FOREGROUND, NULL);  
  42.         CCDirector::sharedDirector()->setGLDefaultValues();   
  43.     }  
  44. }  
  45.   
  46. }  
根据Jni的命名规则,那个标注的nativeInit方法就是上面红色一长串(呵呵)。窗口建立起来后调用nativeInit方法,就是调用这个C++的实现。这里做了窗口的初始化处理。

看标注,你以为这个run函数就进入主循环了么,呵呵

看这个run

[cpp] view plaincopy
  1. int CCApplication::run()  
  2. {  
  3.     // Initialize instance and cocos2d.  
  4.     if (! applicationDidFinishLaunching())  
  5.     {  
  6.         return 0;  
  7.     }  
  8.       
  9.     return -1;  
  10. }</span>  

我们看到了神马!实质上就调了一下applicationDidFinishLaunching,别的什么也没干。所以这里没有进入主循环。

现在再看。这个逻辑貌似就是主循环。

这个nativeRender()函数的实现在Yourcocos2dDir/cocos2dx/platform/android/jni/Java_org_cocos2dx_lib_Cocos2dxRenderer.cpp

[cpp] view plaincopy
  1. #include "text_input_node/CCIMEDispatcher.h"  
  2. #include "CCDirector.h"  
  3. #include "../CCApplication.h"  
  4. #include "platform/CCFileUtils.h"  
  5. #include "CCEventType.h"  
  6. #include "support/CCNotificationCenter.h"  
  7. #include "JniHelper.h"  
  8. #include <jni.h>  
  9.   
  10. using namespace cocos2d;  
  11.   
  12. extern "C" {  
  13.     JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeRender(JNIEnv* env) {  
  14.         cocos2d::CCDirector::sharedDirector()->mainLoop();//看到木有,这是什么 
  15.     }  
  16.   
  17.     JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnPause() {  
  18.         CCApplication::sharedApplication()->applicationDidEnterBackground();  
  19.   
  20.         CCNotificationCenter::sharedNotificationCenter()->postNotification(EVENT_COME_TO_BACKGROUND, NULL);  
  21.     }  
  22.   
  23.     JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnResume() {  
  24.         if (CCDirector::sharedDirector()->getOpenGLView()) {  
  25.             CCApplication::sharedApplication()->applicationWillEnterForeground();  
  26.         }  
  27.     }  
  28.   
  29.     JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInsertText(JNIEnv* env, jobject thiz, jstring text) {  
  30.         const char* pszText = env->GetStringUTFChars(text, NULL);  
  31.         cocos2d::CCIMEDispatcher::sharedDispatcher()->dispatchInsertText(pszText, strlen(pszText));  
  32.         env->ReleaseStringUTFChars(text, pszText);  
  33.     }  
  34.   
  35.     JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeDeleteBackward(JNIEnv* env, jobject thiz) {  
  36.         cocos2d::CCIMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();  
  37.     }  
  38.   
  39.     JNIEXPORT jstring JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeGetContentText() {  
  40.         JNIEnv * env = 0;  
  41.   
  42.         if (JniHelper::getJavaVM()->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK || ! env) {  
  43.             return 0;  
  44.         }  
  45.         const char * pszText = cocos2d::CCIMEDispatcher::sharedDispatcher()->getContentText();  
  46.         return env->NewStringUTF(pszText);  
  47.     }  
  48. }  
看上面标注,找到导演了,导演又开始主循环了。真是众里寻他千百度,那人却在灯火阑珊处啊。

到这里可以发现,Android上的主循环跟win上的不太一样,它不是一个简单的while就完了。它是由java的渲染线程发起的,通过不断调用render来驱动。

0 0
原创粉丝点击