首先仍是就我我的的理解,講講遊戲引擎的處理流程。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