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

3.8 垂直射击游戏—加载游戏数据

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

注意 这时必须触碰玩家飞机才可以发射子弹,同时,此刻的碰撞检测代码也有所差别,当然,玩家是感觉不到的。
3.8.2 加载游戏资源
首先需要让玩家决定什么时候开始游戏,因此要在游戏正式开始前添加一个菜单用来开始游戏。只有当玩家触碰此菜单时,才会正式开始游戏。为了使游戏开发更加贴近实际开发,这里介绍如何制作一个LoadingScreen场景来加载游戏所需要的图片、音效、背景音乐、存档等资源。
1 . 创建LoadingScreen
为了简单起见,该LoadingScreen只显示一个Loading字样,没有使用进度条。后面章节的实例中再考虑使用进度条,这样用户体验会更好一些。虽然界面显示比较简单,但这里向大家介绍的是一种通用的预先加载游戏资源的做法,以后任何Cocos2D游戏都可以使用此方法进行加载。
单击File→New→File,从左边选择Cocos2D v2.x模板,在右边的模板类中选择CCNode class模板类,选择CCLayer作为基类,然后选择next并保存到项目的VerticalShootingGame文件夹下。
用代码清单3-8中的代码替换LoadingScreen.h的内容。

代码清单3-8 LoadingScreen.h文件替换代码

#import <Foundation/Foundation.h>
#import "cocos2d.h"

@interface LoadingScreen : CCLayer {
    CGSize      winSize;
    CGPoint     winCenter;
    int             assetCount;
}
+(CCScene *) scene;
-(void) loadMusic:(NSArray *) musicFiles;
-(void) loadSounds:(NSArray *) soundClips;
-(void) loadSpriteSheets:(NSArray *) spriteSheets;
-(void) loadImages:(NSArray *) images;
-(void) loadAssets:(NSArray *) assets;
-(void) progressUpdate;
-(void) loadingComplete;
@end

LoadingScreen继承自CCLayer,提供一个静态scene方法供CCDirector对象调用。接下来定义3个成员变量,其中winSize代表游戏屏幕窗口大小,winCenter代表窗口的中点,assetCount用来保存游戏需要加载的资源总数。
2 . Loading方法
重点是接下来一系列的Loading方法,每个方法都接收一个NSArray数组作为参数。这些参数都是一些具体资源的文件名,参数的值是从一个配置文件中读出来的,后面我们在介绍实现时会给出来。这些方法及用途如下:
-(void) loadMusic:(NSArray *) musicFiles;(加载背景音乐)
-(void) loadSounds:(NSArray *) soundClips;(加载游戏音效)
-(void) loadSpriteSheets:(NSArray *) spriteSheets;(加载精灵表单)
-(void) loadImages:(NSArray *) images;(加载背景图片等图片资源)
-(void) loadAssets:(NSArray *) assets;(加载游戏字体、存档等资源)
-(void) progressUpdate;(更新游戏进度条,目的只是计算何时加载完成)
-(void) loadingComplete;(资源全部加载完成,切换到另一个游戏场景)
3 . LoadingScreen的具体实现
打开LoadingScreen.m文件,用代码清单3-9替换其中的内容。
代码清单3-9 LoadingScreen.m

#import "LoadingScreen.h"
#import "SimpleAudioEngine.h"

//The next scene you wish to transition to
#import "HelloWorldLayer.h"
@implementation LoadingScreen
+(CCScene *) scene
{
   // 'scene' is an autorelease object
  CCScene *scene = [CCScene node];
    NSString *className = NSStringFromClass([self class]);
    // 'layer' is an autorelease object.
    id layer = [NSClassFromString(className) node];
   // add layer as a child to scene
   [scene addChild: layer];
   // return the scene
   return scene;
}

-(id) init
{
    if ( ( self = [ super init] ) )
    {
        winSize = [[CCDirector sharedDirector] winSize];
        winCenter = ccp(winSize.width / 2, winSize.height / 2);
        CCLabelTTF *loadingText = [CCLabelTTF labelWithString:@"Loading..." fontName:@"Arial" fontSize:20];
        loadingText.position = ccpAdd(winCenter, ccp(0,50));
        [self addChild:loadingText];
    }
    return self;
}

-(void) onEnterTransitionDidFinish
{
    [super onEnterTransitionDidFinish];

    NSString *path = [[CCFileUtils sharedFileUtils] fullPathFromRelativePath:@"preloadAssetManifest.plist"];
    NSDictionary *manifest = [NSDictionary dictionaryWithContentsOfFile:path];
    NSArray *spriteSheets   = [manifest objectForKey:@"SpriteSheets"];
    NSArray *images         = [manifest objectForKey:@"Images"];
    NSArray *soundFX        = [manifest objectForKey:@"SoundFX"];
    NSArray *music          = [manifest objectForKey:@"Music"];
    NSArray *assets         = [manifest objectForKey:@"Assets"];
    assetCount = ([spriteSheets count] + [images count] + [soundFX count] + [music count] + [assets count]);
    if (soundFX)
        [self performSelectorOnMainThread:@selector(loadSounds:) withObject:soundFX waitUntilDone:YES];

    if (spriteSheets)
        [self performSelectorOnMainThread:@selector(loadSpriteSheets:) withObject:spriteSheets waitUntilDone:YES];
    if (images)
        [self performSelectorOnMainThread:@selector(loadImages:) withObject:images waitUntilDone:YES];

    if (music)
        [self performSelectorOnMainThread:@selector(loadMusic:) withObject:music waitUntilDone:YES];

    if (assets)
        [self performSelectorOnMainThread:@selector(loadAssets:) withObject:assets waitUntilDone:YES];
}
-(void) loadMusic:(NSArray *) musicFiles
{
    CCLOG(@"Start loading music");
    for (NSString *music in musicFiles)
    {
        [[SimpleAudioEngine sharedEngine] preloadBackgroundMusic:music];
        [self progressUpdate];
    }
}

-(void) loadSounds:(NSArray *) soundClips
{
    CCLOG(@"Start loading sounds");
    for (NSString *soundClip in soundClips)
    {
        [[SimpleAudioEngine sharedEngine] preloadEffect:soundClip];
        [self progressUpdate];
    }
}
-(void) loadSpriteSheets:(NSArray *) spriteSheets
{
    for (NSString *spriteSheet in spriteSheets)
    {
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:spriteSheet];
        [self progressUpdate];
    }
}
-(void) loadImages:(NSArray *) images
{
    CCLOG(@"LoadingScreen - loadImages : You need to tell me what to do.");
    for (NSString *image in images)
    {
        //Do something with the images
        [self progressUpdate];
    }
}

-(void) loadAssets:(NSArray *) assets
{
    //Overwrite me
    CCLOG(@"LoadingScreen - loadAssets : You need to tell me what to do.");
    for (NSString *asset in assets)
    {
        //Do something with the assets
        [self progressUpdate];
    }
    [self progressUpdate];
}
-(void) progressUpdate
{
    if (--assetCount)
    {
        //以备后面显示进度条用
    }
    else {
        [self loadingComplete];
        CCLOG(@"All done loading assets.");
    }
}
-(void) loadingComplete
{
    CCDelayTime *delay = [CCDelayTime actionWithDuration:2.0f];
    CCCallBlock *swapScene = [CCCallBlock actionWithBlock:^(void) {
    [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0f     scene:[HelloWorldLayer scene]]];
    }];
    CCSequence *seq = [CCSequence actions:delay, swapScene, nil];
    [self runAction:seq];
}
@end

虽然代码比较多,但是不要害怕,我们会依次解释其中的每个方法。
(1)+(CCScene *) scene
这个类方法的实现代码跟一般的有一些不同,它使用Objective-C的动态语言特性反射。首先使用NSStringFromClass得到类名:

NSString *className = NSStringFromClass([self class]);

此处className为LoadingScreen。然后使用NSClassFromString得到该类的类型:

id layer = [NSClassFromString(className) node];

这里还会给该类型发送一个node消息。这种反射和任意发送消息的能力使Objective-C语言具有强大的灵活性,也为游戏开发提供大量的便利。我们可以把关卡的配置、敌人的类型直接存储为文件,然后反射解析。

(2)init方法
该方法的实现非常简单,就是计算屏幕窗口大小和中点位置,然后初始一个CCLabelTTF对象,用来显示Loading字样。
下面我们来看比较重要的onEnterTransitionDidFinish方法。
(3)onEnterTransitionDidFinish方法
该方法首先加载一个配置文件,然后读取配置文件中的游戏资源名字列表并存储在不同的数组中。示例代码如下:

NSString *path = [[CCFileUtils sharedFileUtils] fullPathFromRelativePath:@"preloadAssetManifest.plist"];
    NSDictionary *manifest = [NSDictionary dictionaryWithContentsOfFile:path];

    NSArray *spriteSheets   = [manifest objectForKey:@"SpriteSheets"];
    NSArray *images         = [manifest objectForKey:@"Images"];
    NSArray *soundFX        = [manifest objectForKey:@"SoundFX"];
    NSArray *music          = [manifest objectForKey:@"Music"];
    NSArray *assets         = [manifest objectForKey:@"Assets"];
    assetCount = ([spriteSheets count] + [images count] + [soundFX count] + [music count] + [assets count]);

首先使用CCFileUtils获得preloadAssetManifest.plist文件的具体路径,调用NSDictionary的dictionaryWithContentsOfFile把该文件转换成一个字典对象;然后通过key值取出每种不同类型资源的数组;最后调用数组的count方法得到总共需要加载的资源数量。
继续之前,我们首先需要将资源添加到项目中,打开本章附带示例项目的chapter3/resource/progress目录,将其中的资源全部添加进项目中;然后查看preloadAssetManifest.plist的具体配置情况,在Xcode中打开Resources分组下的arts文件夹,并展开其中的项目,如图3-7所示。

由图3-7可以看出,加载的音效是bullet.mp3,精灵表单为gameArts.plist,背景音乐是game_music.mp3。
注意 本项目比较简单,资源数量有限,完成加载场景基本体会不到加载的过程,因为速度实在是太快了。
接下来我们看看后面的代码。

if (soundFX)
[selfperformSelectorOnMainThread:@selector(loadSounds:)
withObject:soundFXwaitUntilDone:YES];
if (spriteSheets)
       [selfperformSelectorOnMainThread:@selector(loadSpriteSheets:)
withObject:spriteSheets waitUntilDone:YES];
if (images)
       [self performSelectorOnMainThread:@selector(loadImages:)
withObject:images waitUntilDone:YES];
if (music)
       [self performSelectorOnMainThread:@selector(loadMusic:)
withObject:music waitUntilDone:YES];
    if (assets)
       [self performSelectorOnMainThread:@selector(loadAssets:)
withObject:assets waitUntilDone:YES];

这段代码并不复杂,调用performSelectorOnMainThread在主线程上依次加载每种类型的游戏资源,同时waitUntilDone的值为YES能保证所有的资源按照序列依次加载。
其他方法这里就不一一介绍了,注意几个方法。比如:
预先加载音效:[[SimpleAudioEngine sharedEngine] preloadEffect:soundClip]
预先加载背景音乐:[[SimpleAudioEngine sharedEngine] preloadBackgroundMusic:music]
预先加载PNG图片:[[CCTextureCache sharedTextureCache] addImage:image]
预先加载精灵表单可以使用下面的方法:

[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:spriteSheet];

这个方法首先会加载与该plist方法名称相同但后缀为.png的纹理图片,把该plist的所有spirteFrame信息读取出来,以后可以通过spriteFrameWithName获取相应的精灵帧。
(4)progressUpdate和loadingComplete方法
目前,progressUpdate方法非常简单,只是更新资源的总数,当资源全部加载完毕时会调用loadingComplete方法。loadingComplete方法的作用是:过2秒之后运行一个场景切换特效跳转到游戏主场景,即HelloWorldLayer。
3.8.3 修改AppDelegate.m文件
1)添加所包含的头文件。在文件的顶部添加代码:

#import "LoadingScreen.h"

2)修改- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法。
在该方法最后,把之前的pushScene方法改成下面代码:

[director_ pushScene: [LoadingScreen scene]];

编译并运行游戏,首先会看到一个Loading界面,再进入游戏场景。但是我们希望在场景跳转之后,玩家可以看到有一个开始游戏的按钮,只有当玩家选择“开始游戏”时,敌机才出现,游戏才正式开始。因此这里需要对HelloWorldLayer的实现做一些修改。
3.8.4 修改HelloWorldLayer
1)打开HelloWorldLayer.h文件,在其中添加下列变量:

CCMenu  *_startGameMenu;
BOOL    _isGameStarted;

2)打开HelloWorldLayer.m的init方法,添加如代码清单3-10所示代码。
代码清单3-10 在init方法中添加代码

//15.add game start menu & relative game logic
        _isGameStarted = NO;
        [CCMenuItemFont setFontSize:20];
        [CCMenuItemFont setFontName:@"Arial"];

        CCMenuItemFont *startItem = [CCMenuItemFont itemWithString:@"开始游戏" block:^(id sender)
                                 {
                                     _isGameStarted = YES;
                                     CCMenuItem item = (CCMenuItemFont)sender;
                                     item.visible = NO;
    //6.spawn enemy after 1.0 sec
                                     [self performSelector:@selector(spawnEnemy)
                                                withObject:nil
                                                afterDelay:1.0f];
                                     //7.enable accelerometer
                                     self.isAccelerometerEnabled = YES;
                                     //9.enable touch
                                     self.isTouchEnabled = YES;
                                 }];
        startItem.position = ccp(winSize.width / 2, winSize.height / 2);
        _startGameMenu = [CCMenu menuWithItems:startItem, nil];
        _startGameMenu.position = CGPointZero;
        [self addChild:_startGameMenu];

首先注意,这里把之前的代码清单2-11、2-14和2-21的部分代码移到block方法的内部。这里还需要注意,因为只有当玩家触碰“开始游戏”按钮之后,才会正式允许玩家控制飞机的飞行以及发射子弹,所以一定要把Menu的position设置为CGPointZero。
此时编译并运行,加载场景过程效果如图3-8所示,加载完资源以后的游戏画面如3-9所示。
注意 这里所使用的菜单是最简陋的一种,是直接使用系统内置字体创建的。当然,大家还可以通过label、sprite创建更加丰富多彩的按钮,可以参考Cocos2D自带的MenuTest项目。

3.8.5 代码重构
接下来要解决本章最重要的代码重构问题,使用SpriteFrameCache和SpriteFrame初始化精灵,这里用精灵表单来优化游戏性能。
1 . 添加精灵表单
在init方法的最上面添加代码:

CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithFile:@"gameArts.png"];
        batchNode.position = CGPointZero;
        [self addChild:batchNode z:0 tag:kTagBatchNode];

这里给spriteBatchNode添加一个新的tag,所以需要在HelloWorldLayer.m文件最上方定义这个枚举常量:

enum  {
    kTagPalyer = 1,
    kTagBatchNode = 2,
};

2 . 修改sprite的初始化方式
把spriteWithFile改写成spriteWithSpriteFrameName,同时把sprite加到batchNode中而不是加到layer里。这样做的好处是减少opengl call的次数,提高游戏渲染性能。具体如代码清单3-11所示。

代码清单3-11 使用精灵表单减少opengl call的次数

//2.add background
        CCSprite *bgSprite = [CCSprite spriteWithSpriteFrameName:@"background_1.jpg"];
        bgSprite.position = ccp(winSize.width / 2,winSize.height/2);
        [batchNode addChild:bgSprite z:-100];
        //3.add player's plane
        CCSprite *playerSprite = [CCSprite spriteWithSpriteFrameName:@"hero_1.png"];
        playerSprite.position = CGPointMake(winSize.width / 2, playerSprite.contentSize.height/2 + 20);
        [batchNode addChild:playerSprite z:4 tag:kTagPalyer];
        //5.initialize 10 enemy sprites & add them to _enemySprites array for future useage
        const int NUM_OF_ENEMIES = 10;
        for (int i=0; i < NUM_OF_ENEMIES; ++i) {
            CCSprite *enemySprite = [CCSprite spriteWithSpriteFrameName:@"enemy1.png"];
            enemySprite.position = ccp(0,winSize.height + enemySprite.contentSize.height + 10);
            enemySprite.visible = NO;
            [batchNode addChild:enemySprite z:4];
            [_enemySprites addObject:enemySprite];
        }
        //10.init bullets
        _bulletSprite = [CCSprite spriteWithSpriteFrameName:@"bullet1.png"];
        _bulletSprite.visible = NO;
        [batchNode addChild:_bulletSprite z:4];

此时运行代码,我们会发现有点问题,游戏行为变得有些古怪,因为之前操作playerSprite时是通过[self getChildByTag:kTagPlayer]来获取玩家精灵的。现在我们要改成[batchNode getChildByTag:kTagPlayer]。
3 . 定义-(CCSprite*) getPlayerSprite方法
为了减少重复修改,这里需要定义一个新方法-(CCSprite*) getPlayerSprite,其实现如代码清单3-12所示。
代码清单3-12 -(CCSprite*) getPlayerSprite实现

-(CCSprite*)getPlayerSprite{
    CCSpriteBatchNode batchNode = (CCSpriteBatchNode)[self getChildByTag:kTagBatchNode];
    return (CCSprite*)[batchNode getChildByTag:kTagPalyer];

}

要理解上述代码,我们的头脑中需要有一个node的层级关系图,首先通过当前layer找到batchNode,然后通过batchNode找到playerSprite。
此时还需要稍微修改其他内容来获得playerSprite的方法,修改以下代码:

CCSprite *playerSprite = (CCSprite)[self getChildByTag:kTagPlayer];

将其改写成:

CCSprite *playerSprite = [self getPlayerSprite];

共有三处需要修改,大家可以参考随书附赠的源码,这里就不再赘述了。
4 . 修改发射子弹的碰撞检测算法
另外单击玩家发射子弹的碰撞检测算法也要进行修改,如代码清单3-13所示。
代码清单3-13 修改单击玩家就发射子弹的碰撞检测算法

-(void) ccTouchesEnded:(NSSet )touches withEvent:(UIEvent )event{
    //修改成,必须选中playerSprite才能够发射子弹
    UITouch *touch = [touches anyObject];
    CCSprite *playerSprite = [self getPlayerSprite];
    CGPoint pt;
    //简化为下面的一句代码调用
    CCSpriteBatchNode batchNode = (CCSpriteBatchNode)[self getChildByTag: kTagBatchNode];
    pt = [batchNode convertTouchToNodeSpace:touch];
    if (CGRectContainsPoint(playerSprite.boundingBox, pt)) {
        _isTouchToShoot = YES;
        CCLOG(@"touched!");
    }
}

相信通过这段代码大家能更清楚地认识到,bondingBox是相对于节点的父节点来计算的。如果要判断一个点是否在一个矩形区域内,首先要把它们都转化到同一个坐标系中,才能进行相应的判断。本例中把touch点和玩家飞机的矩形区域都转化到batchoNode的坐标空间中。
将-(void) updatePlayerPosition:(ccTime)dt方法中计算图片纹理宽度一半的语句:

float imageWidthHavled = playerSprite.texture.contentSize.width * 0.5f;

改成以下代码:

float imageWidthHavled = playerSprite.textureRect.size.width * 0.5f;

注意 谨慎使用sprite.texture.contentSize,只有当使用精灵图片文件初始化精灵时这种写法才有效,如果使用spriteBatchNode则会失效!!!
如果使用CCSpriteBatchNode创建精灵对象,就不能将精灵对象添加为当前层的子节点,而应添加为精灵表单的子节点。另外,以上方法是为了让大家对CCSprite相关类有更清晰的认识,在实际游戏开发中,并不需要使用上述这么复杂的步骤。
编译并运行到真机上面,好好享受学习的成果吧!

时间: 2024-10-03 21:59:26

《Cocos2D权威指南》——3.8 垂直射击游戏—加载游戏数据的相关文章

《Hack与HHVM权威指南》——1.2.1 自动加载一切

本节书摘来自华章出版社<Hack与HHVM权威指南>一书中的第1章,第1.2.1节,作者 Owen Yamauchi,更多章节内容可以访问"华章计算机"公众号查看. 1.2.1 自动加载一切 类型检查器做出的一个关键假设就是,你的项目经过设置后,代码库中的任何类.函数或者常量都能够在你代码库的其他地方使用.不会尝试去分析任何include或者require语句,确保当前文件在使用时已经加载了其他文件.相反,它认为你已经完成了"自动加载"的相关设置.这就简

《Cocos2D权威指南》——导读

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

html5-html游戏加载 统一logo界面

问题描述 html游戏加载 统一logo界面 10C 现在手上又一些html5的游戏,想给他们加统一的加载界面.就是在游戏开始前添加一个图片,1秒后图片消失,然后显示游戏界面...请问怎么做. 解决方案 setTimeout(function(){ location.href = '游戏界面链接';}1000);

[Unity3D]异步加载游戏场景与异步加载游戏资源进度条

摘要: 异步任务相信大家应该不会陌生,那么本章内容MOMO将带领大家学习Unity中的一些异步任务.在同步加载游戏场景的时候通常会使用方法 Application.LoadLevel("yourScene"); 这句代码执行完毕后程序会干什么呢??如下 ...     异步任务相信大家应该不会陌生,那么下面介绍一下Unity中的一些异步任务.在同步加载游戏场景的时候通常会使用方法 Application.LoadLevel("yourScene");  这句代码执行

模拟农场17游戏加载不进去怎么解决

模拟农场17进不去游戏怎么办 只要做好以下5点就可以了: 1路径设置都为英文,减少文件夹字符,以免报错闪退. 2更新最新的显卡的驱动,防止游戏无法进入. 3检查配置是否达到最低要求,配置高低是检测进入游戏的门槛. 4安装游戏必备组件(系统运行库)所有游戏运行都需要系统组件支持. 5安装时下载关闭杀毒软件,以免误杀游戏部分未识别文件. 好了以上就是小编为各位整理的一篇关于模拟农场17游戏加载不进去问题的解决办法了,具体的细节如下文介绍.

《Cocos2D权威指南》——第2章 你的第一款iPhone游戏—垂直射击游戏 2.1 准备工作

第2章 你的第一款iPhone游戏-垂直射击游戏 本章我们将以一个垂直射击游戏为题材,带领大家动手制作一个简单的游戏,主要目的是让大家对Cocos2D开发游戏有一个感性的认识,同时体验Cocos2D的强大以及易用性.之后的章节将引入更多的游戏元素,逐步完善此游戏. 2.1 准备工作 作为开发者,首先需要有一台iOS设备,iPhone.iPod Touch或者iPad都可以:其次要拥有开发者账号,按照第1章介绍的方法下载并安装开发者证书,这样才可以把游戏编译运行到真机上.为什么非要真机呢?接下来向

《Cocos2D权威指南》——2.5 游戏音效

2.5 游戏音效 游戏如果跟无声电影一样,那么肯定会少了很多乐趣.其实要在Cocos2D的游戏世界里添加声音是非常简单的.打开HelloWorldLayer.m,在文件顶部添加一行代码以导入头文件.在init方法中return self:语句前.if条件语句的最后添加代码清单2-26所示代码.代码清单2-26 在方法中return self:语句前.if条件语句的最后添加代码 [[SimpleAudioEngine sharedEngine] preloadEffect:@"bullet.mp3

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

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

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

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