cocos2d-x游戏开发(四)游戏主循环
前端之家收集整理的这篇文章主要介绍了
cocos2d-x游戏开发(四)游戏主循环,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
欢迎转载:http://blog.csdn.net/fylz1125/article/details/8518737
终于抽时间把这个游戏写完了。由于没有自拍神器,所以把它移植到了Android上,用我的戴妃跑的很欢啊。自此,我算是完成了一个功能比较完善的游戏了。
麻雀虽小,五脏俱全,该有的都有,不该有的估计也有,嘿嘿。这几天把写这个游戏的经历和学习过程整理一下,多写几篇博客,就当做记笔记了。
首先还是就我个人的理解,讲讲游戏引擎的处理流程。
其实游戏逻辑简单化就是一个死循环,如下:
-
- boolgame_is_running=true;
-
- while(game_is_running){
- update_game();
- display_game();
- }
我们所看到的游戏画面,游戏音乐,以及一些触控,输入等。在逻辑上就是这么一个死循环。这个循环一直在跑,期间会处理一些列的事件,简化之就是上面的两个函数。
cocos2d-x引擎也是如此,所有的逻辑都是在这个主循环下实现的。下面看看cocos2dx在各平台上的主循环实现。
1.Win
看它的main.cpp
#include"main.h"
- #include"../Classes/AppDelegate.h"
- #include"CCEGLView.h"
-
- USING_NS_CC;
- intAPIENTRY_tWinMain(HINSTANCEhInstance,
- HINSTANCEhPrevInstance,
- LPTSTRlpCmdLine,87); font-weight:bold; background-color:inherit">intnCmdShow)
- {
- UNREFERENCED_PARAMETER(hPrevInstance);
- UNREFERENCED_PARAMETER(lpCmdLine);
-
- AppDelegateapp;
- CCEGLView*eglView=CCEGLView::sharedOpenGLView();
- eglView->setFrameSize(2048,1536);
- //Theresolutionofipad3isverylarge.Ingeneral,PC'sresolutionissmallerthanit.
-
- eglView->setFrameZoomFactor(0.4f);
- returnCCApplication::sharedApplication()->run();
- }
前面都不要关心,只是用来传递OpenGL窗口的,关键是最后一句,CCApplication::sharedApplication()->run()。看这个run函数:
intCCApplication::run()
- {
- PVRFrameEnableControlWindow(false);
- //Mainmessageloop:
- MSGmsg;
- LARGE_INTEGERnFreq;
- LARGE_INTEGERnLast;
- LARGE_INTEGERnNow;
- QueryPerformanceFrequency(&nFreq);
- QueryPerformanceCounter(&nLast);
- //Initializeinstanceandcocos2d.
- if(!applicationDidFinishLaunching())
- return0;
- }
- CCEGLView*pMainWnd=CCEGLView::sharedOpenGLView();
- pMainWnd->centerWindow();
- ShowWindow(pMainWnd->getHWnd(),SW_SHOW);
- while(1)
- if(!PeekMessage(&msg,NULL,PM_REMOVE))
- //Getcurrenttimetick.
- QueryPerformanceCounter(&nNow);
- //Ifit'sthetimetodrawnextframe,drawit,elsesleepawhile.
- if(nNow.QuadPart-nLast.QuadPart>m_nAnimationInterval.QuadPart)
- nLast.QuadPart=nNow.QuadPart;
- CCDirector::sharedDirector()->mainLoop();
- else
- Sleep(0);
- continue;
- if(WM_QUIT==msg.message)
- //Quitmessageloop.
- break;
- //Dealwithwindowsmessage.
- if(!m_hAccelTable||!TranslateAccelerator(msg.hwnd,m_hAccelTable,&msg))
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return(int)msg.wParam;
- }
不熟悉windows的童鞋估计都知道windows是消息驱动的。这个死循环就是用来处理windows的消息循环的,在其中处理了FPS逻辑,消息分发等。注意看其中红色标标注的
CCDirector::sharedDirector()->mainLoop();
这是神马东西啊!这个就是cocos2d-x的主循环了,由导演负责维护。从此就进入了cocos2d-x的世界,跟windows没有一毛钱关系了。
2.Android
Android平台的游戏是从一个Activity开始的。(话说好像Android的所有应用都是从Activity开始的吧)。
在引擎源码下有个目录是android的java代码,是模板代码,几乎所有的游戏都用这个,不怎么变。不信可以你可以看
YourCocos2dxDir/cocos2dx/platform/android/java这个目录,就是创建android工程的时候会去这个目录拷贝java代码作为模板。
来看看HelloCpp的代码
packageorg.cocos2dx.hellocpp;
- importorg.cocos2dx.lib.Cocos2dxActivity;
- importandroid.os.Bundle;
- publicclassHelloCppextendsCocos2dxActivity{
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- static{
- System.loadLibrary("hellocpp");
- }
很简单,对吧。几行代码而已,这里说明了两个问题
1. Cocos2dxActivity才是核心的Activity。
2. 游戏的C++部分包括引擎部分,被编译成了动态链接库hellocpp。这里就是加载了hellocpp动态链接库。
这个动态链接库是在用NDK编译的时候生成的,就是libs/armeabi/libhellocpp.so。(扯远了)
还是来看看Cocos2dxActivity这个Activity。
publicabstractclassCocos2dxActivityextendsActivityimplementsCocos2dxHelperListener{
- //===========================================================
- //Constants
- privatestaticfinalStringTAG=Cocos2dxActivity.class.getSimpleName();
- //Fields
- privateCocos2dxGLSurfaceViewmGLSurfaceView;
- privateCocos2dxHandlermHandler;
- //===========================================================
- //Constructors
- @Override
- protectedvoidonCreate(finalBundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- this.mHandler=newCocos2dxHandler(this);
- this.init();
- Cocos2dxHelper.init(this,this);
- //Getter&Setter
- //Methodsfor/fromSuperClass/Interfaces
- @Override
- protectedvoidonResume(){
- super.onResume();
- Cocos2dxHelper.onResume();
- this.mGLSurfaceView.onResume();
- protectedvoidonPause(){
- super.onPause();
- Cocos2dxHelper.onPause();
- this.mGLSurfaceView.onPause();
- publicvoidshowDialog(finalStringpTitle,finalStringpMessage){
- Messagemsg=newMessage();
- msg.what=Cocos2dxHandler.HANDLER_SHOW_DIALOG;
- msg.obj=newCocos2dxHandler.DialogMessage(pTitle,pMessage);
- this.mHandler.sendMessage(msg);
- publicvoidshowEditTextDialog(finalStringpTitle,finalStringpContent,finalintpInputMode,finalintpInputFlag,finalintpReturnType,finalintpMaxLength){
- msg.what=Cocos2dxHandler.HANDLER_SHOW_EDITBox_DIALOG;
- msg.obj=newCocos2dxHandler.EditBoxMessage(pTitle,pContent,pInputMode,pInputFlag,pReturnType,pMaxLength);
- publicvoidrunOnGLThread(finalRunnablepRunnable){
- this.mGLSurfaceView.queueEvent(pRunnable);
- //Methods
- publicvoidinit(){
- //FrameLayout
- ViewGroup.LayoutParamsframelayout_params=
- newViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,153); list-style:decimal-leading-zero outside; color:inherit; line-height:20px; margin:0px!important; padding:0px 3px 0px 10px!important"> ViewGroup.LayoutParams.FILL_PARENT);
- FrameLayoutframelayout=newFrameLayout(this);
- framelayout.setLayoutParams(framelayout_params);
- //Cocos2dxEditTextlayout
- ViewGroup.LayoutParamsedittext_layout_params=
- newViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,248)"> ViewGroup.LayoutParams.WRAP_CONTENT);
- Cocos2dxEditTextedittext=newCocos2dxEditText(this);
- edittext.setLayoutParams(edittext_layout_params);
- //...addtoFrameLayout
- framelayout.addView(edittext);
- //Cocos2dxGLSurfaceView
- this.mGLSurfaceView=this.onCreateView();
- framelayout.addView(this.mGLSurfaceView);
- this.mGLSurfaceView.setCocos2dxRenderer(newCocos2dxRenderer());
- this.mGLSurfaceView.setCocos2dxEditText(edittext);
- //Setframelayoutasthecontentview
- setContentView(framelayout);
- publicCocos2dxGLSurfaceViewonCreateView(){
- returnnewCocos2dxGLSurfaceView(this);
- //InnerandAnonymousClasses
- }
代码很多,呵呵。其实核心就是那个mGLSurfaceView和它的渲染器new Cocos2dxRenderer()。在Android上,OpenGL的渲染是由一个GLSurfaceView和其渲染器Render组成。GLSurfaceView显示界面,Render渲染更新。这个Render其实是一个渲染线程,不停再跑,由框架层维护。这里不多讲。
来看这个Cocos2dxRenderer
packageorg.cocos2dx.lib;
- importjavax.microedition.khronos.egl.EGLConfig;
- importjavax.microedition.khronos.opengles.GL10;
- importandroid.opengl.GLSurfaceView;
- publicclassCocos2dxRendererimplementsGLSurfaceView.Renderer{
- //Constants
- privatefinalstaticlongNANOSECONDSPERSECOND=1000000000L;
- privatefinalstaticlongNANOSECONDSPERMICROSECOND=1000000;
- privatestaticlongsAnimationInterval=(long)(1.0/60*Cocos2dxRenderer.NANOSECONDSPERSECOND);
- privatelongmLastTickInNanoSeconds;
- privateintmScreenWidth;
- privateintmScreenHeight;
- //Constructors
- publicstaticvoidsetAnimationInterval(finaldoublepAnimationInterval){
- Cocos2dxRenderer.sAnimationInterval=(long)(pAnimationInterval*Cocos2dxRenderer.NANOSECONDSPERSECOND);
- publicvoidsetScreenWidthAndHeight(finalintpSurfaceWidth,finalintpSurfaceHeight){
- this.mScreenWidth=pSurfaceWidth;
- this.mScreenHeight=pSurfaceHeight;
- //Methodsfor/fromSuperClass/Interfaces
- @Override
- publicvoidonSurfaceCreated(finalGL10pGL10,finalEGLConfigpEGLConfig){
- Cocos2dxRenderer.nativeInit(this.mScreenWidth,this.mScreenHeight);
- this.mLastTickInNanoSeconds=System.nanoTime();
- publicvoidonSurfaceChanged(finalGL10pGL10,finalintpWidth,finalintpHeight){
- //③注意这里
- publicvoidonDrawFrame(finalGL10gl){
- /*
- *FPScontrollingalgorithmisnotaccurate,anditwillslowdownFPS
- *onsomedevices.SocommentFPScontrollingcode.
- */
- /*
- finallongnowInNanoSeconds=System.nanoTime();
- finallonginterval=nowInNanoSeconds-this.mLastTickInNanoSeconds;
- */
- //shouldrenderaframewhenonDrawFrame()iscalledorthereisa
- //"ghost"
- Cocos2dxRenderer.nativeRender();
- //fpscontrolling
- if(interval<Cocos2dxRenderer.sAnimationInterval){
- try{
- //becausewerenderitbefore,soweshouldsleeptwicetimeinterval
- Thread.sleep((Cocos2dxRenderer.sAnimationInterval-interval)/Cocos2dxRenderer.NANOSECONDSPERMICROSECOND);
- }catch(finalExceptione){
- }
- }
- this.mLastTickInNanoSeconds=nowInNanoSeconds;
- //Methods
- privatestaticnativevoidnativeTouchesBegin(finalintpID,finalfloatpX,finalfloatpY);
- privatestaticnativevoidnativeTouchesEnd(finalintpID,finalfloatpY);
- privatestaticnativevoidnativeTouchesMove(finalint[]pIDs,finalfloat[]pXs,finalfloat[]pYs);
- privatestaticnativevoidnativeTouchesCancel(finalint[]pIDs,finalfloat[]pYs);
- privatestaticnativebooleannativeKeyDown(finalintpKeyCode);
- privatestaticnativevoidnativeRender();
- privatestaticnativevoidnativeInit(finalintpWidth,finalintpHeight);
- privatestaticnativevoidnativeOnPause();
- privatestaticnativevoidnativeOnResume();
- publicvoidhandleActionDown(finalintpID,finalfloatpY){
- Cocos2dxRenderer.nativeTouchesBegin(pID,pX,pY);
- publicvoidhandleActionUp(finalintpID,153); list-style:decimal-leading-zero outside; color:inherit; line-height:20px; margin:0px!important; padding:0px 3px 0px 10px!important"> Cocos2dxRenderer.nativeTouchesEnd(pID,248)"> publicvoidhandleActionCancel(finalint[]pIDs,finalfloat[]pYs){
- Cocos2dxRenderer.nativeTouchesCancel(pIDs,pXs,pYs);
- publicvoidhandleActionMove(finalint[]pIDs,153); list-style:decimal-leading-zero outside; color:inherit; line-height:20px; margin:0px!important; padding:0px 3px 0px 10px!important"> Cocos2dxRenderer.nativeTouchesMove(pIDs,248)"> publicvoidhandleKeyDown(finalintpKeyCode){
- Cocos2dxRenderer.nativeKeyDown(pKeyCode);
- publicvoidhandleOnPause(){
- Cocos2dxRenderer.nativeOnPause();
- publicvoidhandleOnResume(){
- Cocos2dxRenderer.nativeOnResume();
- privatestaticnativevoidnativeInsertText(finalStringpText);
- privatestaticnativevoidnativeDeleteBackward();
- privatestaticnativeStringnativeGetContentText();
- publicvoidhandleInsertText(finalStringpText){
- Cocos2dxRenderer.nativeInsertText(pText);
- publicvoidhandleDeleteBackward(){
- Cocos2dxRenderer.nativeDeleteBackward();
- publicStringgetContentText(){
- returnCocos2dxRenderer.nativeGetContentText();
- }
代码很多,一副貌似很复杂的样子。其实脉络很清晰的,我们只看脉络,不考虑细节哈。我们顺藤摸瓜来...
首先要知道GLSurfaceView的渲染器必须实现GLSurfaceView.Renderer接口。就是上面的三个Override方法。
onSurfaceCreated在窗口建立的时候调用,onSurfaceChanged在窗口建立和大小变化是调用,onDrawFrame这个方法就跟普通View的Ondraw方法一样,窗口建立初始化完成后渲染线程不停的调这个方法。这些都是框架决定的,就是这个样子。下面分析下代码几处标记的地方:
看标记①,窗口建立,这个时候要进行初始化。这个时候它调用了一个native函数,就是标记②。看到这个函数形式是不是能想到什么呢,等下再说。
看标记③,前面说了,这个函数会被渲染线程不停调用(像不像主循环的死循环啊)。然后里面有个很牛擦的函数④。
这又是一个native的函数,呵呵。
native的代码是神马啊,就是C++啊。知之为知之,不知谷歌之。
既然是java调用C++,那就是jni调用了。
我们来看看jni/hellocpp/下的main.cpp
#include"AppDelegate.h"
- #include"platform/android/jni/JniHelper.h"
- #include<jni.h>
- #include<android/log.h>
- #include"HelloWorldScene.h"
- #defineLOG_TAG"main"
- #defineLOGD(...)__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
- usingnamespacecocos2d;
- extern"C"
- jintJNI_OnLoad(JavaVM*vm,void*reserved)
- JniHelper::setJavaVM(vm);
- returnJNI_VERSION_1_4;
- voidJava_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*env,jobjectthiz,jintw,jinth)
- if(!CCDirector::sharedDirector()->getOpenGLView())
- CCEGLView*view=CCEGLView::sharedOpenGLView();
- view->setFrameSize(w,h);
- CCLog("with%d,height%d",w,h);
- AppDelegate*pAppDelegate=newAppDelegate();
- CCApplication::sharedApplication()->run();
- else
- ccDrawInit();
- ccGLInvalidateStateCache();
- CCShaderCache::sharedShaderCache()->reloadDefaultShaders();
- CCTextureCache::reloadAllTextures();
- CCNotificationCenter::sharedNotificationCenter()->postNotification(EVNET_COME_TO_FOREGROUND,NULL);
- CCDirector::sharedDirector()->setGLDefaultValues();
- }
根据Jni的命名规则,那个标注②的nativeInit方法就是上面红色一长串(呵呵)。窗口建立起来后调用nativeInit方法,就是调用这个C++的实现。这里做了窗口的初始化处理。
看标注⑤,你以为这个run函数就进入主循环了么,呵呵
看这个run
<spanstyle="font-size:18px;">//Initializeinstanceandcocos2d.
- if(!applicationDidFinishLaunching())
- return0;
- return-1;
- }</span>
我们看到了神马!实质上就调了一下applicationDidFinishLaunching,别的什么也没干。所以这里没有进入主循环。
现在再看③和④。这个逻辑貌似就是主循环。
这个nativeRender()函数的实现在Yourcocos2dDir/cocos2dx/platform/android/jni/Java_org_cocos2dx_lib_Cocos2dxRenderer.cpp
#include"text_input_node/CCIMEDispatcher.h"
- #include"CCDirector.h"
- #include"../CCApplication.h"
- #include"platform/CCFileUtils.h"
- #include"CCEventType.h"
- #include"support/CCNotificationCenter.h"
- #include"JniHelper.h"
- #include<jni.h>
- usingnamespacecocos2d;
- extern"C"{
- JNIEXPORTvoidJNICALLJava_org_cocos2dx_lib_<spanstyle="color:#ff0000;">Cocos2dxRenderer_nativeRender</span>(JNIEnv*env){
- <spanstyle="color:#ff0000;">cocos2d::CCDirector::sharedDirector()->mainLoop();
- JNIEXPORTvoidJNICALLJava_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnPause(){
- CCApplication::sharedApplication()->applicationDidEnterBackground();
- CCNotificationCenter::sharedNotificationCenter()->postNotification(EVENT_COME_TO_BACKGROUND,NULL);
- JNIEXPORTvoidJNICALLJava_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnResume(){
- if(CCDirector::sharedDirector()->getOpenGLView()){
- CCApplication::sharedApplication()->applicationWillEnterForeground();
- JNIEXPORTvoidJNICALLJava_org_cocos2dx_lib_Cocos2dxRenderer_nativeInsertText(JNIEnv*env,jstringtext){
- constchar*pszText=env->GetStringUTFChars(text,NULL);
- cocos2d::CCIMEDispatcher::sharedDispatcher()->dispatchInsertText(pszText,strlen(pszText));
- env->ReleaseStringUTFChars(text,pszText);
- JNIEXPORTvoidJNICALLJava_org_cocos2dx_lib_Cocos2dxRenderer_nativeDeleteBackward(JNIEnv*env,jobjectthiz){
- cocos2d::CCIMEDispatcher::sharedDispatcher()->dispatchDeleteBackward();
- JNIEXPORTjstringJNICALLJava_org_cocos2dx_lib_Cocos2dxRenderer_nativeGetContentText(){
- JNIEnv*env=0;
- if(JniHelper::getJavaVM()->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK||!env){
- constchar*pszText=cocos2d::CCIMEDispatcher::sharedDispatcher()->getContentText();
- returnenv->NewStringUTF(pszText);
- }
看上面标注,找到导演了,导演又开始主循环了。真是众里寻他千百度,那人却在灯火阑珊处啊。
到这里可以发现,Android上的主循环跟win上的不太一样,它不是一个简单的while就完了。它是由java的渲染线程发起的,通过不断调用render来驱动。
3.iOs
ios上面和Android上类似。看AppController.mm
#import<UIKit/UIKit.h>
- #import"AppController.h"
- #import"cocos2d.h"
- #import"EAGLView.h"
- #import"AppDelegate.h"
- #import"RootViewController.h"
- @implementationAppController
- @synthesizewindow;
- @synthesizeviewController;
- #pragmamark-
- #pragmamarkApplicationlifecycle
- //cocos2dapplicationinstance
- staticAppDelegates_sharedApplication;
- -(BOOL)application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions{
- //Overridepointforcustomizationafterapplicationlaunch.
- //Addtheviewcontroller'sviewtothewindowanddisplay.
- window=[[UIWindowalloc]initWithFrame:[[UIScreenmainScreen]bounds]];
- EAGLView*__glView=[EAGLViewviewWithFrame:[windowbounds]
- pixelFormat:kEAGLColorFormatRGBA8
- depthFormat:GL_DEPTH_COMPONENT16
- preserveBackbuffer:NO
- sharegroup:nil
- multiSampling:NO
- numberOfSamples:0];
- //UseRootViewControllermanageEAGLView
- viewController=[[RootViewControlleralloc]initWithNibName:nilbundle:nil];
- viewController.wantsFullScreenLayout=YES;
- viewController.view=__glView;
- //SetRootViewControllertowindow
- if([[UIDevicecurrentDevice].systemVersionfloatValue]<6.0)
- //warning:addSubViewdoesn'tworkoniOS6
- [windowaddSubview:viewController.view];
- //usethismethodonios6
- [windowsetRootViewController:viewController];
- [windowmakeKeyAndVisible];
- [[UIApplicationsharedApplication]setStatusBarHidden:YES];
- <spanstyle="color:#ff0000;">cocos2d::CCApplication::sharedApplication()->run();</span>
- returnYES;
- -(void)applicationWillResignActive:(UIApplication*)application{
- Sentwhentheapplicationisabouttomovefromactivetoinactivestate.Thiscanoccurforcertaintypesoftemporaryinterruptions(suchasanincomingphonecallorSMSmessage)orwhentheuserquitstheapplicationanditbeginsthetransitiontothebackgroundstate.
- UsethismethodtopauSEOngoingtasks,disabletimers,andthrottledownOpenGLESframerates.Gamesshouldusethismethodtopausethegame.
- cocos2d::CCDirector::sharedDirector()->pause();
- -(void)applicationDidBecomeActive:(UIApplication*)application{
- Restartanytasksthatwerepaused(ornotyetstarted)whiletheapplicationwasinactive.IftheapplicationwasprevIoUslyinthebackground,optionallyrefreshtheuserinterface.
- cocos2d::CCDirector::sharedDirector()->resume();
- -(void)applicationDidEnterBackground:(UIApplication*)application{
- Usethismethodtoreleasesharedresources,saveuserdata,invalidatetimers,andstoreenoughapplicationstateinformationtorestoreyourapplicationtoitscurrentstateincaseitisterminatedlater.
- Ifyourapplicationsupportsbackgroundexecution,calledinsteadofapplicationWillTerminate:whentheuserquits.
- cocos2d::CCApplication::sharedApplication()->applicationDidEnterBackground();
- -(void)applicationWillEnterForeground:(UIApplication*)application{
- Calledaspartoftransitionfromthebackgroundtotheinactivestate:hereyoucanundomanyofthechangesmadeonenteringthebackground.
- cocos2d::CCApplication::sharedApplication()->applicationWillEnterForeground();
- -(void)applicationWillTerminate:(UIApplication*)application{
- Calledwhentheapplicationisabouttoterminate.
- SeealsoapplicationDidEnterBackground:.
- #pragmamark-
- #pragmamarkMemorymanagement
- -(void)applicationDidReceiveMemoryWarning:(UIApplication*)application{
- Freeupasmuchmemoryaspossiblebypurgingcacheddataobjectsthatcanberecreated(orreloadedfromdisk)later.
- cocos2d::CCDirector::sharedDirector()->purgeCachedData();
- -(void)dealloc{
- [superdealloc];
- @end
直接看标注,跟进run()
if(applicationDidFinishLaunching())
- <spanstyle="color:#ff0000;">[[CCDirectorCallersharedDirectorCaller]startMainLoop]</span>;
- }</span>
再跟标注的startMainLoop()
-(void)startMainLoop
- //CCDirector::setAnimationInterval()iscalled,weshouldinvalidateitfirst
- [displayLinkinvalidate];
- displayLink=nil;
- NSLog(@"runloop!");
- displayLink=[NSClassFromString(@"CADisplayLink")displayLinkWithTarget:selfselector:@selector(doCaller:)];
- [displayLinksetFrameInterval:self.interval];
- [displayLinkaddToRunLoop:[NSRunLoopcurrentRunLoop]forMode:NSDefaultRunLoopMode];
- }
好了,看红色标注。这个貌似循环不起来啊,呵呵。
仔细看他加载的这个类CADisplayLink,就是这个东西循环起来的。这其实就是个定时器,默认每秒运行60次,其有个属性可以设置FPS。看后面有个回调函数doCaller,跟进
-(void)doCaller:(id)sender
- cocos2d::CCDirector::sharedDirector()->mainLoop();
好了,终于又看到导演了。导演很忙,又开始主循环了。
一旦进入主循环,游戏就开始我们自己设计的游戏逻辑。
打字打的睡着了....不打了
原文链接:https://www.f2er.com/cocos2dx/342238.html