[一位菜鸟的COCOS-2D编程之路]加载游戏数据和代码重构

昨天复习了关于COCOS2d的一些基础知识,今天就来学习了关于游戏加载方面的问题和代码重构。

写一个简单的游戏数据加载的demo。

1.如果想在进入游戏前,加载游戏,肯定有进度条什么的吧,当然,也就是我们要再游戏开始前有一个关于游戏加载的场景类。 由于我自己写的demo丢失,只好拿着实例写了。。。sorry,不过我会认真的写注释的

建立如下: 

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

@interface LoadingScreen : CCLayer {
    CGSize      winSize;
    CGPoint     winCenter;
    
    int             assetCount;
}
+(CCScene *) scene;  //场景类的转化和生成

/** Called if there is any music to load, it loads the files one by one via the NSArray */
-(void) loadMusic:(NSArray *) musicFiles;  //音乐文件的加载

/** Called if there are any sfx to load, it loads the files one by one via the NSArray */
-(void) loadSounds:(NSArray *) soundClips;

/** Called if there are any Sprite Sheets to load, it loads the files one by one via the NSArray */
-(void) loadSpriteSheets:(NSArray *) spriteSheets; //精灵表单的加载,我更喜欢叫一组精灵

/** Called if there are any images to load, it loads the files one by one via the NSArray.
 Images can be a cache of backgrounds or anything else.  You can add to this method
 to have it do whatever you want with the list.
 */
-(void) loadImages:(NSArray *) images; //图片的加载

/** Called if there are any assets to load, it loads the files one by one via the NSArray.
 Assets basically are anything not of the above.  This pretty much should be modified
 to your needs.  (Such as models, etc)
 */
-(void) loadAssets:(NSArray *) assets; //季度条进度的加载
/** updates the progress bar with the next step.  When progress bar reaches 100%
 It calls loadingComplete which can change scenes, or do anything else you wish.
 */
-(void) progressUpdate; //主线程 的分线程更新完成之后的调用

/** Called by progressUpdate when all assets are loaded from the manifest. */
-(void) loadingComplete; // 全部完成调用
@end

2.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];//放置加载BAR
                        
    }
    
    return self;
}

3.进入场景之后的加载方法,也别注意不用的资源加载的方式的不同,主线程加载

-(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];

}

4.单个加载方法 SEL方法

-(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
        [[CCTextureCache sharedTextureCache] addImage:image];
        [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];        
}

4.工具类方法 ,加载,加载一部分,和加载完成的方法

-(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

至此,已经结束了加载场景的vc。

我们将要把这个scene放到我们的game中去

5.一步一步走!

修改 Appdelegate.m方法中得启动方法

只是在启动方法得末尾加上加载的方法而已

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

6.修改HellpWorldLayer.m文件的init方法

1)增加游戏菜单

 
        //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];
       
        
	}


由于触摸 开始游戏按钮之后才可以进行游戏,所以MEnu的position一定要设置成CGPointZero
现在可以试试效果了~

二,代码重构

1,添加精灵表单

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


    //添加精灵表单
        CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithFile:@"gameArts.png"];
        batchNode.position = CGPointZero;
        [self addChild:batchNode z:0 tag:kTagBatchNode];

2.修改Sprite的初始化方式

 //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,初始化方式 从 spriteWithFIle改为 spriteWithSpriteFrameName
        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];
        
        //4.init enemy sprites array
        _enemySprites = [[CCArray alloc] init];
        
        //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];
        }
        
        //8.game main loop
        [self scheduleUpdate];
        
       
        _isTouchToShoot = NO;
        
        //10.init bullets
        _bulletSprite = [CCSprite spriteWithSpriteFrameName:@"bullet1.png"];
        _bulletSprite.visible = NO;
        [batchNode addChild:_bulletSprite z:4];
        


3.为了减少修改的次数,定义一个 - (CCSprite *)getPlayerSPrite方法

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

4.修改发射子弹的碰撞检测方法

-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{    
    //修改成,必须点选中playerSprite才能够发射子弹
    
    //方法1:因为boundingBox是相对于世界坐标系而言的,所以要用self convertTouchToNodeSpace转换成世界坐标系中的坐标
    UITouch *touch = [touches anyObject];
    CCSprite *playerSprite = [self getPlayerSprite];
    
    CGPoint pt;
//    pt = [touch locationInView:[touch view]];
//    pt = [[CCDirector sharedDirector] convertToGL:pt];
//    pt = [self convertToNodeSpace:pt];
    //上面三句调用,可以简化为下面一句调用
    //CGPoint pt = [self convertTouchToNodeSpace:touch];
        
//    if (CGRectContainsPoint(playerSprite.boundingBox, pt)) {
//        _isTouchToShoot = YES;
//    }
    
    //===================================================================
    //方法2:
//    pt = [touch locationInView:[touch view]];
//    pt = [[CCDirector sharedDirector] convertToGL:pt];
//    pt = [playerSprite convertToNodeSpace:pt];
    //简化为下面的一句代码调用
    CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag:kTagBatchNode];
    pt = [batchNode convertTouchToNodeSpace:touch];
    
    CCLOG(@"pt.x = %f, pt.y = %f",pt.x, pt.y);
        
    if (CGRectContainsPoint(playerSprite.boundingBox, pt)) {
        _isTouchToShoot = YES;
        CCLOG(@"touched!");
    }
    
    
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值