[cocos2d]关于CCSprite的若干问题与误区

文章 [cocos2d] 利用texture atlases生成动画 中介绍了如何生成动画并绑定在CCSprite实例上。

使用该代码遇到了几个问题,值得mark下

问题1、多实例

问题描述:

新建一个PlayerSprite类继承CCSprite,若在PlayerSprite类中使用文中代码生成会出现问题。

//生成sprite(动画将绑定在sprite上)    
CCSprite *sprite = [CCSprite spriteWithSpriteFrame:[frameCache spriteFrameByName:@"1.png"]];

问题出现在于这句。
因为PlayerSprite已经是CCSprite类,当PlayerSprite实例化时,此行代码会再把CCSprite实例化,之后的动画会绑定在新的sprite上。

解决方法:

1、在PlayerSprite类中删除此句代码,并将之后的所有的sprite改成 self 即可。(注意最后还有一句addChild要删除)

 1 @interface PlayerSprite : CCSprite
 2 @end
 3 @implementation PlayerSprite
 4 //利用软件将5帧png贴图生成1张大的png贴图和plist
 5    CCSpriteFrameCache *frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
 6 //读取plist并缓存plist包含的贴图
 7     [frameCache addSpriteFramesWithFile:@"sprite.plist"];
 8     NSMutableArray *frames = [NSMutableArray arrayWithCapacity:5];
 9     int i;
10     for (i = 1; i <= 5; i++){
11 //假设命名为1.png 2.png。。。。
12         NSString *file = [NSString stringWithFormat:@"%i.png",i];
13 //从缓存中读取贴图生成动画帧
14         CCSpriteFrame *frame = [frameCache spriteFrameByName:file];
15 //加入到动态数组中         
16         [frames addObject:frame];
17     }
18 //利用动画帧生成动画对象
19    CCAnimation *anim = [CCAnimation animationWithSpriteFrames:frames delay:0.05f];
20 //生成sprite(动画将绑定在sprite上)    
21 //此句删除
22 //  CCSprite *sprite = [CCSprite spriteWithSpriteFrame:[frameCache spriteFrameByName:@"1.png"]];
23 //生成在屏幕中间
24     self.position = CGPointMake(screenSize.width / 2, screenSize.height / 2);
25 //利用animate运行动画
26     CCAnimate *animate = [CCAnimate actionWithAnimation:anim];
27 //重复播放动画
28     CCRepeatForever *repeat = [CCRepeatForever actionWithAction:animate];
29     [self runAction:repeat];
30 //加入到场景中
31 //此句也要删除,在适当的地方补回此句代码
32 //    [self addChild:sprite z:0 tag:1];
33 
34 @end
修改后的代码

 2、然后在适当的地方实例化 

PlayerSprite *sprite = [PlayerSprite spriteWithSpriteFrame:[frameCache spriteFrameByName:@"1.png"]];
[self addChild:sprite z:0 tag:1];

 经验:

copy代码一定要明白每一行代码的用处~

 

问题2、contentSize为0

问题描述:开始出现问题1的时候我是直接把该代码删除

然后直接在适当的地方使用下面代码实例化。(如果不使用texture的相关属性不会有明显的问题)

PlayerSprite *sprite = [PlayerSprite node];

如果此时要获得sprite大小的话会发现返回值为0。

//sprite的contentSize大小
CGSize size1 = sprite.contentSize; //sprite所使用的贴图大小,使用纹理贴图集会发生问题,返回为纹理贴图的size
CGSize size2 = sprite.texture.contentSize; //返回的是sprite大小(包括旋转,缩放,变换) CGRect rect = sprite.boundingBox;

根据cocos2d库的源代码追溯下去寻找,发现如果使用spriteWithXXX实例化,最终会调用CCTexture2D获得贴图的大小;而直接使用[CCSprite node]初始化则少了该步,最后导致实例没有正确的size值;

 1 @implementation CCSprite
 2 
 3 //....
 4 
 5 -(id)initWithFile:(NSString*)filename{
 6 //.....省略
 7 
 8 CCTexture2D *texture  = [[CCTextureCache sharedCache] addImage:filename];
 9 
10 if ( texture ){
11 CGRect rect = CGRectZero;
12 rect.size = texture.contentSize;
13 return [self initWithTexture:texture rect:rect];
14 }
15 
16 [self release];
17 return nil;
18 
19 }
20 
21 //.....
22 @end
CCSprite Source Code


解决方法:

同问题1,使用spriteWithXXX实例化即可

PlayerSprite *sprite = [PlayerSprite spriteWithSpriteFrame:[frameCache spriteFrameByName:@"1.png"]];
[self addChild:sprite z:0 tag:1];

经验:

由此可以看出CCSprite与CCLayer,CCScene的继承类实例过程有不同的地方,

CCSprite的继承类用spriteWithXXX实例化的话,不会调用继承类的init方法,而只会调用CCSprite的init方法。

而对于CCLlayer与CCScene的继承类,因为是用XXLayer *layer = [XXLayer node]此类方式实例化,而 node实则上是[[[self alloc] init] autorelease]的缩写,会调用继承类的init方法。

 

问题3、贴图复用/获得已缓存的贴图

PlayerSprite *sprite = [PlayerSprite spriteWithSpriteFrame:[frameCache spriteFrameByName:@"1.png"]];

 可能有人会发现在问题1、2中sprite使用的贴图是frameCache中获得的,那么有没方法获得已经缓存好的贴图而不是每次都要重新加载呢?

Learn iPhone and iPad Cocos2D Game Development一书中作者在第七章中介绍到一个比较好的方法

( Scrolling With Joy -> Advanced Parallax Scrolling -> Re-creating the Background in Code)

待续

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值