cocos2d-x游戏开发之游戏主循环

首先还是就我个人的理解,讲讲游戏引擎的处理流程。

其实游戏逻辑简单化就是一个死循环,如下:

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

我们所看到的游戏画面,游戏音乐,以及一些触控,输入等。在逻辑上就是这么一个死循环。这个循环一直在跑,期间会处理一些列的事件,简化之就是上面的两个函数。

cocos2d-x引擎也是如此,所有的逻辑都是在这个主循环下实现的。下面看看cocos2dx在各平台上的主循环实现。

1.Win

看它的main.cpp

 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函数:

 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没有一毛钱关系了。

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

时间: 2024-08-26 21:52:39

cocos2d-x游戏开发之游戏主循环的相关文章

Android游戏开发之游戏帧动画的播放与处理

带你走进游戏开发的世界之游戏帧动画的处理<ignore_js_op> 1.帧动画的原理 帧动画帧动画顾名思义,一帧一帧播放的动画就是帧动画. 帧动画和我们小时候看的动画片的原理是一样的,在相同区域快速切换图片给人们呈现一种视觉的假象感觉像是在播放动画,其实不过是N张图片在一帧一帧的切换罢了.            如图所示:人物行走动画的实现方式, 4帧行走动画在播放区域 一帧一帧向左切换播放 给人们一种播放动画的假象 ,图片就动了起来, 很简单吧,其它三方向播放动画的方法类似我就不再一一举例

JavaFX横幅类游戏开发 教训 游戏贴图

上一节课,我们即将完成战旗Demo有了一个大概的了解.教训这,我们将学习绘制游戏地图. 由于JavaFX 2.2中添加了Canvas相关的功能,我们就能够使用Canvas来实现游戏绘制了. 游戏地图绘制主要用到GraphicsContext.drawImage方法. drawImage(Image image,double sx,double sy,double sw,double sh,double dx,double dy,double dw,double dh); 当中image 表示源图

在线捉鬼游戏开发之一 - 游戏流程介绍与技术选用

看过芒果台某知名节目的朋友们应该对“谁是卧底”不会陌生:N人参与,N-1人拿到同一个词(如馒头),剩余一人拿到另一个词(如包子),N人都只能看到自己的词,故没人知道自己是否和别人描述的不一样.游戏采用轮流发言制,想尽办法描述自己手中的词,让自己不被怀疑,且又不能让真正的卧底猜出自己和别人不一样,直到猜出谁是卧底. 此类游戏的有趣之处在于描述的尺度要拿捏在明确且不点破之间,机器没有人的智慧那么发散,人的参与感就更重要了(不然好比我喜欢的飞行棋,你还真不知道网络对面的对手是不是条狗). 捉鬼 这个游

unity3f游戏开发之游戏设计中运营重用体系

游戏设计中,运用重用体系重用资源包括有以下几个设计目的: 1).方便玩家识别 为了方便玩家识别某一类游戏中的要素,而采用的设计目的.如某种某种动物的皮毛的道具图标.为了区分不同,除了基本图素相同外,不同之处只是以变换颜色和更改名称加以区分,这样可以方便玩家快速识别图标. 2).降低客户端的容量 游戏中最占用硬盘空间的,其实是大量的资源,如模型文件.贴图等美术资源文件.为了降低客户端的容量,开发者除了要采用压包技术进行资源压包外,在设计的过程中,设计师还要考虑到客户端容量大小的问题(特别是某些2D

unity3d游戏开发之 游戏贴图、模型基本规范(Q&amp;A)

一个游戏角色的好坏的贴图可以说起了70%的作用.对于面数比较低的角色而言游戏角色的大部分细节都是靠贴图来表现的. Q 游戏的贴图在尺寸上有些什么要求?是不是必须是正方形的? A 游戏贴图的长宽都必须是2的倍数的任意组合,例如2,4,8,16,32,64.....1024等.并不一定必须是正方形,例如长宽可以是256,128也可以是1024*32. Q 一个游戏角色是否只可以有一张贴图? A 不是.一个角色可以有好几张贴图,根据不同情况有不同要求.例如有些网络游戏,它的角色的上身,下身,手脚头的贴

csdn vip文章:Unity游戏开发-小游戏-非常简单的游戏-unity-

原文https://blog.csdn.net/qq_20484877/article/details/81841190 1*创建物体 Create菜单下 3D Object菜单下Cube 1.1设置属性x100   z100作为地面  1.2在创建一个立方体物体 1.3 Create菜单下 3D Object菜单下Cube 1.4复制立方体 创建一个空物体放立方体 代码 #pragma strict function Start () { } var speed : int =5; var s

[游戏开发-学习笔记]菜鸟慢慢飞(四)-Camera

游戏开发中,主相机应该是最重要的GameObject之一,毕竟游戏呈现给玩家,就是通过它. 相机的使用,在不同的游戏中,有很大的不同.这里总结一下自己学到的一些相关知识. 固定位置-游戏过程中相机的Transform属性不改变. 调整好位置后就不要动了,一般使用正交相机,即Camera-Projection选择Orthographic.Unity Manual-Camera 适用:2D游戏.比如飞机大战,消消乐. 游戏开始后,相机追踪某一物体,然后固定不动. 游戏开始后,我们才能确定追踪物体的位

Android游戏开发设计步骤

如今搭载Android操作系统的手机数量比iPhone多得多.据悉,Android设备平均每天激活40万台.但iOS对开发商来说依旧是个更加有利可图.更受欢迎的平台.原因是:Android无需花钱买应用:众多设备和应用商店使得Android市场呈分散状态.那么怎么去有效的设计Android游戏开发呢,专业的IT培训扣丁学堂为你解答: 1 手机游戏开发简介 游戏的本质就是在屏幕上不断地显示和更新图片,只不过不是胡乱地更新,而是根据程序逻辑来控制.一款完整的游戏需要多方面的知识,比如游戏的创意.背景

最大的幻术-游戏开发-到底是先学游戏引擎还是先学游戏编程

学习游戏的目的 我们学习游戏制作,游戏开发,游戏编程,游戏XX,我们的目的只有一个,打造一个非常牛逼,非常屌,非常让人开心的虚拟体验.我们用自己的学识让玩家在虚拟世界征战,生活,一步一步的让玩家幸福!那么我们的目的只有一个,让玩家知道自己的幸福在哪里,并且学会追求自己的幸福.当然,每个人对幸福的定义不一样.那么,我们只好让玩家来体验我们所来表达的最通俗的,最普遍的幸福体验,然后慢慢引导玩家去寻找自己的幸福体验.可能,在最后玩家都会离开游戏,离开虚拟世界,(对,这是真的,玩家需要一步一步达到定点,