holydancer原创,如需转载,请在显要位置注明:
转自holydancer的CSDN专栏,专栏地址:http://blog.csdn.net/holydancer
之前我们简单地介绍了一下自定义一个精灵,使其在初始化的时候即实现动画,并利用了纹理图册精简代码,今天我们着重介绍一下CCSpriteBatchNode,这是一个相当重要的概念,游戏开发不像应用,大量的动画图片,高速的计算,大量的图形占用,所以我们不得不将图形优化放到一个很高的位置,好在cocos2d在这一块儿上封装得很好,我们只需要了解一下一些类的基本用法,就可以很简单地优化代码;
CCSpriteBatchNode是对绘制精灵进行优化的一个辅助类,看类名我们就可以知道其是一个Node,生成精灵的时候我们需要将其放到层上,如果用CCSpriteBatchNode的话,我们只需要将一个CCspriteBatchNode对象放到该层上,其后将一个一个精灵放到该对象上即可;这样说有些笼统,看一个简单的例子:
有一张png图片"fish.png“,我们需要通过其创建一个精灵添加到层上,那么传统的方式就是:
CCSprite *fishSprite = [CCSprite spriteWithFile:@"fish.png"];
[layer addChild:fishSprite];
如果该层上有10个精灵呢?那就加个for循环,代码上我们感觉效率不低,但在硬件底层,openGL在绘制的时候每次绘制一个精灵,都要有一个准备的过程,形象的说,就像一个画家要画十只鱼,画一只鱼的时候,需要准备调色盘,画笔,画完一只,收起来;画第二只的时候,再准备调色盘,再画,画完再收好;如此十次,画得越多,耽误的越多;这样说的话你就会觉得这个画家有点二,但是传统的绘制精灵还真就是这样,机器不是人,他是不知道自己变通的;所以我们就要用到CCSpriteBatchNode了,上面的代码我们可以这样来改动:
CCSpriteBatchNode *fishBatch = [CCSpriteBatchNode batchNodeWithFile :@"fish.png"];
[layer addChild:fishBatch];
CCSprite *fishSprite = [CCSprite spriteWithFile:@"fish.png"];
[fishBatch addChild:fishSprite];
这样写你可能不觉得有什么优化,但是fishBatch里面添加的精灵越多,其优势就越明显,还是刚才的例子,之前每画一条鱼,都会准备,绘制,收起;现在将精灵添加进fishBatch,就像这个画家知道一次性要画多少条鱼,就不会那么死板的进行一次又一次额外重复的工作了;
如果我们将CCSpriteBatchNode与动画相结合的话,没有关系,假设已生成动画anim;
CCSpriteBatchNode *fishBatch = [CCSpriteBatchNode batchNodeWithFile :@"fish.png"];
[layer addChild:fishBatch];
CCSprite *fishSprite = [CCSprite spriteWithFile:@"fish.png"];
[fishSprite runAction: anim];
[fishBatch addChild:fishSprite];
下面我们来看一个将CCSpriteBatchNode,纹理图册,自定义精灵类(默认初始化运行动作),CCSpriteFrameCache结合起来的例子:
自定义精灵类fishSprite.h:
#import <Foundation/Foundation.h> #import "cocos2d.h" @interface fishSprite : CCSprite { } +(id)fish; @end
fishSprite.m
#import "fishSprite.h" @implementation fishSprite +(id)fish { return [[self alloc]initWithImage]; } -(id)initWithImage { if ((self=[super init])) { [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"fish.plist"]; // 将所有fish.plist相关的精灵添加到缓存里; self = [CCSprite spriteWithSpriteFrameName:@"fish1.png"]; //这句很关键,不加这句,CCSproteBatchNode和自定义生成的精灵不会采用同一个纹理,这样强行采用这种技术就会报错; //下面将纹理图册中的纹理组成动画;使用CCSpriteFrameCache和纹理图册结合会很方便; NSMutableArray *frameArray = [NSMutableArray array]; for (int i = 1; i<15; i++) { [frameArray addObject: [[CCSpriteFrameCache sharedSpriteFrameCache ]spriteFrameByName: [NSString stringWithFormat:@"fish%d.png",i]]]; } CCAnimation *fishAnimation = [CCAnimation animationWithSpriteFrames:frameArray delay:0.05f]; CCAnimate *animate = [CCAnimate actionWithAnimation:fishAnimation]; [self runAction:[CCRepeatForever actionWithAction:animate]]; //使该精灵一生成就会运动; } return self; } @end
之后在显示层的init方法中这样添加:
-(id)init { // ask director for the window size if (self = [super init]) { CGSize size = [[CCDirector sharedDirector] winSize]; CCSprite *background; background = [CCSprite spriteWithFile:@"bg.jpg"]; background.position = ccp(size.width/2, size.height/2); // add the label as a child to this Layer [self addChild: background]; // //在层上添加精灵; CCSpriteBatchNode *fishBatch = [CCSpriteBatchNode batchNodeWithFile:@"fish.png"]; [self addChild:fishBatch]; CCSprite *fish = [fishSprite fish]; fish.position = ccp(140, 150); [self addChild:fish]; [self scheduleUpdate]; } return self; }
这样,代码中的注释很明白,这里再强调一下几点:
1、CCSpriteBatchNode中添加的精灵所依赖的生成纹理必须是一样,包括生成CCSpriteBatchNode对象时所使用的纹理;
2、所有添加进去的精灵,z轴都是一样的,即都依赖于CCSSpriteBatchNode对象的z轴;