cocos2d-x遊戲開發之遊戲主循環

首先仍是就我我的的理解,講講遊戲引擎的處理流程。java

其實遊戲邏輯簡單化就是一個死循環,以下:node

1    
2 bool game_is_running = true; 3 
4     while( game_is_running ) { 5  update_game(); 6  display_game(); 7     }

咱們所看到的遊戲畫面,遊戲音樂,以及一些觸控,輸入等。在邏輯上就是這麼一個死循環。這個循環一直在跑,期間會處理一些列的事件,簡化之就是上面的兩個函數。linux

 

cocos2d-x引擎也是如此,全部的邏輯都是在這個主循環下實現的。下面看看cocos2dx在各平臺上的主循環實現。android

1.Winios

看它的main.cppwindows

 1 #include "main.h"
 2 #include "../Classes/AppDelegate.h"
 3 #include "CCEGLView.h"
 4 
 5 USING_NS_CC;  6 
 7 int APIENTRY _tWinMain(HINSTANCE hInstance,  8  HINSTANCE hPrevInstance,  9  LPTSTR lpCmdLine, 10                        int nCmdShow) 11 { 12  UNREFERENCED_PARAMETER(hPrevInstance); 13  UNREFERENCED_PARAMETER(lpCmdLine); 14 
15     // create the application instance
16  AppDelegate app; 17     CCEGLView* eglView = CCEGLView::sharedOpenGLView(); 18     eglView->setFrameSize(2048, 1536); 19     // The resolution of ipad3 is very large. In general, PC's resolution is smaller than it. 20     // So we need to invoke 'setFrameZoomFactor'(only valid on desktop(win32, mac, linux)) to make the window smaller.
21     eglView->setFrameZoomFactor(0.4f); 22     return CCApplication::sharedApplication()->run();// 注意這裏
23 }

前面都不要關心,只是用來傳遞OpenGL窗口的,關鍵是最後一句,CCApplication::sharedApplication()->run()。看這個run函數:app

 1 int CCApplication::run()  2 {  3     PVRFrameEnableControlWindow(false);  4 
 5     // Main message loop:
 6  MSG msg;  7  LARGE_INTEGER nFreq;  8  LARGE_INTEGER nLast;  9  LARGE_INTEGER nNow; 10 
11     QueryPerformanceFrequency(&nFreq); 12     QueryPerformanceCounter(&nLast); 13 
14     // Initialize instance and cocos2d.
15     if (!applicationDidFinishLaunching()) 16  { 17         return 0; 18  } 19 
20     CCEGLView* pMainWnd = CCEGLView::sharedOpenGLView(); 21     pMainWnd->centerWindow(); 22     ShowWindow(pMainWnd->getHWnd(), SW_SHOW); 23 
24     while (1)// 注意這裏,主循環來了
25  { 26         if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 27  { 28             // Get current time tick.
29             QueryPerformanceCounter(&nNow); 30 
31             // If it's the time to draw next frame, draw it, else sleep a while.
32             if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart) 33  { 34                 nLast.QuadPart = nNow.QuadPart; 35                 CCDirector::sharedDirector()->mainLoop(); //看看這是神馬
36  } 37             else
38  { 39                 Sleep(0); 40  } 41             continue; 42  } 43 
44         if (WM_QUIT == msg.message) 45  { 46             // Quit message loop.
47             break; 48  } 49 
50         // Deal with windows message.
51         if (! m_hAccelTable || ! TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg)) 52  { 53             TranslateMessage(&msg); 54             DispatchMessage(&msg); 55  } 56  } 57 
58     return (int) msg.wParam; 59 }

不熟悉windows的童鞋估計都知道windows是消息驅動的。這個死循環就是用來處理windows的消息循環的,在其中處理了FPS邏輯,消息分發等。注意看其中紅色標標註的框架

1 CCDirector::sharedDirector()->mainLoop();

這是神馬東西啊!這個就是cocos2d-x的主循環了,由導演負責維護。今後就進入了cocos2d-x的世界,跟windows沒有一毛錢關係了。ide

2.Android函數

Android平臺的遊戲是從一個Activity開始的。(話說好像Android的全部應用都是從Activity開始的吧)。

在引擎源碼下有個目錄是android的java代碼,是模板代碼,幾乎全部的遊戲都用這個,不怎麼變。不信能夠你能夠看

YourCocos2dxDir/cocos2dx/platform/android/java這個目錄,就是建立android工程的時候會去這個目錄拷貝java代碼做爲模板。

來看看HelloCpp的代碼

 1 package org.cocos2dx.hellocpp;  2 
 3 import org.cocos2dx.lib.Cocos2dxActivity;  4 
 5 import android.os.Bundle;  6 
 7 public class HelloCpp extends Cocos2dxActivity{  8 
 9     protected void onCreate(Bundle savedInstanceState){ 10  super.onCreate(savedInstanceState); 11  } 12     
13     static { 14          System.loadLibrary("hellocpp"); 15  } 16 }

很簡單,對吧。幾行代碼而已,這裏說明了兩個問題

1. Cocos2dxActivity纔是核心的Activity。

2. 遊戲的C++部分包括引擎部分,被編譯成了動態連接庫hellocpp。這裏就是加載了hellocpp動態連接庫。

這個動態連接庫是在用NDK編譯的時候生成的,就是libs/armeabi/libhellocpp.so。(扯遠了)

仍是來看看Cocos2dxActivity這個Activity。

 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(this, this);  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

 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

 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

 1 <span style="font-size:18px;">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

 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_<span style="color:#ff0000;">Cocos2dxRenderer_nativeRender</span>(JNIEnv* env) { 14         <span style="color:#ff0000;">cocos2d::CCDirector::sharedDirector()->mainLoop();//看到木有,這是什麼</span>
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來驅動。

3.iOs

ios上面和Android上相似。看AppController.mm

 1 #import <UIKit/UIKit.h>
 2 #import "AppController.h"
 3 #import "cocos2d.h"
 4 #import "EAGLView.h"
 5 #import "AppDelegate.h"
 6 
 7 #import "RootViewController.h"
 8 
 9 @implementation AppController  10 
 11 @synthesize window;  12 @synthesize viewController;  13 
 14 #pragma mark -
 15 #pragma mark Application lifecycle
 16 
 17 // cocos2d application instance
 18 static AppDelegate s_sharedApplication;  19 
 20 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  21 
 22     // Override point for customization after application launch.  23 
 24     // Add the view controller's view to the window and display.
 25     window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];  26     EAGLView *__glView = [EAGLView viewWithFrame: [window bounds]  27  pixelFormat: kEAGLColorFormatRGBA8  28  depthFormat: GL_DEPTH_COMPONENT16  29  preserveBackbuffer: NO  30  sharegroup: nil  31  multiSampling: NO  32                                  numberOfSamples:0 ];  33 
 34     // Use RootViewController manage EAGLView
 35     viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];  36     viewController.wantsFullScreenLayout = YES;  37     viewController.view = __glView;  38 
 39     // Set RootViewController to window
 40     if ( [[UIDevice currentDevice].systemVersion floatValue] < 6.0)  41  {  42         // warning: addSubView doesn't work on iOS6
 43  [window addSubview: viewController.view];  44  }  45     else
 46  {  47         // use this method on ios6
 48  [window setRootViewController:viewController];  49  }  50     
 51  [window makeKeyAndVisible];  52 
 53  [[UIApplication sharedApplication] setStatusBarHidden: YES];  54 
 55     
 56     <span style="color:#ff0000;">cocos2d::CCApplication::sharedApplication()->run();</span>//<span style="color:#ff0000;">看這裏</span>
 57     return YES;  58 }  59 
 60 
 61 - (void)applicationWillResignActive:(UIApplication *)application {  62     /*
 63  Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.  64  Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.  65      */
 66     cocos2d::CCDirector::sharedDirector()->pause();  67 }  68 
 69 - (void)applicationDidBecomeActive:(UIApplication *)application {  70     /*
 71  Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.  72      */
 73     cocos2d::CCDirector::sharedDirector()->resume();  74 }  75 
 76 - (void)applicationDidEnterBackground:(UIApplication *)application {  77     /*
 78  Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.  79  If your application supports background execution, called instead of applicationWillTerminate: when the user quits.  80      */
 81     cocos2d::CCApplication::sharedApplication()->applicationDidEnterBackground();  82 }  83 
 84 - (void)applicationWillEnterForeground:(UIApplication *)application {  85     /*
 86  Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background.  87      */
 88     cocos2d::CCApplication::sharedApplication()->applicationWillEnterForeground();  89 }  90 
 91 - (void)applicationWillTerminate:(UIApplication *)application {  92     /*
 93  Called when the application is about to terminate.  94  See also applicationDidEnterBackground:.  95      */
 96 }  97 
 98 
 99 #pragma mark -
100 #pragma mark Memory management
101 
102 - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { 103     /*
104  Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later. 105      */
106      cocos2d::CCDirector::sharedDirector()->purgeCachedData(); 107 } 108 
109 
110 - (void)dealloc { 111  [super dealloc]; 112 } 113 
114 
115 @end

直接看標註,跟進run()

1 <span style="font-size:18px;">int CCApplication::run() 2 { 3     if (applicationDidFinishLaunching()) 4  { 5         <span style="color:#ff0000;">[[CCDirectorCaller sharedDirectorCaller] startMainLoop]</span>; 6  } 7     return 0; 8 }</span>

再跟標註的startMainLoop()

 1 -(void) startMainLoop  2 {  3         // CCDirector::setAnimationInterval() is called, we should invalidate it first
 4  [displayLink invalidate];  5         displayLink = nil;  6         NSLog(@"run loop !");  7         displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(doCaller:)];//看這裏
 8  [displayLink setFrameInterval: self.interval];  9  [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 10 }

好了,看紅色標註。這個貌似循環不起來啊,呵呵。

仔細看他加載的這個類CADisplayLink,就是這個東西循環起來的。這其實就是個定時器,默認每秒運行60次,其有個屬性能夠設置FPS。看後面有個回調函數doCaller,跟進

1 -(void) doCaller: (id) sender 2 { 3     cocos2d::CCDirector::sharedDirector()->mainLoop();//看這裏
4 }

好了,終於又看到導演了。導演很忙,又開始主循環了。

一旦進入主循環,遊戲就開始咱們本身設計的遊戲邏輯。

 

原文鏈接:http://blog.csdn.net/dawn_moon/article/details/8518737

相關文章
相關標籤/搜索