今天早上来了先学习了一下:CCSpriteBatchNode,下面的系转载。
每当cocos2d在屏幕上回执一个纹理(一张图片)时,图形硬件都需要做前后三个动作:准备渲染、渲染图形和渲染后的清除。这些工作产生了一个纹理所共有的开销。如果要缓解此状况(大量的图形渲染造成大量的开销),就需要让硬件知道需要进行渲染的这一组精灵使用的是同一纹理。这样图形硬件就会为这组精灵只进行一次准备、渲染和清除的工作。
有没有完过雷电类的游戏,想象一下,当你发出大量的子弹时,若是按照一般的做法每个子弹都渲染一次的话,开销会很大。
这个时候就显示出CCSpriteBatchNode的好处来了,下面介绍下CCSpriteBatchNode。
先看个简单的例子:
一般情况下,我们向屏幕上添加一个子弹精灵是这样:
CCsprite *bullet = [CCSpritespriteWithFile:@”bullet.png”];
[self addChild:bullet];
当我们添加多个子弹时:
for(int I = 0;i<1000;i++)
{
CCsprite *bullet= [CCSprite spriteWithFile:@”bullet.png”];
[self addChild:bullet];
}
这样会开销很大。
如果使用CCSpriteBatchNode的话可以这样做:
CCSprite *batch = [CCSpritebatchNodeWithFile:@”bullet.png”];
[self addChild:batch];
CCSprite *bullet = [CCSpritespriteWithFile:@”bullet.png”];
[batch addchild:bullet];
看起来很繁琐,不向能解决问题的样子。是的,创建单个子弹效果不好,但是如果创建大量子弹那就不能相提并论了。
for(int I = 0;i<1000;i++)
{
CCsprite *bullet= [CCSprite spriteWithFile:@”bullet.png”];
[batch addChild:bullet];
}
有么有发现CCSpriteBatchNode和cocos2d的一个东西很像?没想出来的想想CCLayer!是的,和CCLayer很类似,事实上,它的特性也和CCLayer相似。
-
在同一个CCSpriteBatchNode上添加的子节点的z值只能在CCSpriteBatchNode调整绘制的顺序。这样的话你如果想创造显示在一个怪物上的子弹和显示在怪物下的子弹,你需要创建两个CCSpriteBatchNode,通过调整CCSpriteBatchNode的z值达到效果。
-
这里要注意下,CCSprite使用的纹理必须和CCSpriteBatchNode相同。看似很狭隘,但是如果你使用纹理图册(纹理图册中可以有很多不同的图像)时,就能和好的解决这个问题。实际上当使用纹理图册时,也可以很好的解决z值问题,比如说,把怪物图片添加到纹理图册中。
一个很多图像的纹理图册,制作纹理图册k可以参考http://www.2cto.com/kf/201110/108425.html
知道了怎么chuchua创建一个纹理图册,那么我们下面看通过使用纹理图册加载不同的图片精灵进入CCSpriteBatchNode:
CCSpriteFrameCache*frameCache = [CCSpriteFrameCachesharedSpriteFrameCache];
[frameCache addSpriteFramesWithFile:@"frames.plist"];
CCSpriteBatchNode*batch = [CCSpriteBatchNodebatchNodeWithFile:@"frames.png"];
[self addChild:batch];
CCSprite*sprite = [CCSpritespriteWithSpriteFrameName:@"frameone.png"];
[batch addChild:sprite];
CCSprite*sprite = [CCSpritespriteWithSpriteFrameName:@"frametwo.png"];
[batch addChild:sprite];
这样看似向batch中添加了不同的图像精灵,其实不然,frames 是所有图组合成的大图。
看提示就能发现CCSpriteBatchNodej添加子精灵节点时,检查的是文件的id,我们通过纹理图册加载精灵shi时使用的是同一张图片文件,所以成功。当加载不同文件时提示失败(个人看法)
在看cocos2d的时候发现anchorpoint和position之间的关系不清,查找了相关资料:
将该图片放置到屏幕左下方
CCSprite sprite = CCSprite.sprite("Default.png");
addChild(sprite);
生成的精灵放置在( 0,0 ),也就是屏幕左下角。但是精灵的贴图的中心点和精灵的左下角位置一致 ,导致贴图只能显示一部分(贴图的右边上半部分)。
可以这样想,一个精灵有两部分,一部分是节点背景对象 ,另一部分是贴图对象 (自己理解定义的名称,非官方)
怎么可以让贴图完全显示出来呢?使用定位点
每个节点都有一个定位点,但是只有当节点拥有贴图时,这个定位点才有用。默认情况下, anchorPoint 属性设置为(0.5,0.5 )
定位点和节点的位置没有关系。当改变 anchorPoint 属性的时候,我们能看到精灵在屏幕上的位置发生了变化,但是其实节点没有改变;改变的是精灵里贴图的位置
CCSprite sprite = CCSprite.sprite("Default.png");
sprite.setScale(0.6f);
sprite.setPosition(CGPoint.make(500, 300));
addChild(sprite);
ccMacros.CCLOGERROR("test", "Position:"+sprite.getPosition().x +"--"+sprite.getPosition().y);
ccMacros.CCLOGERROR("test", "AnchorPoint:"+sprite.getAnchorPoint().x +"--"+sprite.getAnchorPoint().y);
ccMacros.CCLOGERROR("test", "AnchorPointInPixels:"+sprite.getAnchorPointInPixels().x+"--"+sprite.getAnchorPointInPixels().y);
修改定位点为0
CCSprite sprite = CCSprite.sprite("Default.png");
sprite.setScale(0.6f);
sprite.setPosition(CGPoint.make(500, 300));
sprite.setAnchorPoint(CGPoint.make(0, 0));
addChild(sprite);
从上面可以看出来精灵的位置没有发生变化,发生变化的只是贴图对象 相对于节点背景对象 的偏移 。
默认情况下 anchorPoint 为( 0.5,0.5 ),即贴图对象 的中心位置对应着节点背景对象 的左下角;而当 anchorPoint 为(0,0 ),即贴图对象 的左下角对应着节点背景对象 的左下角
所以按照下面的代码,图片就可以正好显示在左下角了
CCSprite sprite = CCSprite.sprite("Default.png");
sprite.setAnchorPoint(CGPoint.make(0, 0));
addChild(sprite);
附:AnchorPoint问题:
设置AnchorPoint,到底有什么作用,当初我的理解是这个AnchorPoint是相对本身位置参考点。
比如:我定义个Sprite,设置一个anchorPoint为居中置顶的位置 。
sprite.anchorPoint = ccp( intW / 2, intH );
sprite.rotation = 90;
但实际翻转时还是以左下角为参考点翻转。更改的参考点并不起作用,或者我理解错误。
问题:
1:想实现我这个更改翻转的参考点,如何实现?;
2:AnchorPoint到底做什么用?
答:这个属性表示你这个图片setPosition时的点在图片上所处的位置.
取值范围0-1
0,0表示左下角,
1,1表示右上角
0.5,0.5表示图片的中心点.
所有的图片都是以矩形来界定的.
问:这样设置翻转时还是以左下角为参考点
答:在设置 anchorPoint 的时候,
imageVIew = [[UIImageView alloc] init];
imageView.anchorPoint = ccp(0.5, 1);
imageView.frame = CGRectMake(.......);
好像是先设置 anchorPoint, 再设置 frame. 试试.
答:问题算是解决了。说说基本思路。
我之前定义一个Sprite,初始化时用一个ColorLayer 填充精灵 代码如下:
+ (id) BulletWithinLayer:(CCLayer *) layer
{
BQBullet *bullet = [BQBullet node];
//bullet.anchorPoint = ccp(0.5,1);///注释A
[bullet SetLayer:layer];
return bullet;
}
-(id)init
{
if((self == [super init]))
{
CCColorLayer *tmp = [CCColorLayer layerWithColor:ccc4(255, 255, 0, 255)];
//tmp.anchorPoint = ccp(0.5,1); ///注释B
[self addChild:tmp z:0 tag:1];
}
return self;
}
//生成一个bullet精灵
BQBullet *bullet = [BulletWithinLayer:layer];
bullet.anchorPoint= ccp(0.5,1);
bullet.rotation= 45;
[layer addChild: bullet z:1];
这时看到的翻转还是已左下角,关闭注释A,B都是无效。
后面我用一个图片代替ColorLayer生成精灵,就有效果了。
为什么会有这种区别呢?更填充的层有关系吗?真是没搞懂啊?虽然说最后游戏不是这种写法,但对程序员来说,在没有图的情况下应该也能完成一个游戏,就是用单纯的色块来替换,这样就不用等美术图出来了,也能更早的出模型,至少以前在J2ME上都是可以这样做的,现在在iphone上,画个色块就TMD的这么麻烦,真是很不爽!
针对:色块无法翻转的问题找到了,因为色块是ColorLayer,CCLayer默认的isRelativeAnchorPoint = NO;重新打开就行了isRelativeAnchorPoint = YES;