转载自:http://www.apkbus.com/android-854-1.html
之前我们简单地介绍了一下自定义一个精灵,使其在初始化的时候即实现动画,并利用了纹理图册精简代码,今天我们着重介绍一下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轴; |