cocos2d基础知识
第3章 基础知识
3.1 cocos2d中的单件类
cocos2d充分利用了Singleton设计模式。从理论上来讲,单件(Singleton)就是一个普通的类,但它在应用程序的整个生命周期中只被实例化一次。为了确保这一点,cocos2d采用静态方法来创建并访问这个对象实例。所以,要访问单件对象,不应使用alloc/init或静态的自动释放初始化器,而应该调用以shared开头的方法。
单件的好处在于它可以在任何地方被任何类使用。可以把它理解为一个全局类(可参照“全局变量”的概念来加深理解)。如果在很多不同的地方需要使用同一组数据和方法,那么这时候单件就非常有用。
在你创建一个单件类之前,务必要考虑清楚,对于这个类以及它的数据,是否真的只需要一个实例?这个设计以后是否会发生变化?
3.2 Director类
CCDirector类(简称为Director)是整个cocos2d游戏引擎的核心。Director被设计为单件,这个设计是非常合理地:它存储了cocos2d中大量的全局配置信息,而且管理这所有的cocos2d场景。
Director的主要用途包括:
1)切换场景
2)存储cocos2d配置信息
3)访问视图(OpenGL、UIView、UIWindow)
4)暂停、恢复以及终止游戏
5)在UIKit和OpenGL之间转换坐标
事实上,一共有4中Director可供选择,但它们之间只有细微的差别。最常用的一种是CCDisplayLinkDirector,它的内部采用苹果公司官方的CADisplayLink类来实现。这是一个很好的选择,但它只在iOS3.1或更高的版本上可用。另一种选择是,可以使用CCFastDirector。如果想同时使用cocos2d和Cocoa Touche视图,就必须使用CCThreadedFastDirector,因为只有它可以支持cocos2d和Cocoa Touch视图。CCThreadedFastDirector的缺点在于耗电量比较大,如果你非常注重这一点,那么应选用CCTimerDirector。不过,不要万不得已,最好不要用它,因为它是所有Director中最慢的一个。
3.3 场景图
场景图有时也称为场景层次体系,是一个由所有处于活动状态的cocos2d节点构成的层次体系。除了场景以外,每个节点只有一个父节点,同时可以拥有任意个数的子节点。
当向节点添加其他节点时,就是在构建一个节点场景图。在场景图中,对某个节点采取的大多数操作会同时影响到它的所有子节点。
3.4 CCNode类层次体系
所有节点都有一个公共父节点类——CCNode,它定义了除节点显示外的多数公共属性和方法。
3.5 CCNode类
CCNode是所有节点的基类。它是一个没有具体显示的抽象类,仅用于定义所有节点的公共属性和方法。
3.5.1 节点的处理方式
CCNode类实现了添加、获取以及删除子节点的所有方法。
addChild方法中的参数”z”决定了节点的绘制顺序。首先绘制z值最低的节点,最后绘制z值最高的节点。如果多个节点拥有相同的z值,就按照添加它们的先后顺序进行绘制。当然,这只对有具体显示的节点(比如精灵)有效果。
tag参数保证了你在使用getChildByTag方法时能够区分并获取特定节点。
注意:
如果多个节点拥有相同的标记值,getChildByTag方法将返回最先匹配该标记值的节点,其他拥有该标记值的节点就不可能再被访问到了。所以,确保每个节点的标记值都是唯一的。
而且,动作也是可以有标记值的。节点和动作的标记值互相不会产生影响,所以,某个节点与某个动作的标记值相同不会产生任何问题。
3.5.2 动作的处理方式
动作是指在特定时间内完成移动、旋转、缩放以及其他操作的一些行为。
3.5.3 消息调度
节点可以对消息进行调度,其实就是指Objective-C中每隔一段时间调用一次方法。
要使特定的更新方法以每帧的频率被调用一次,最简单的做法如下所示:
-(void) scheduleUpdates
{
[selfscheduleUpdate];
}
-(void) update:(ccTime) delta
{
//每帧调用的代码
}
注意,更新方法是有固定格式的,也就是说,它永远是像示例代码这样定义的。参数delta代表了该函数自上次被调用到现在所经过的时间。
如果想调用另一个方法,或者不想以每帧的频率(而是以每0.1秒的频率)调用该方法,就应该采用以下做法:
-(void) scheduleUpdates
{
[selfschedule:@selector(updateTenTimePerSecond:)interval:0.1f];
}
-(void) updateTenTimePerSecond:(ccTime) delta
{
//该方法将根据其设定的时间间隔,每秒钟调用十次
}
注意,如果interval的值为0,还是应该用scheduleUpdate方法。但是,加入之后需要取消一个定时方法的调用,最好还是采取上面的做法,因为scheduleUpdate做不到这一点。
注意:@selector(...)中的冒号数一定要与所指定方法的参数个数相同。假设有如下方法:
-(void) example:(ccTime)delta sender:(id) sender flag:(bool) aBool
那么对应的@selector语句就应该是:
@selector(example:sender:flag:)
不论在调度消息时还是在其他情况下使用@selector(...),都需要注意一个很重要的问题,在默认情况下,如果方法名不存在,编译器并不会报错;但是,一旦程序运行时调用了指向不存在方法的aselector语句,应用程序就会立即崩溃。 要使节点中所有用选择器选定的方法(包括使用scheduleUpdate指定的方法)停止,可使用:
[self unscheduleAllSelectors];
要使某个用特定选择器选定的方法停止(假设选择器名为“updateTenTimePerSecond”),可使用:
[self unschedule:@selector(updateTenTimePerSecond:)];
注意,该做法不会令使用scheduleUpdate指定的更新方法停止。
更新方法以优先级从低到高的顺序被调用。scheduleUpdate的默认优先级为0。
3.6 场景和层
与CCNode类似,CCScene和CCLayer类也没有具体显示。它们通常仅供内部使用,作为场景图起点的抽象概念。所谓场景图,就是一个以CCScene为根节点的继承体系。CCLayer通常是用来组织节点的一个单元,而且只要进行了相关设置,它还可以用来接收触摸输入以及加速计输入。
3.6.1 CCScene
一个CCScene对象往往是场景图中的第一个节点。通常来说,CCScene节点的第一层子节点一定是CCLayer的子类。游戏中的各个对象总是由这些子节点来保存,而不是由父节点CCScene保存。由于场景对象本身通常不包含有任何游戏相关代码,而且它很少被子类化,因而它往往是用CCLayer对象中的静态方法“+(id) scene”来创建的。
3.6.2 场景和内存
注意:当进行场景切换时,cocos2d会把自己占用的内存清理感觉。它会删去所有节点,停止所有动作,并且对所有用选择器选中的方法取消调度。
绝对不要把节点添加为场景图的子节点,然后再去保留它。可以用cocos2d提供的方法来获取这些节点对象,或者宁愿使用一个弱引用去指向这个节点,也不要保留它。只要把内存管理的问题丢给cocos2d,你就是安全的。
3.6.3 推进和弹出场景
pushScene和popScene用来在不是法旧场景内存的情况下运行新场景,旨在加快场景替换的速度。
3.6.4CCTransutionScene
场景过度就是任何从CCTransitionScene继承的类,它们可以让游戏看起来很专业。
可以把CCTransitionScene与replaceScene和pushScene结合起来使用,但是,千万不要将过渡效果和popScene一起使用。
cocos2d中可供使用的过渡效果:
1)CCFadeTransition:淡入淡出到一个指定颜色的背景,然后恢复。
2)CCFadeTRTransition(还有其他3种版本):瓦片翻转,渐渐显示新场景。
3)CCJumpZoomTransition:旧场景弹跳着缩小,新场景弹跳着放大。
4)CCMoveInLTransition(还有其他3中版本):旧场景移出,同时新场景从任意方向移入。
5)CCOrientedTransitionScene(还有其他6种版本):整个场景都会翻转过来。
6)CCPageTurnTransition:翻页效果。
7)CCRotoZoomTransition:旧场景边旋转边缩小,新场景边旋转边放大。
8)CCShrinkGrawTransition:旧场景缩小,新场景在旧场景继承上放大。
9)CCSlideInLTransition(还有其他3种版本):新场景从各个方向掠过旧场景。
10)CCSplitColsTransition(还有另一种版本):旧场景切成竖条,从上方或下方散开,新场景显现。
11)CCTurnOffTilesTransition:新场景呈瓦片状替代旧场景。
3.6.5 CCLayer
与场景一样,层是没有维度的。层的本质是对节点进行分组。当需要对一组对象施加相同的动作或行为时,可以用层很方便地达到这个效果。
注意:你可以使用任意多的层,与其他节点相比,它们对于性能并没有特别大的影响。不过,如果层能够接收用户输入,情况就有所变化了。因为接收触摸或加速计事件的开销是很大的。所以,不要用太多层来接收触摸或加速计输入。可以只用一个层来接收和处理这些输入,然后在必要的情况下,通过这个层将输入事件通知给其他节点或类。
1.接收触摸事件
CCLayer类是被设计为可以接收触摸输入的,但是需要显式地启用这个功能,可以通过将isTouchEnable属性设为YES来实现。
由于触摸事件是由Cocoa TouchAPI接收的,因此一定要把触摸位置转换为OpenGL坐标。
默认情况下,层接收到的事件和苹果公司的UIResponder类类似。cocos2d也支持有针对性的触摸处理。区别在于:有针对性的触摸一次只接收单点触摸,而UIResponder触摸事件总是能接收多点触摸。有针对性的触摸处理知识简单地把多指触摸分割成了独立的事件,这样可以方便你更灵活地针对游戏需求去进行处理。更重要的是,它允许你把特定的触摸事件从事件队列中移除,可以指定一个触摸事件为已处理事件,并阻止将它传送给其他层。这样以来,如果触摸集中在一块特定区域内,你就可以很快识别出来,识别并处理完以后,可以把这些触摸标记为已处理,其他层就都不会再对这个区域做检测。
2.接收加速计事件
类似于触摸输入,需要显式地启动加速计来接收加速计事件:
self.isAccelerometerEnabled=YES;
3.7 CCSprite类
CCSprite是cocos2d中最为常用的类,它用一幅图像将精灵显示到屏幕上。要创建一个精灵,最简单的方法就是为精灵指定一个图像文件,而这个图像文件会在cocos2d内部被加载到CCTexture2D类的图像资源中。为了保证图像文件能够被成功读取,必须把图像文件加到Xcode中的Resources分组下。
cocos2d中精灵的position属性指定了图像中心所在的位置。一个刚被初始化的精灵,它的位置默认为(0,0)。
警告:
iOS设备上的文件名是区分大小写的,而模拟器上的文件名并不区分大小写,所以你改用真机进行测试时,很可能因为文件名而引发程序崩溃。
3.7.1 定位点揭秘
每个节点都有anchorPoint(定位点)属性,但是这个属性只在节点需要用纹理来显示时才会发挥作用。任意节点的anchorPoint属性默认值都是(0.5,0.5)或图像尺寸的一半。可以说,它是一个乘数或因子,而并非一个确切的像素值。
anchorPoint属性仅仅决定了纹理相对于精灵节点所在位置的偏移,偏移值是由纹理的实际大小乘以anchorPoint属性的值得出的。CCSprite有一个只读的anchorPointInPixels属性,所以你不必手工计算具体的偏移值,仅在需要时修改anchorPoint属性的值即可。
注意:如果所有精灵的定位点都在屏幕左下角,那么涉及旋转、缩放、子节点相对位置、距离检查、碰撞检测等问题时,情况就会变的非常复杂。你一定会需要把定位点设置在纹理中心的。
3.7.2 纹理大小
纹理大小的问题非常值得一提。到目前位置,iOS设备只支持尺寸为“2的n次幂”的纹理,所以每张纹理的宽度和高度只可能为:2、4、8、16、32、64、128、512和1024像素,在3G设备上可能还有2048像素。纹理不是方形的,所以,即使是8*1024像素的纹理用起来也不会有任何问题。
3.8 CCLabel类
CCLabel可以帮你方便地在屏幕上显示文本。
cocos2d内部会以指定的字体作为参数创建一个CCTexture2D对象,也就是一张纹理,然后再由该纹理渲染出最后显示的文本。每次文本发生改变,就要做一次上述工作,所以最好不要频繁改变文本(比如说,不要没过一帧就改一下文本)。重建一个标签文本的纹理是非常费时的。
如果要想让文本相对于标签左对齐、右对齐、上对齐或下对齐,只须修改anchorPoint属性就可以轻松做到。
3.9 菜单
CCMenu只能接受CCMenuItem对象作为其子节点。
警告:
menuWithItems(菜单项列表)总是以nil作为最后一个参数。这是一个技术要求,如果忘记加上nil,程序可能会在这一行代码崩溃。
3.10 动作
动作时轻量级的类,可以用来让节点执行诸如移动、旋转、缩放、变色、消失等很多动作。由于它们能作用在所有节点上,因此可以对精灵、标签甚至菜单或整个场景施加动作,这就是动作的强大之处。
动作分两大类:瞬时动作基本上等同于设置节点的属性,如visible和flipX;延时动作会执行一段时间,如上面的移动动作。另外不需要清除这两种动作。一旦动作完成就会自动从节点上清除并释放发所占用的内存。
3.10.1 重复动作
可以使一个动作或一系列动作不停地重复,用这个方法可以创建无限循环的动画。
3.10.2 流畅动作
CCEaseAction类的出现使得动作显得更为强大了。流畅动作允许你改变在一段时间的动作效果。
3.10.3 动作序列
在一个动作序列中,你可以使用任意数量和类型的动作。也可以将动作序列和CCRepeatForever动作一起使用。
注意:
就像使用菜单项那样,一串动作总是以nil结尾。如果你忘记在最后一个参数位置加上nil,创建CCSequence的这行代码就会崩溃。
3.10.4 瞬时动作
瞬时动作可用于翻转节点、移动节点以及设置节点的可视性等。瞬时动作通常只是用于CCCallFunc动作。
<!--EndFragment-->