《Cocos2D权威指南》——1.4 深入学习HelloCocos2D项目

1.4 深入学习HelloCocos2D项目

在完成了第一个HelloCocos2D项目后,如果读者不仅想看到飞机在屏幕上飞行,还想知道这一切是怎样实现的,我们不妨来一起探究其中的每一行代码。
1.4.1 初识场景和节点
要想理解HelloCocos2D这个项目,首先要了解场景(CCScene)、层(CCLayer)和节点(CCNode)的概念。
Cocos2D游戏是由不同的场景构成的,由导演(CCDirector)负责运行和切换各个场景。在Cocos2D中,CCDirector在任何一个时间点上只能运行一个场景。
所有节点的父类都是CCNode类,它包含了位置信息,但没有显示信息。它是所有其他节点类的父类,包括两个最基本的类:CCScene和CCLayer。
CCScene是一个抽象的概念,功能是根据像素坐标把物体放置在场景里相应的地方。所以任何Cocos2D场景都会用一个CCScene作为父对象。
CCLayer类本身并不做什么,它的功能是允许触摸和加速计的输入。因为大多数游戏会接受基本的触摸输入,所以CCLayer通常是第一个被加入CCScene的类。
Cocos2D的每个场景都包含一个或多个层,彼此叠加。
举例来说,通常我们刚进入游戏的时候都会看到一个初始菜单,接下来会进入游戏的主画面来战斗或完成任务,然后很快会因为种种原因看到GAMEOVER这个经典永恒的画面。而在不同的场景之中,可能会有很多的层(就像Photoshop的图层一样),每个层里又包含了很多Nodes(子节点,比如精灵、标签、菜单等),每个子节点也可能有其他的节点(比如一个精灵的里面可以存在一个子精灵)。
请记住,当需要在屏幕中添加飞机精灵的时候,要先创建一个新的精灵对象,然后把它添加成该层的子节点。
1.4.2 实现代码分析
现在逐步分析1.3节的代码是如何实现的。
1 . 主程序入口main.m
万物皆有起始,程序的运行也是。毫无疑问,任何一个使用Xcode开发的应用或游戏都是从main.m开始执行的。本例中的main.m在左侧的Supporting Files文件夹下,如图1-20所示。

main.m中的代码如代码清单1-3所示。
代码清单1-3 main.m中的代码

#import <UIKit/UIKit.h>

int main(int argc, char *argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, @"AppController");
    [pool release];
    return retVal;
}

简单来说,主函数创建了一个NSAutoreleasePool(自动释放池),然后调用UIApplicationMain启动程序,该程序使用AppController类来执行UIApplicationDelegate的协议(protocol)。
上述代码使用了NSAutoreleasePool来管理内存。也就是说,通过给对象发送Autorelease(自动释放)消息,就不再需要担心忘记发送release消息。Autorelease Pool(自动释放池)可以确保内存中的自动释放对象最终会被释放。
注意 main.m文件的内容对于任何iOS应用或游戏都是一样的,无须对此做任何的修改。如果你看不懂这个文件,建议学习iPhone或者Objective-C开发的基础教程。
简而言之,程序启动了,接下来会调用AppController类。
在此之前,可以先看Supporting Files下的另一个文件Prefix.pch,这个头文件的作用是给编译过程加速。我们应该把不常变化的框架(Frameworks)头文件添加到前缀头文件(Prefix Header)中。这样,在编译的时候,框架的代码会被预先编译,所有的类都将可以使用这些头文件。
不过,这样做也有一个缺点:如果前缀头文件中一个头文件发生了变化,项目中的所有代码都将会重新编译。这就是为什么应该只添加那些极少或者从来都不变化的头文件到前缀头文件中。
我们可以将cocos2d.h头文件添加到前缀头文件中,因为它很少改变。不过,只有复杂一些的项目才会感受到编译速度的变化。
如果大家想了解更多关于如何使用前缀头文件减少编译时间的知识,可以参考苹果开发者文档。
2 . AppDelegate
每个iOS程序都有一个AppDelegate类,用于实现UIApplicationDelegate协议。AppDelegate在某些时间点通过从iOS接收信息来跟踪程序的状态变化。例如,可以用它确认是否有打进来的电话或者系统内存是否已经不足。在查看以上方法的具体实现代码前,先要了解AppDelegate.h中的类定义。在AppDelegate.h中定义了AppController这个类,它直接继承自NSObject,且遵循UIApplicationDelegate和CCDirectorDelegate两个协议。
程序开始运行后,收到的第一个消息就是applicationDidFinishLaunchingWithOptions,在这个方法中,可以放置项目的启动代码。Cocos2D就是在这里初始化的。
在Xcode中打开AppDelegate.m文件,让我们来详细查看并解释其中的代码细节。
先说一下在Xcode4中切换方法的技巧,如图1-21所示。单击最右侧的“No Selection”处,就可以在不同方法间跳转。这跟Xcode3.2.6是不同的,用起来一样方便。

现在切换到applicationDidFinishLaunchingWithOptions方法,如代码清单1-4所示。
代码清单1-4 applicationDidFinishLaunchingWithOptions方法

- (BOOL) application:(UIApplication)application didFinishLaunchingWithOptions:(NSDictionary )launchOptions
{
   // 1.Create the main window
   window_ = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
   //2.Create an CCGLView with a RGB565 color buffer, and a depth buffer of 0-bits
      CCGLView *glView = [CCGLView viewWithFrame:[window_ bounds]
         pixelFormat:kEAGLColorFormatRGB565 //kEAGLColorFormatRGBA8
    depthFormat:0   //GL_DEPTH_COMPONENT24_OES
   preserveBackbuffer:NO
   sharegroup:nil
   multiSampling:NO
numberOfSamples:0];

   director_ = (CCDirectorIOS*) [CCDirector sharedDirector];
   director_.wantsFullScreenLayout = YES;
   //3.Display FSP and SPF
   [director_ setDisplayStats:YES];
   // 4.set FPS at 60
   [director_ setAnimationInterval:1.0/60];
   // 5.attach the openglView to the director_
   [director_ setView:glView];
   // 6.for rotation and other messages
   [director_ setDelegate:self];
   // 7.2D projection
   [director_ setProjection:kCCDirectorProjection2D];
// [director setProjection:kCCDirectorProjection3D];
   // 8.Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices
   if( ! [director_ enableRetinaDisplay:YES] )
      CCLOG(@"Retina Display Not supported");
   // 9.Default texture format for PNG/BMP/TIFF/JPEG/GIF images
   // It can be RGBA8888, RGBA4444, RGB5_A1, RGB565
   // You can change anytime
   [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
   // 10.If the 1st suffix is not found and if fallback is enabled then fallback //suffixes are going to searched. If none is found, it will try with the name //without //suffix
   // On iPad HD  : "-ipadhd", "-ipad",  "-hd"
   // On iPad     : "-ipad", "-hd"
   // On iPhone HD: "-hd"
   CCFileUtils *sharedFileUtils = [CCFileUtils sharedFileUtils];
   [sharedFileUtils setEnableFallbackSuffixes:NO];
// Default: NO. No fallback suffixes are going to be used
   [sharedFileUtils setiPhoneRetinaDisplaySuffix:@"-hd"];
// Default on iPhone RetinaDisplay is "-hd"
   [sharedFileUtils setiPadSuffix:@"-ipad"];
   // Default on iPad is "ipad"
   [sharedFileUtilssetiPadRetinaDisplaySuffix:@"-ipadhd"];  // Default on iPad RetinaDisplay is "-ipadhd"
   // 11.Assume that PVR images have premultiplied alpha
   [CCTexture2D PVRImagesHavePremultipliedAlpha:YES];

   // 12. and add the scene to the stack. The director will run it when it //automatically when the view is displayed
   [director_ pushScene: [IntroLayer scene]]; 

   // 13.Create a Navigation Controller with the Director
   navController_ = [[UINavigationController alloc] initWithRootViewController:director_];
   navController_.navigationBarHidden = YES;

   // 14.set the Navigation Controller as the root view controller
   [window_ setRootViewController:navController_];
   //15. make main window visible
   [window_ makeKeyAndVisible];
   return YES;

}

以上的代码中,第一步就是对UIWindow进行初始化,并绑定CCGLView。UIWindow被设置为全屏,而CCGLView则会接收所有的OpenGL ES命令调用。接下来,我们按照注释的编号来逐行解释。
1)创建程序的主窗口。
2)创建CCGLView对象,用于游戏中的渲染。在Cocos2D中,使用CCGLView将OpenGL ES命令发送给OpenGL ES驱动。从Cocos2D v2.0之后,CCGLView替代了之前的EAGLView,以使命名更加规范。
3)将FPS(Frames Per Second)和SPF(Second Per Frame)显示设置为开。Cocos2D会自动计算游戏的当前帧数,并显示在屏幕的左下角。在调试过程中FPS显示对我们会非常有用,当然在正式上传之前可以将其设置为NO(即不显示)。
4)将动画间距设置为每秒60次,这也是Cocos2D中的默认设置。通常情况下,Cocos2D每秒会更新屏幕中的显示60次(最高的刷新频率)。
5)将openglView绑定到director_导演对象上。
6)将director_的代理对象设置为自身,以便获取屏幕旋转等信息。
7)设置2D或3D投射。
8)启用Retina高清显示模式。
9)设置Cocos2D的纹理格式。
10)在iPad或Retina高清显示模式下,使用CCFileUtils自动添加图片的后缀。
11)设置PVR图像具备多重透明度。
12)初始化IntroLayer场景,并使用pushScene方法切换到该场景。
13)使用director_创建Navigation Controller。
14)将此导航控制器设置为根视图控制器。
15)设置主窗口可见。
在Cocos2D中,CCDirector负责游戏的循环运行,并且在游戏中渲染所有的图像。因此,它会掌控游戏的运行、暂停或停止。代码清单1-5中显示了使用CCDirector响应iPhone操作系统的各个事件,包括暂停或继续。
代码清单1-5 调用CCDirector

- (void)applicationWillResignActive:(UIApplication *)application {
        if( [navController_ visibleViewController] == director_ )
        [director_ pause];//1
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
        if( [navController_ visibleViewController] == director_ )
        [director_ resume];//2
}

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
   [[CCDirector sharedDirector] purgeCachedData];//3
}

-(void) applicationDidEnterBackground:(UIApplication*)application {
        if( [navController_ visibleViewController] == director_ )
        [director_ stopAnimation];//4
}

-(void) applicationWillEnterForeground:(UIApplication*)application {
        if( [navController_ visibleViewController] == director_ )
        [director_ startAnimation];
}//5
- (void)applicationWillTerminate:(UIApplication *)application {
   CC_DIRECTOR_END();} //6
- (void)applicationSignificantTimeChange:(UIApplication *)application {
   [[CCDirector sharedDirector] setNextDeltaTimeZero:YES];
} //7

我们还是按照注释编号来依次解释每个方法的作用。
1)当操作系统暂停应用的执行时,调用此方法来暂停游戏和所有的计时器。当玩家在玩游戏的过程中锁定了iPad或iPhone,或是有电话打进来,或其他类似事件发生需要强迫游戏进入后台时,会调用此方法。
2)与1)中的情况相反,通常当玩家解锁iPad或iPhone,或电话已接听完毕,会调用此方法来继续游戏和所有的计时器。
3)当系统收到内存不足的警告时,会调用此方法从内存中清除未在屏幕中显示的纹理图。
注意 所有的图像文件(PNG或PVR格式)都被加载成GPU可以理解的OpenGL ES纹理,而精灵则对应着这些纹理图。Cocos2D内置了一个纹理缓存管理器来保存这些纹理图,这样可以极大地加速创建新精灵并充分利用已有的纹理图。不利的一面是,如果收到内存警报,Cocos2D会将当前未使用的纹理图全部从内存中清除。因此,当游戏的场景切换时,有时需要手动释放当前的层和场景。
4)在iOS4.0及以后的版本中,支持应用的后台运行。在这种情况下,会停止运行屏幕中的动画。
5)与4)中的情况相反,应用重新回到前台来运行。这种情况下会重新启动屏幕中的动画。
6)玩家完全退出应用且不在后台运行时,将调用此方法。该方法会终止CCDirector的控制,并从应用程序的UIWindow中解除对EAGLView的绑定。同时还将结束游戏循环,从内存中清除所有的纹理和计时器。
7)将上一次时间调用和当前事件调用间的增量时间设置为0。该方法的调用场景是:两次时间调用之间已经过了太长的时间。这通常是由iPhone重新调整了系统时间而导致的。
在代码清单1-4中,最重要的代码是applicationDidFinishLaunching方法中的如下代码:

[director_ pushScene: [IntroLayerscene]];

应用在启动AppDelegate后,创建一个CCDirector导演类对象,然后运行IntroLayer场景。接下来我们看看IntroLayer的实现。
3 . IntroLayer
首先,IntroLayer继承自CCLayer,而CCDirector只能运行CCScene对象,所以,需要实现IntroLayer的scene方法,它会把IntroLayer当作唯一的子节点添加进去,并返回一个CCScene,具体如代码清单1-6所示。
代码清单1-6 IntroLayer的scene方法

// Helper class method that creates a Scene with the IntroLayer as the only child
+(CCScene *) scene
{
   // 'scene' is an autorelease object.
   CCScene *scene = [CCScene node];
   // 'layer' is an autorelease object.
   IntroLayer *layer = [IntroLayer node];
   // add layer as a child to scene
   [scene addChild: layer];
   // return the scene
   return scene;
}

IntroLayer在以前的Cocos2D版本中是不存在的,这是Cocos2D v2.0模板新加的类,它的主要目的就是在进入游戏之前,可以显示游戏制作公司的Logo等信息。显示Logo的实现代码如代码清单1-7所示。
代码清单1-7 IntroLayer的onEnter方法

-(void) onEnter
{
   [super onEnter];
   // 1
   CGSize size = [[CCDirector sharedDirector] winSize];

   CCSprite *background;
   //2
   if( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ) {
            background = [CCSprite spriteWithFile:@"Default.png"];
            background.rotation = 90;
   } else {
            background = [CCSprite spriteWithFile:@"Default-Landscape~ipad.png"];
   }
//3
   background.position = ccp(size.width/2, size.height/2);
   // 4
   [self addChild: background];
   // 5
   [self scheduleOnce:@selector(makeTransition:) delay:1];
}

我们仍然按照注释编号来依次解释每个方法的作用。
1)获得设备支持的窗口大小。
2)判断设备是iPhone还是iPad,并据此来加载不同的背景资源图片。
3)设置背景图片的位置。
4)把背景图片添加到IntroLayer中。
5)触发一个定时器方法调用,在1秒后会调用makeTransition函数。
最后,我们看看makeTransition方法的实现,如下所示。

-(void) makeTransition:(ccTime)dt
{
   [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[HelloWorldLayer scene] withColor:ccWHITE]];
}

这个方法只有一句代码调用,就是使用CCDirector配合CCTransitionFade场景切换特效类,把HelloWorldLayer类在1秒屏幕变白后展示出来。最后,我们看看HelloWordLayer类的实现。
4 . HelloWorldLayer
HelloWorldLayer类继承自CCLayer。因为CCScene只是一个抽象的概念,默认设置场景的方法是在类里使用一个静态初始化方法+(id)scene。此方法会生成一个CCScene对象,并且将HelloWorldLayer的对象添加为场景的节点。几乎在任何情况下,CCScene都是在这里创建和使用的。
+(id)scene类方法的代码如代码清单1-8所示。
代码清单1-8 +(id)scene类方法

+(CCScene *) scene
{
   // 'scene' is an autorelease object
   CCScene *scene = [CCScene node];

   // 'layer' is an autorelease object
   HelloWorldLayer *layer = [HelloWorldLayer node];

   // add layer as a child to scene
   [scene addChild: layer];

   // return the scene
   return scene;
}

第一行代码是通过调用[CCScene node]来创建一个CCScene的实例化对象,[CCScene node]其实等同于[[[CCScene alloc]init]autorelease];接下来,创建了一个HelloWorldLayer的层节点;最后,将该层节点添加到场景中,并返回场景给调用者。
了解了+(id)scene类方法的作用,我们再来看-(id)init初始化方法的作用,其代码如代码清单1-9所示。
代码清单1-9 -(id)init初始化方法

-(id) init
{
   // always call "super" init
   // Apple recommends to re-assign "self" with the "super" return value
   if( (self=[super init])) {

      //采用静态初始化方法生成并初始化标签对象。按住option,单击labelWithString,你会了解更多的知识

      CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];

      //实例化一个CCDirector的单例,从而从CCDirector得到窗口的尺寸
      CGSize size = [[CCDirector sharedDirector] winSize];

      //将标签放在屏幕中央,注意ccp其实是Cocos2D对于CGPointMake的宏定义,类似的宏定义还有很多
      label.position =  ccp( size.width /2 , size.height/2 );

      //将标签作为子节点添加到场景层中,这里应该注意,很多初学者会忘记这一点,然后发现精灵对象并未出//现在屏幕中。此外,可以在调用addChild之前或之后赋予位置信息
      [self addChild: label];

   //生成并初始化精灵对象
   CCSprite *plane = [CCSprite spriteWithFile:@"plane.png"];

   //将精灵放在屏幕中的特定位置

   plane.position = ccp(size.width/2,size.height*0.7);

   //将精灵作为子节点添加到场景层中

   [self addChild:plane];

   //定义一个moveAction动作,在3秒内移动到屏幕的左侧外
   id flyAction = [CCMoveTo actionWithDuration:3.0f position:ccp(size.width+100,size.height*0.7)];
   //让飞机执行这个动作
   [plane runAction:flyAction];
   }
   //后面是初始化GameCenter的成就榜和高分榜的代码,此处先略去不讲
   return self;
}

代码清单1-9中的代码注释基本上解释了每行代码的具体作用。此外,其中有些看似比较奇怪的地方,如在self = [super init]调用中,发送给super对象的init消息将返回的值赋给了self。如果大家之前有C++的编程经验,可能会对此很不理解。这是因为在Objective-C中,必须手动调用super类的init方法,不存在对父类的自动调用;而且必须把[super init]的返回值赋给self,因为有可能会得到一个空值(nil)。
[super init]的另一种写法如下,作用和上面的写法完全一样:

-(id) init {
self = [super init];
if (self != nil) { //在此添加init方法的代码
}
return self;
}

最后还有一个-(void)dealloc方法,它的作用和一般的iOS应用无异,用于销毁前面所创建的对象。
以上就是HelloCocos2D项目的详细实现过程。考虑到大家之前大多有过iOS开发的经验,这里并没有对所有类的所有实现代码进行逐行解释和分析,但通过以上三步,我们初步了解了一个Cocos2D应用的启动和运行过程,为以后开发更复杂的应用或游戏打下了坚实的基础。

时间: 2024-10-03 08:59:16

《Cocos2D权威指南》——1.4 深入学习HelloCocos2D项目的相关文章

《Cocos2D权威指南》——1.3 HelloCocos2D实例

1.3 HelloCocos2D实例 本节我们将开发一个简单的HelloCocos2D实例,并且通过几行代码在屏幕中添加一架飞机,甚至让飞机在屏幕中飞行.通过本章的实例,大家可以初步体验Cocos2D的强大功能.1.3.1 创建HelloCocos2D项目打开Xcode,单击菜单栏上的File→New→New Project以创建新项目,会看到3个Cocos2D模板,如图1-16所示. 选择第一个模板,给项目命名"HelloCocos2D",其他保持选项默认,然后单击"Nex

《Cocos2D权威指南》——导读

前言 为什么要写这本书 2011年10月5日,秋风萧瑟,阴雨绵绵,在这颗蔚蓝色的美丽星球上,一代传奇伟人乔布斯在亲友的陪伴下安然离去,宛若流星划过天际,空留那辆银色的奔驰SL55AMG在落叶纷飞中孤独守候着曾经的主人.这个世界从此失去了一位引领科技创新的时代领袖. 从1976年在父母的车库中创业开始,乔布斯参与.开创并改变了几个行业-PC.电脑动画.数字音乐.移动互联网.他创办了苹果公司,中途又因某些原因被苹果驱逐.然而在苹果挣扎于濒死的边缘时,他又挺身而出将苹果救活,并把它推到无人可以企及的高

《Cocos2D权威指南》——1.5 在设备上运行HelloCocos2D项目

1.5 在设备上运行HelloCocos2D项目 在设备上进行测试之前,我们首先要确保已经注册了苹果的iPhone开发者账号,这样注册之后,就可以登录iPhone开发者的专用入口,如图1-22所示. 配置iOS设备有两种方式:一种方式是让Xcode自动应用配置Provisioning Profile:另一种方式则是从iOS Provisioning Portal中对特定的应用手动创建一个Provisioning Profile.1.5.1 使用Xcode的自动设置 对于初学者来说,在iOS平台上

《Cocos2D权威指南》——第1章 1.0 开始前的准备工作

第一部分 基础篇 本部分内容 开始前的准备工作 你的第一款iPhone游戏-垂直射击游戏 Cocos2D核心类 Cocos2D中的动作.特效与动画 Cocos2D中的文本渲染系统Cocos2D中的事件处理机制Cocos2D世界的声音 在Cocos2D中使用瓷砖地图 物理引擎-更真实的Cocos2D世界 第1章 1.0 开始前的准备工作 本章我们将介绍什么是Cocos2D以及有关Cocos2D的一些重要基础知识,包括如何下载与安装Cocos2D-iPhone的模板.如何安装Cocos2D-iPho

《Cocos2D权威指南》——1.2 下载与安装

1.2 下载与安装 本节介绍Cocos2D的下载与安装.如果想使用Cocos2D开发iPhone应用或游戏,首先要下载Cocos2D的模板,然后安装该模板,最后创建Cocos2D**的帮助文档.下面分别来介绍这几个步骤. 1.2.1 下载Cocos2D** 首先登录Cocos2D的官方网站:http://www.cocos2d-iphone.org,切换到Download选项,可以看到如图1-2所示的网站页面. 由图1-2可以看到,Cocos2D的最新稳定版本有v1.0.1和v2.0版.考虑到C

《Cocos2D权威指南》——1.6 本章小结

1.6 本章小结 本章首先介绍了Cocos2D的基础知识.包括它的一些特性.下载并安装Cocos2D模板的步骤:然后,创建了一个简单的HelloCocos2D项目:接着详细解释了HelloCocos2D项目的实现代码:最后,介绍了如何在设备上对项目进行测试.第2章我们会以一个完整的垂直射击小游戏为背景,详细介绍使用Cocos2D开发游戏的基本方法与步骤.

《Cocos2D权威指南》——3.4 CCLayer层类

3.4 CCLayer层类 一个CCLayer是屏幕上可绘制的区域,可以是半透明的,这样就可以看到CCScene下面的其他层.在游戏编程的过程中,开发者大部分时间都需要跟层打交道.如图3-5所示,一个游戏场景包含3个层,背景层.动画层和菜单层. CCLayer直接继承自CCNode,作为精灵节点和其他节点的容器,它同时可以接收触摸输入和加速计输入的信息,前提是上述接收功能已经启用.3.4.1 CCLayer类的作用 CCLayer类的作用主要有三个. (1)其他子节点的容器和组织者 例如对一个层

《Cocos2D权威指南》——3.6 CCSprite精灵类

3.6 CCSprite精灵类 CCSprite是Cocos2D游戏开发中最常用的类,用图片把精灵(sprite)显示在屏幕上. 在游戏开发中,经常会遇到精灵(sprite)这个术语.精灵是一个图像,可以在屏幕上独立地移动.一个精灵可能是玩家角色.敌人,或者是大的背景图像.一般情况下,精灵来自于开发者所准备的PNG或PVRTC图像.一旦图像载入内存,就会将精灵转换成纹理图,从而被iPhone GPU用于在屏幕上渲染.3.6.1 CCSprite类的属性及方法 生成精灵的最简单方法是把图片文件加载

《Cocos2D权威指南》——3.8 垂直射击游戏—加载游戏数据

3.8 垂直射击游戏-加载游戏数据 为了使大家对CCSprite和各相关类的使用有更加直观的印象,下面我们结合前面的游戏示例,使用精灵表单优化游戏性能,同时在游戏开始和结束时添加菜单,让玩家对游戏有更多控制权.当然,在这个示例小游戏中,这种优化是看不出差别的.但这是最佳实践,建议读者以后编写游戏都以这种方式使用精灵. **3.8.1 注释draw方法和背景 ** 首先,在Xcode中打开之前的项目中把draw方法注释掉,同时恢复先前注释掉的添加游戏背景的代码段,编译并运行,如图3-6所示. 注意