1. 如何优化cocos2d程序的内存使用和程序大小
避免一个接一个地加载PNG和JPG纹理(他们之间至少等待一帧)
cocos2d里面纹理加载分为两个阶段:1.从图片文件中创建一个UIImage对象。2.以这个创建好的UIImage对象来创建
CCTexture2D对象。这意味着,当一个纹理被加载的时候,在短时候内,它会消耗两倍于它本身内存占用的内存大小。(译注:为什么只是短时间内呢?
因为autoRelease pool和引用计数的关系,临时创建的UIImage对象会被回收。)
当你在一个方法体内,接二连三地加载4个纹理的时候,这个内存问题会变得更加糟糕。因为在这个方法还没结束之前,每一个纹理都会消耗两倍于它本身的内存。
我不是很确定,现在的cocos2d是否仍然如此。或者这种情况是否只适用于手工引用计数管理,或许ARC不会如此呢?我习惯于按顺序加载纹理,但是在加
载下一个纹理之前要等待一帧。这将会使得任何纹理加载的消耗对内存的压力降低。因为等待一帧,引用计数会把临时的UIImage对象释放掉,减少内存压
力。此外,在后续的文章中,如果你想在背景线程中按序加载纹理的话,也可以采用这种方法。
不要使用JPG图片!
cocos2d-iphone使用JPG纹理的时候有一个问题。因为JPG纹理在加载的时候,会实时地转化为PNG格式的纹理。这意味着cocos2d-iphone加载纹理是非常慢的(这里有演示),而且JPG纹理将消耗三倍于本身内存占用大小的内存。
一个2048*2048大小的纹理会消耗16M的内存。当你加载它的时候,在短时间内,它将消耗32MB内存。现在,如果这个图片是JPG格式,你会看到
这个数字会达到48MB,因为额外的UIImage对象的创建。虽然,最终内存都会降到16M,但是,那一个时刻的内存飙高,足以让os杀死你的游戏进
程,造成crash,影响用户体验。
JPG不论在加载速度和内存消耗方面都很差。所以,千万不要使用JPG!
忽视文件图片大小
这种情况,我见到很多。它乍听起来可能觉得有点荒诞,但事实如此,因为它需要关于文件格式的知识,而这些知识并不是每一个程序员都了解的。我经常听到的论断就是“嘿!我的程序不可能有内存警告,我所有的图片资源加起来还不到30MB!”。
怎么说呢,因为图片文件大小和纹理内存占用是两码事。假设他们是帐篷。图片文件就相当于帐篷被装在行李箱。但是,如果你想要使用帐篷的话,它必须被撑起来,被“膨胀”。
图片文件和纹理的关系与此类似。图片文件大多是压缩过的,它们被使用的话必须先解压缩,然后才能会GPU所处理,变成我们熟知的纹理。一个
2048*2048的png图片,采用32位颜色深度编码,那么它在磁盘上占用空间只有2MB。但是,如果变成纹理,它将消耗16MB的内存!
当然,减少纹理占用内存大小是有办法滴。
使用16-bit纹理
最快速地减少纹理内存占用的办法就是把它们作为16位颜色深度的纹理来加载。cocos2d默认的纹理像素格式是32位颜色深度。如果把颜色深度减半,那么内存消耗也就可以减少一半。并且这还会带来渲染效率的提升,大约提高10%。
你可以使用CCTexture2D对象的类方法setDefaultAlphaPixelFormat来更改默认的纹理像素格式,代码如下:
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGB5A1];
[[CCTextureCache sharedTextureCache] addImage:@"ui.png"];
这里有个问题:首先,纹理像素格式的改变会影响后面加载的所有纹理。因此,如果你想后面加载纹理使用不同的像素格式的话,必须再调用此方法,并且重新设置一遍像素格式。
其次,如果你的CCTexture2D设置的像素格式与图片本身的像素格式不匹配的话,就会导致显示严重失真。比如颜色不对,或者透明度不对等等。
有哪些比较有用的纹理像素格式呢?
generate 32-bit textures: kCCTexture2DPixelFormat_RGBA8888 (default)
generate 16-bit textures: kCCTexture2DPixelFormat_RGBA4444
generate 16-bit textures: kCCTexture2DPixelFormat_RGB5A1
generate 16-bit textures: kCCTexture2DPixelFormat_RGB565 (no alpha)
RGBA8888是默认的格式。对于16位的纹理来说,使用RGB565可以获得最佳颜色质量,因为16位全部用来显示颜色:总共有65536总颜色值。
但是,这里有个缺点,除非图片是矩形的,并且没有透明像素。所以RBG565格式比较适合背景图片和一些矩形的用户控件。
RBG5A1格式使用一位颜色来表示alpha通道,因此图片可以拥有透明区域。只是,1位似乎有点不够用,它只能表示32768种可用颜色值。而且图片
要么只能全部是透明像素,或者全部是不透明的像素。因为一位的alpha通道的缘故,所以没有中间值。但是你可以使用fade
in/out动作来改变纹理的opacity属性。
如果你的图片包含有半透明的区域,那么RBGA4444格式很有用。它允许每一个像素值有127个alpha值,因此透明效率与RGBA8888格式的纹理差别不是很大。但是,由于颜色总量减少至4096,所以,RBGA4444是16位图片格式里面颜色质量最差的。
现在,你可以得到16位纹理的不足之处了:它由于颜色总量的减少,有一些图片显示起来可能会失真,而且可能会产生“梯度”。
使16位纹理看起来更棒
幸运的是,我们有TexturePacker.(后面简称TP)
TP有一个特性叫做“抖动”,它可以使得原本由于颜色数量减少而产生的失真问题得到改善。(TP里面有很多抖动算法,关于这些算法,读者可以参考我翻译的另一篇文章)。
特别是在拥有Retina显示的像素密度下,你几乎看不出16位与32位的纹理之间的显示差别。当然,前提是你需要采用“抖动”算法。
cocos2d默认的颜色深度将会把所有的纹理都渲染到16位的color
framebuffer里面,然后再显示到你的设备屏幕上面。既然这样,我们为什么不把所有的纹理的格式都弄成16位呢,32位又有什么用呢?反正它本来
就会渲染到16位的framebuffer上去的。这个问题有点太底层了,我不想深挖下去,而且我也不适合解释这个问题。(译者:哈哈,知之为知之,不知
为不知)
使用NPOT纹理
NOPT是“non power of two”的缩写,译作“不是2的幂”。NPOT stands for “non power of
two”. 在cocos2d1.x的时候,你必须在ccConfig.h文件中开启对NPOT的支持,但是,cocos2d
2.x就不需要了,它默认是支持NPOT的。所有3代(iphone 3GS)以后的ios设置都支持cocos2d 2.x(因为它们支持OpenGL
ES2.0),所以也都能支持NPOT纹理。
如果纹理图集(texture
atlas)使用NPOT的纹理,它将有一个具大的优势:它允许TP更好地压缩纹理。因此,我们会更少地浪费纹理图集的空白区域。而且,这样的纹理在加载
的时候,会少使用1%到49%左右的内存。而且你可以使用TP强制生成NPOT的纹理。(你只需要勾选“allow free size”即可)
为什么要关心NPOT呢?因为苹果的OpenGL驱动有一个bug,导致如果使用POT的纹理,则会产生额外33%的内存消耗。
默认使用PVR格式的纹理
TP让你可以创建PVR格式的纹理。除了PVR纹理支持NPOT外,它们不仅可以不是2的幂,而且还可以不是方形的。
PVR是最灵活的纹理文件格式。除了支持标准的未压缩的RGB图片格式外,支持有损压缩的pvrtc格式。另外,未压缩的pvr格式的纹理的内存消耗非常
地低。不像png图片那样要消耗2倍于本身内存占用大小的内存,pvr格式只需要消耗纹理本身内存大小再加上一点点处理该图片格式的内存大小。
pvr格式的一个缺点就是,你不能在Mac上面打开查看。但是,如果你安装了TP的话,就可以使用TP自带的pvr图片浏览器来浏览pvr格式的图片了。(强烈建议大家购买TP,支持TP,不要再盗版了)
使用PVR格式的文件几乎没有缺点。此外,它还可以极大地提高加载速度,后面我会解释到。
使用pvr.ccz文件格式
在三种可选用的pvr文件格式中,优先选择pvr.ccz格式。它是专门为cocos2d和TP设计的。在TP里面,这是它生成的最小的pvr文件。而且pvr.ccz格式比其它任何文件格式的加载速度都要快。
当在cocos2d里面使用pvr格式的纹理时,只使用pvr.ccz格式,不要使用其它格式!因为它加载速度超快,而且加载的时候使用更少的内存!
当视觉察觉不出来的时候,可以考虑使用PVRTC压缩
PVR纹理支持PVRTC纹理压缩格式。它主要是采用的有损压缩。如果拿PVRTC图片与JPG图片作对比的话,它只有JPG图片中等质量,但是,最大的好处是可以不用在内存里面解压缩纹理。
这里把32位的png图片(左边)与最佳质量的PVRTC4(4位)图片(点击图片查看完整的大小)作对比:
注意,在一些高对比度的地方,明显有一些瑕疵。有颜色梯度的地方看起来还好一点。
PVRTC肯定不是大部分游戏想要采用的纹理格式。但是,它们对于粒子效果来说,非常适用。因为那些小的粒子在不停地移动、旋转、缩放,所以你很难看出一些视觉瑕疵。
PVRTC压缩图片格式
TP提供的PVR格式不仅有上面两种,还包括TC2和TC4这两种没有alpha通道的格式。
这里的alpha和16位纹理的alpha是一样的。没有alpha通道意味着图片里面没有透明像素,但是,更多的颜色位会用来表示颜色,那么颜色质量看起来也会更好一些。
有时候,PVRTC图片格式指的是使用4位或者2位颜色值 ,但是,并不完全是那样。PVRTC图片格式可以编码更多的颜色值。
预先加载所有的纹理
就像标题所说,尽你所能,一定要预先加载所有的纹理。如果你的所有的纹理加起来不超过80MB内存消耗的话(指的是拥有Retina显示的设备,非Retina的减半考虑),你可以在第一个loading场景的时候就全部加载进来。
这样做最大的好处在于,你的游戏体验会表现得非常平滑,而且你不需要再担心资源的加载和卸载问题了。
这样也使得你可以让每一个纹理都使用合适的纹理像素格式,而且可以更方便地找出其它与纹理无关的内存问题。因为如果与纹理有关,那么在第一次加载所有的纹
理的时候,这个问题就会暴露出来的。如果所有的纹理都加载完毕,这时候再出现内存问题,那么肯定就与纹理无关了,而是其它的问题了。
如果你知道问题与纹理无关的话,那么你查找剩下的内存问题将会变得更加简单。而且你避免了前面说的这种情况:当2048*2048的纹理加载的时候,它本
来只需要消耗16MB内存,但是短时间会冲到32MB内存。后面会提出一种方法来解决“间歇性内存飙高”(“译者发明滴”)的方法。(译者:希望下次开发
者的对话中“间歇性内存飙高”的说法会出现,呵呵)
按照纹理size从大到小的顺序加载纹理
由于加载纹理时额外的内存消耗问题,所以,采用按纹理size从大到小的方式来加载纹理是一个最佳实践。
假设,你有一个占内存16MB的纹理和四个占用内存4MB的纹理。如果你首先加载4MB的纹理,这个程序将会使用16MB的内存,而当它加载第四张纹理的
时候,短时间内会飙到20MB。这时,你要加载16MB的那个纹理了,内存会马上飙到48MB(4*4 + 16*2),然后再降到32MB(4*4 +
16)。
但是,反过来,你先加载16MB的纹理,然后短时候内飙到32MB。然后又降到16MB。这时候,你再依次加载剩下的4个4MB的,这时,最多会彪到(4*3 + 4*2 + 16=36)MB。
在这两种情况下,内存的峰值使用相差12MB,要知道,可能就是这12MB会断送你的游戏进程的小命哦!
避免在收到内存警告消息的时候清除缓存
我有时候看到了一种奇怪的“自己开枪打自己的脚”的行为:纹理已经全部在Loading场景里面加载完毕了,这时候,内存警告发生了,然后cocos2d就会把没有使用的纹理从缓存中释放掉。
听起来不错,没有使用到的纹理都被释放掉了,但是!。。。
你刚刚把所有的纹理都加载进来,还没有进入任何一个场景中(此时所有的纹理都被当作“unused”),但是马上被全部从texture
cache中移除出去。可是,你又需要在其它场景中使用它们。怎么办?你需要接着判断,如果有纹理没有加载,就继续加载。但是,一加载,由于“间歇性内存
飙高”,又马上收到了内存警告,再释放,再判断,再加载。。。。
我的天,这是一个死循环啊!这也能解释为什么有些童鞋,在loading场景完了之后进入下一个场景 的时候很卡的原因了。
现在,当我收到内存警告的时候,我的做法是----什么也不做。内存警告仍然在发生,但是,它只是在程序刚开始加载的时候。我知道这是为什么,因为“间歇
性内存飙高”嘛,所以,我不去管它。(但是,如果是游戏过程中再收到内存警告,你就要注意了,因为这时候可能你有内存泄漏了!!!)
我有时候会想办法改善一下,通过移除掉一些不使用的纹理和一些只有在很特殊的场景才会使用的图片(比如settings界面,玩家是不经常访问的)。然
后,不管什么时候,当我需要某张图片的时候,我会首先检查一下该sprite
frame是否在cache中,如果没有就加载。你会在后面看到具体的做法。
理解在什么时候、在哪里去清除缓存
不要随机清除缓存,也可以心想着释放一些内存而去移除没有使用的纹理。那不是好的代码设计。有时候,它甚至会增加加载次数,并多次引发“间歇内存飙高”。分析你的程序的内存使用,看看内存里面到底有什么,以及什么应该被清除,然后只清除该清除的。
你可以使用mpCachedTextureInfo方法来观察哪些纹理被缓存了:
[[CCTextureCache sharedTextureCache] mpCachedTextureInfo];
2. 求cocos2d-x大神,这个ccBlendFunc怎么用
因为这个函数不是用来去黑底的,而是用来正片叠底的。
想要有效果就必须在HelloWorld.png下面再加一张不是黑色的背景图。
比如这样:
CCSprite*bg=CCSprite::create("bg.png");//白色或其他颜色的背景,黑色的会没效果
bg->setPosition(ccp(240,160));
this->addChild(bg,0);
CCSprite*p=CCSprite::create("HelloWorld.png");
p->setPosition(ccp(240,160));
this->addChild(p,1);
ccBlendFunccb={GL_ONE,GL_ZERO};
p->setBlendFunc(cb);
3. 开发iphone的游戏时,怎么把游戏背景设置自己想要的图片求代码参考
lz用什么引擎的?cocos2d?如果是的话就是加载一幅与游戏区域等大小的图片即可 。
那更简单了,别用导航栏,同时隐藏状态栏,弄一个imageView弄的和游戏场景一样大,加载一个图片放到最底层就好了
回复 zhuxurong123:这个就要用到touchesmoved(好像叫这个,你看看api)。通过这个方法的参数可以获得手指在屏幕上的位置,每次手指移动都会调用这个方法。在这个方法里记录下每次手指的位置然后对你想要移动的uiview或其子类创建一个移动动画(在动画开始前记得停止本view的所有动画,否则移动路径就乱了),这样做可以做出view跟随手指移动的效果,或者更简单一点,通过手指位置坐标点直接设置view坐标,也可以达到view随手指移动的效果
#pragma mark - Finger Move View
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray *pointArray = [touches allObjects];
UITouch *touch = [pointArray objectAtIndex:0];
CGPoint pointInView = [touch locationInView:self.view];
self.curView.center = pointInView;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray *pointArray = [touches allObjects];
UITouch *touch = [pointArray objectAtIndex:0];
CGPoint pointInView = [touch locationInView:self.view];
self.curView.center = pointInView;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView *newView = [[UIView alloc] initWithFrame:CGRectMake(0.f, 0.f, 60.f, 60.f)];
newView.backgroundColor = [UIColor orangeColor];
self.curView = newView;
[self.view addSubview:newView];
newView = nil;
}
4. 如何使用cocos2d制作一个太空射击游戏
在这个教程里面,你将会学习到如何开发一个太空射击游戏!
你可以使用加速计(重力感应)来控制飞船的移动,并且可以点击屏幕来发射激光武器。
如果你对于如何制作基于cocos2d-x3.0的游戏完全陌生的话,这个教程可以帮助你!你将会学习到,如何从头至尾构建一个完整的游戏,不需要任何的经验!
假如你对cocos2d-x3.0编程完全陌生的话,那么你可能需要先学习一下相关的教程了。
这个教程对于中级开发者来说也非常好,因为它覆盖了一些比较高级的主题,比如视差滚动(parallax scrolling),预分配Node,加速计移动以及粒子系统的使用。
话不多说,直入主题!
添加相关资源文件
为了做这样一个手机游戏,你将需要一些跟太空主题相关的图片资源和声音资源。
你可以直接下载我老婆制作的太空游戏资源。
因此,请直接下载吧,并且把它解压到你的项目的Resources目录下面去。
如果你很好奇,你可以随便看看你刚刚向工程里面添加进去了一些什么东西。下面是完整的内容列表:
Backgrounds: 一些背景图片,你等下会使用它们来制作一个滚动背景。里面包含星系,太阳,和空间异常(它移动速度比较慢),还有一组空间尘埃图片(它们会出现在背景前面,而且会移动地稍微快一点)
Fonts: 使用 Glyph Designer制作的位图字体,我们将使用这些字体来在游戏中显示文字。
Particles: 使用 Particle Designer制作的一些特殊的粒子效果。 在这里,我们用来创建星星飞动的效果。
Sounds: 一些与太空相关的背景音乐和音效。使用 Garage Band 和 cxfr制作的。
Spritesheets: 一张格式为pvr.ccz的大图片,里面包含了游戏中将要用到的许多小图片,比如陨石,太空船等。这个文件使用 Texture Packer制作的---如果你想使用pvr.ccz文件格式的话,你可能就需要使用这个工具。当然pvr.ccz格式的优点就是文件小,加载速度快。
如果你还没安装上面任何一款工具的话,也不用担心!对于这个教程来说,你完全不需要他们,你可以使用我已经制作好的这些资源就够了。以后,如果有条件,你可以再去试试上面提到的工具。
你可能会奇怪,为什么要把所有的这些图片都弄成这样一张大图呢?因为,首先,它可以帮助节省内存,同时还可以提高性能。
接下来,让我们开始coding吧!:)
添加一个太空船
首先,让我们在屏幕上添加一艘太空船吧!
让我们试试,看是否工作!打开HelloWorld.h,在HelloWorld类开头加入下面代码(在已有public:行的上面)
SpriteBatchNode *_batchNode;
Sprite *_ship;
上面的代码创建了两个私有实例变量 – 一个是SpriteBatchNode,一个是太空飞船精灵。
现在切换到HelloWorldScene.cpp,在init()方法里,删除从注释“2. add a menu item”到方法最后的所有代码,加入下面代码:
_batchNode = SpriteBatchNode::create("Sprites.pvr.ccz"); // 1
this->addChild(_batchNode); // 2
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("Sprites.plist"); // 3
_ship = Sprite::createWithSpriteFrameName("SpaceFlier_sm_1.png"); // 4
auto winSize = Director::getInstance()->getWinSize(); // 5
_ship->setPosition(Point(winSize.width *0.1, winSize.height *0.5)); // 6
_batchNode->addChild(_ship,1); // 7
注意这些代码与你过去使用的Objective-C版的cocos2d 非常类似。API是有很多相同的地方的,仅仅是有一些与C++的语法不同。
编译运行,你应该可以看到你的船出现在屏幕上
增加视差滚动
接下来,我们会加入宇宙背景,使它以视差滚动这种很酷的方式来滚动。
首先,我们不得不在所有的类名前面加上cocos2d::这个名字空间,这太烦人了!所以在HelloWorld.h类声明前加入下面行:
USING_NS_CC;
接着在HelloWorld的private部分加入一些新的变量(注意我们不再需要加cocos2d前缀):
ParallaxNodeExtras *_backgroundNode;
Sprite *_spacest1;
Sprite *_spacest2;
Sprite *_planetsunrise;
Sprite *_galaxy;
Sprite *_spacialanomaly;
Sprite *_spacialanomaly2;
然后,在HelloWorldScene.cpp的init方法中,return语句前加入下面代码:
// 1) Create the ParallaxNodeExtras
_backgroundNode = ParallaxNodeExtras::node();
this->addChild(_backgroundNode,-1);
// 2) Create the sprites we'll add to the ParallaxNodeExtras
_spacest1 = Sprite::create("bg_front_spacest.png");
_spacest2 = Sprite::create("bg_front_spacest.png");
_planetsunrise = Sprite::create("bg_planetsunrise.png");
_galaxy = Sprite::create("bg_galaxy.png");
_spacialanomaly = Sprite::create("bg_spacialanomaly.png");
_spacialanomaly2 = Sprite::create("bg_spacialanomaly2.png");
// 3) Determine relative movement speeds for space st and background
Point stSpeed = Point(0.1, 0.1);
Point bgSpeed = Point(0.05, 0.05);
// 4) Add children to ParallaxNodeExtras
_backgroundNode->addChild(_spacest1,0,stSpeed,Point(0, winSize.height / 2));
_backgroundNode->addChild(_spacest2,0,stSpeed,Point(_spacest1->getContentSize().width, winSize.height / 2));
_backgroundNode->addChild(_galaxy, -1, bgSpeed,Point(0, winSize.height *0.7));
_backgroundNode->addChild(_planetsunrise, -1, bgSpeed,Point(600, winSize.height * 0));
_backgroundNode->addChild(_spacialanomaly, -1, bgSpeed,Point(900, winSize.height *0.3));
_backgroundNode->addChild(_spacialanomaly2, -1, bgSpeed,Point(1500, winSize.height *0.9));
编译运行,你应该可以看到一个宇宙场景的启动
而,这还不是很有趣,因为还没有任何东西在动!
为了移动太空尘埃和相关背景层,你只需要移动一样东西就可以了,ParallaxNodeExtras。对于移动parallax node的每一个y值,灰尘就会移动0.1y值,同时背景会移动0.05y值。
为了移动parallax节点,你只需要飞一帧更新一下它的位置就可以了。打开HelloWorldLayer.m文件,加入下列的代码:(添加位置注意看注释)
this->scheleUpdate();
void HelloWorld::update(float dt)
{
Point backgroundScrollVel = Point(-1000, 0);
_backgroundNode->setPosition(_backgroundNode->getPosition()+backgroundScrollVel*dt);
}
编译并运行工程,你会看到,使用parallax来做视差滚动效果真是太简洁了!
5. cocos2djs 怎样创建imageview
本节我们会通过一个实例介绍纹理对象创建Sprite对象使用,这个实例如图5-2所示,其中地面上的草是放在背景(如下图所示)中的,场景中的两棵树是从后图所示的“树”纹理图片中截取出来的,图5-5所示是树的纹理坐标,注意它的坐标原点在左上角。
创建Sprite对象实例
场景背景图片
“树”纹理图片
“树”纹理图片
下面我们看看app.js 中HelloWorldLayer中初始化代码如下:
var HelloWorldLayer = cc.Layer.extend({
ctor:function () {
this._super();
var size = cc.director.getWinSize();
var bg = new cc.Sprite(res.background_png); ①
bg.x = size.width/2;
bg.y = size.height/2;
this.addChild(bg);
var tree1 = new cc.Sprite(res.tree_png,cc.rect(604, 38, 302, 295)); ②
tree1.x = 200;
tree1.y = 230;
this.addChild(tree1);
var texture = cc.textureCache.addImage(res.tree_png); ③
var tree2 = new cc.Sprite(texture, cc.rect(73, 72,182,270)); ④
tree2.x = 500;
tree2.y = 200;
this.addChild(tree2);
}
});
在上面代码第①行通过图片创建精灵,变量res.background_png是图片的完整路径,它是在resource.js文件中定义的,它代表的图片是background.png,background.png图片如图5-3所示。第②行代码是通过tree1.png图片(res.tree_png变量保存的内容)和矩形裁剪区域创建精灵,矩形裁剪区域为(604, 38, 302, 295),如图所示。
rect类可以创建矩形裁剪区,rect构造函数如下:
rect (x, y, width, height)
其中x,y是UI坐标,坐标原点在左上角,width是裁剪矩形的宽度,height是裁剪矩形的高度。
第③行代码把tree1.png图片添加到纹理缓存中,第④行代码是通过指定纹理和裁剪的矩形区域来创建精灵。
资料由:成都点点通软件开发公司提供!
6. 谈谈对quick-cocos2d-x和cocos2d-x lua的区别理解
下面简单举个例子吧,还是显示经典的HelloWorldScene中那张背景图片,如果我们在quick中使用原生lua的写法,就和使用C++写一样
function MainScene:ctor()
self.size = CCDirector:sharedDirector():getWinSize()
local sp = CCSprite:create("HelloWorld.png")
sp:setPosition(ccp(self.size.width/2, self.size.height/2))
self:addChild(sp)
end
需要这样些语句才能完成,不过用quick提供的API,那么就简单太多了,真的感动的要哭
function MainScene:ctor()
local sp = display.newSprite("HelloWorld.png", display.cx, display.cy)
self:addChild(sp)
end
就这些,是不是太方便,对于坐标的提供大大简化了需求,32个赞!
下面说一说对于quick的学习方法吧,我觉得C++那一套编写游戏的方法你掌握的话,对于lua开发游戏难度到并不是太大,毕竟相应的函数方法都是有的,困难之处在于怎么使用lua的方式写出来,比如一个触摸响应事件,如果用quick提供的方式写出来,这就需要好好看看API了,当然quick提供的在线API还不是很完整,有些地方还是不太详细的,所以看sample是另一个途径了,quick里面提供了大量的sample,这对于我们来说比任何资源都重要。一旦把这些基础的用法掌握了,可以看看那个CoinFlip这个完整的游戏示例,我觉得这样一来差不多自己就能用quick开发游戏了。
7. cocos2d加载程序时的那个背景图片如何添加,那个背景图片在给定的plist文件里
cocos2d加载程序时的那个文件是一个命名为Default.png的图片,你可以命名一个同名图片去覆盖它。
通常游戏的开始画面可能不仅仅是一张图片,加载了。
我不记得是cocos2d哪个版本了,在AppDelegate文件里有一个removeStartupFlicker方法,里面注释着以下内容
- (void) removeStartupFlicker
{
//
// THIS CODE REMOVES THE STARTUP FLICKER
//
// Uncomment the following code if you Application only supports landscape mode
//
#if GAME_AUTOROTATION ==
//CC_ENABLE_DEFAULT_GL_STATES();
//CCDirector *director = [CCDirector sharedDirector];
//CGSize size = [director winSize];
//CCSprite *sprite = [CCSprite spriteWithFile:@"Default.png"];
//sprite.position = ccp(size.width/2, size.height/2);
//sprite.rotation = -90;
//[sprite visit];
//[[director openGLView] swapBuffers];
//CC_ENABLE_DEFAULT_GL_STATES();
#endif // GAME_AUTOROTATION ==
}
把CCSprite *sprite = [CCSprite spriteWithFile:@"Default.png"];
在这里你可以取你plist里的那个图片路径来显示它
当然,通常的做法是自己创建一个初始画面的类,不去显示Default.png,自己在类里面做这个初始画面,是淡入淡出也好,甚至播动画也好,都可以自己把控。要记得把初始场景设为它。
8. 如何使用cocos2d
cocos2d是一个非常强大的开源库,它可以为你开发iphone上面的游戏节省大量的时间。目前支持精灵(sprite)、动画、物理引擎、声音引擎以及许许多多非常酷的图像效果等等。
我也是刚开始学习cocos2d,目前已经有许多非常好的教程来教你如何使用cocos2d了。但是,那些都不是我想要的。我真正想要的是一个非常简单,但是可以跑起来的游戏。这个游戏包括怎么使用动画、碰撞检测和播放声音,这就够了,并不需要使用太多高级的特性。最终,我自己做了一个这样的游戏,因此,基于我的一些经验写了这篇教程,希望会对初学者有所帮助。
这篇教程将会从头至尾、一步一步地教你如何使用cocos2d来制作一个简单的iphone游戏。你可以按照教程一步步来,或者干脆直接跳到文章的最后,下载样例程序。没错!游戏里面有忍者。
下载并安装cocos2d
你可以从下面的链接来下载cocos2d的最新版本(以前是google,现在采用git了) the Cocos2D Google Code page.
在你下载完代码以后,你可能想安装非常有用的项目模板。打开终端窗口,然后cd到你的cocos2d解压缩目录下面,输入./install_template.sh
请注意,你可以传递一些参数给这个安装脚本,比如你把xcode安装在了一个非标准的目录下面。(或者你有多个版本的sdk安装在你的机器上面)
Hello, Cocos2D!
让我们从最简单的HelloWorld项目开始吧!启动xcode,点file->new project,然后选择cocos2dApplicationtemplate来创建一个新的cocos2d项目并把它命名为“Cocos2dSimpleGame”
继续,点编译并运行这个工程模板,如何一切都ok的话,那么你会看到下面的内容:
cocos2d是按照“场景”(scene)的概念组织的,对一个游戏来说,就好像某个关卡或者屏幕之类的。比如,你可能需要一个场景来为你的游戏建立初使化菜单界面,另外一个场景当作玩游戏的主要界面,还有一个游戏结束的时候的界面。在一个场景里面,你可以有许多“层”(layer)(这个和photoshop有点类似)。每一个层又可以包含一些结点,比如精灵、标签、菜单等。而且一个结点也可以包含其它的结点。(比如,一个精灵可以包含一个子精灵)
如果你看一下样例工程,你会看到只有一个场景HelloWorldScene--我们接下来将会在这个场景里面实现我们的游戏逻辑。继续打开它,你会在init方法里面看到,它把一个带有“HelloWorld”字样的标签加到了当前场景中。我们将把这些代码去掉,并且放一个精灵在上面。
增加一个精灵
在我们增加一个精灵之前,我们需要一些图片。你可以自己去创建一些,或者使用我可爱的妻子为这个项目所创建的图片: a Player image, a Projectile image, and a Target image.
一旦你获得了这些图片,你就可以把它们用鼠标拖到xcode的resource文件夹中去,并且保证“ Copy items into destination group’s folder (if needed)”勾上了。现在,我们拥有自己的图片了,我们先得计算一下,应该把player放在哪里。请注意,cocos2d坐标系的原点在屏幕的左下角,即(0,0)位置在左下角,这与一般的窗口坐标系统在左上角有所区别。x方向往右是正,y方向往上是正。由于项目是landscape(横版)模式,这就意味着右上角的坐标是(480,320)。
还有需要注意的是,当我们设置一个对象的位置的时候,这个位置是相对于所加精灵的中心点来加的。因此,如果我们想让我们的player精灵与屏幕的左边界水平对齐,并且垂直居中的话。
那么对于x轴:我们需要设置为[player sprite's width]/2。y坐标设置为[window height]/2。
下面有一张图,可以更加清楚一些:
好,让他开始射击吧!打开Class文件夹并点击HelloWorldScene.m,然后把init方法用下面的代码替换掉:
复制代码
-(id) init
{
if( (self=[super init] )) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *player = [CCSp www.hbbz08.com rite spriteWithFile:@"Player.png"
rect:CGRectMake(0, 0, 27, 40)];
player.position = ccp(player.contentSize.width/2, winSize.height/2);
[self addChild:player];
}
return self;
}
复制代码
编译并运行,你的精灵这时候应该出现在正确的位置上了。但是,这个前景默认是黑的。对于这张忍者图片来说,白色的背景可能看起来更好一些。在cocos2d里面,有一种非常简单的方式来改变层的背景颜色,那就是使用CCColoredLayer类。好,跟我来吧!点击HelloWorldScene.h,然后把HelloWorld接口声明改成下面这样:
@interface HelloWorld : CCColorLayer
然后点击HelloWorldScene.m文件,在init方法里面做一些小小的修改,以便使我们能把层的背景颜色改成白的:
9. cocos2d怎么使用texture素材
我使用张图片给我历图片添加边框种带波纹效边框四边形张图片透明部遮罩效部白色区域则历图片显示区域
实现效我使用OpenGL混合模式
看《何使用CCRenderTexture态创建纹理》篇教程我讨论OpenGL混合模式我提非便线工具用见化调节混合模式效
完我想要效我需要采取面策略:
我首先渲染mask精灵src color(mask精灵)设置GL_ONE并且destination
color(空buffer)设置GL_ZERO所效简单mask图片显示
接我渲染历图片精灵src
color(历)设置GL_DST_ALPHA意思看看mask图片前alpha值少0(完全透明)显示mask1(完全透明)显示历图片(译者注:家明白参考链接)dst
color(the mask)设计GL_ZERO前渲染mask消失
酷吧能觉我需要先mask精灵渲染再渲染历精灵并且指定两精灵blendFunc行实际行通
面所提混合算精灵面些精灵渲染候问题---比背景图片面精灵作假设面做完1步骤imgae
buffer面存唯张图片mask(假设确啦要切换历图片)
我需要种式建立干净黑板执行12步制作遮罩纹理幸运用RenderTexture非便
Masking
and CCRenderTexture]
RenderTexture类让屏幕外buffer面渲染
用起非便主要原---使用给游戏截屏高效缓存用户渲染内容运行态创建sprite
sheet或者像本教程制作mask sprite
使用RenderTexture需要采取4步:
创建RenderTexture类像素单位指定想要绘制纹理宽度高度
调用RenderTexturebegin初始化渲染操作
调用OpenGL函数绘制实际内容--些OpenGL调用终都绘制屏幕外影响游戏现渲染图像
调用RenderTextureend结束绘制操作旦完RenderTexturesprite属性用Sprite用
要觉第3步奇怪---使用Cocos2d90%情况需要手直接调用OpenGL函数想渲染节点直接调用某节点visitsprite->visit函数自发射些OpenGL函数指针给图形硬件显示
点需要注意坐标问题(00)点渲染纹理左角位置所使用RenderTexture候定要坐标设置
能听些烦程序员喜欢看代码让我始coding吧
给精灵添加遮罩: 终实现
打HelloWorldScene.minit面添加面注意静态文件声明需要注意:
//a static method
Sprite* HelloWorld::maskedSpriteWithSprite(Sprite* textureSprite, Sprite* maskSprite)
{
// 1
RenderTexture * rt = RenderTexture::create( maskSprite->getContentSize().width,
maskSprite->getContentSize().height );
// 2
maskSprite->setPosition(maskSprite->getContentSize().width/2,
maskSprite->getContentSize().height/2);
textureSprite->setPosition(textureSprite->getContentSize().width/2,
textureSprite->getContentSize().height/2);
// 3
maskSprite->setBlendFunc( BlendFunc{GL_ONE, GL_ZERO} );
textureSprite->setBlendFunc( BlendFunc{GL_DST_ALPHA, GL_ZERO} );
// 4
rt->begin();
maskSprite->visit();
textureSprite->visit();
rt->end();
// 5
Sprite *retval = Sprite::createWithTexture(rt->getSprite()->getTexture());
retval->setFlippedY(true);
return retval;
}
让我步步解面操作:
使用mask精灵创建CCRenderTexture
重新设置mask精灵texture精灵位置使左角(00)
按照我前讨论设置每精灵blendFunc
调用CCRenderTexturebegin始渲染操作依渲染masktexture精灵调用end
基于CCRenderTexturesprite属性texture创建新精灵同翻转y纹理创建倒
接我使用面函数制作遮罩效:
//cal->setPosition(visibleSize.width/2, visibleSize.height/2);
Sprite * mask = Sprite::create("CalendarMask.png");
Sprite * maskedCal = maskedSpriteWithSprite(cal, mask);
maskedCal->setPosition(visibleSize.width/2, visibleSize.height/2);
//pRet->addChild(cal);
pRet->addChild(maskedCal);
编译并运行