-
cocos2d基础介绍
这篇文章主要会介绍一些cocos2d的基础类,以及他们的用途。
cocos2d中,大量使用了单例(singleton)模式,单例其实就是一个普通的类,但是它在整个应用程序生命周期内只实例化一次,cocos2d中,要访问单例对象,基本上都是使用shared开头的方法(目前为止,我没有发现过有不这样使用的单例)。如果你还没看懂单例是什么,那么看看下面这个例子你就知道了。
static MyManager *shareManager = nil; +(MyManager) sharedManager { if(shareManager == nil) { shareManager = [[MyManager alloc] init]; } return shareManager; }我觉得单例应该是包含了一些公用的方法,而且调用这些方法,不会去修改单例的属性,否则其他的类来调用单例的时候,所遇到的结果就是未知的了。说完单例,我们先来说说一个重要的单例类——CCDirector。CCDiretor类是Cococs2d游戏引擎的核心,它存储了cocos2d种大量的全局配置信息,而且管理着所有的cocos2d场景。Dirctor的主要作用有一下几点:
- 切换场景
- 存储cocos2d的配置信息
- 访问试图(包含OpenGL、UIView、UIWindow)
- 暂停、恢复以及终止游戏
- 在UIKit和OpenGL之间转换坐标
- CCNode类
接下来,说说CCNode类。cocos2d中,所有的节点都继承自CNode类,它是一个没有具体显示的抽象类,仅用于定义所有的公共属性和方法。首先我们来看一下cocos文档里面列举出来的类的继承关系,可以从中发现CCScene、CCSprite都继承自CCNode,以前CCLayer也应该是继承自CCNode,但是在1.0.1的文档中查不到这个类,先记录下,等下再去查。

再来看看这个类的部分公共函数,里面包含了各种对节点的操作,增加、删除、获取节点、调度(即隔多少秒执行一次,稍后会详细说、取消调度、开始播放动作、停止动作等):
(void) - addChild: (void) - addChild:z: (void) - addChild:z:tag: (void) - removeFromParentAndCleanup: (void) - removeChild:cleanup: (void) - removeChildByTag:cleanup: (void) - removeAllChildrenWithCleanup: (CCNode *) - getChildByTag: (void) - reorderChild:z: (void) - cleanup (void) - draw (void) - visit (void) - transform (void) - transformAncestors (CGRect) - boundingBox (CGRect) - boundingBoxInPixels (CCAction *) - runAction: (void) - stopAllActions (void) - stopAction: (void) - stopActionByTag: (CCAction *) - getActionByTag: (NSUInteger) - numberOfRunningActions (void) - scheduleUpdate (void) - scheduleUpdateWithPriority: (void) - schedule: (void) - schedule:interval: (void) - unschedule: (void) - unscheduleAllSelectors (void) - resumeSchedulerAndActions (void) - pauseSchedulerAndActions - CCScene类
一个CCScene对象往往是场景图种的第一个节点。通常来说,CCScene节点的第一层子节点一定是CCLayer的子类,而CCScene对象本身,通常是利用CCLayer对象种的静态方法+(id)scene来创建,而且游戏中的各个对象,也通常是由这些子节点(CCLayer)来保存,而不是CCScene本身来保存,这样做的好处,会在CCLayer部分介绍。
1、场景类跟app建立关系上
我们可以把要显示的第一个场景,加在AppDelegate中applicationDidFinishLaunching方法的最后,类似如下:
[[CCDirector sharedDirector] runWithScene:[HelloWorld scene]];
HelloWold类是一个继承自CCLayer的类,scene是其中的一个静态方法,用来将layer加入scene里面,如下所示:
+(id)scene { CCScene *scene = [CCScene node]; CCLayer *layer = [HelloWord node]; [scene addChild:layer]; return scene; }2、内存使用
当进行场景替换的时候,cocos2d会把自己占用的内存清理干净,它会删除所有的节点,停止所有的动作,并且对所有用选择器选中的方法取消调度。但是,由于在进行场景替换时,新场景往往在旧场景释放之前就被加载到内存了,这会导致内存负荷瞬间加大,这个问题在使用场景转换动画的时候,显得格外明显。这时候,场景首先会被创建,然后过渡效果运行,一直要到过度效果运行完毕之后,旧场景才会从内存中释放。
由于场景替换的时候,会停止所有的动作,那么可否在播放场景过渡动画前先把前一个场景截屏,然后释放掉前一个场景再播放动画,这样的话,就能节省不少内存。
3、场景的推进和弹出
cocos2d种有pushScene和popScene这两个有用的方法,这两个方法用来在不释放旧场景内存的情况下运行新场景,可以加快场景替换的速度。由于很多场景可以互相叠加的存在于内存之中,很容易就会忘记弹出一个场景,或者对于同一个场景弹出太多遍。学过堆栈的同学,应该知道这种情况的危险性。但是这个用来切换setting还是不错的选择,因为setting一般都不怎么占内存,当然,特殊情况除外。
- CCTransitonScene
场景过渡动画有时候能为游戏添色不少。在cocos2d中,要使用过度动画还是比较简单的,只要在场景转换时添加两行代码就行了。比如下面这个淡入淡出效果:
CCFadeTransition *tran = [CCFadeTransition transitionWithDuration:1 scene:[HelloWorld scene] withColor:ccWHITE]; [[CCDirector sharedDirector] replaceScene:tran];CCTransitonScene定义了很多的场景转换动画,看下下面这张类图应该能很清楚的知道:

- CCLayer类
开始在CCScene里面提到过,CCLayer本质是对节点进行分组,游戏中的各个对象,一般是用CCLayer来保存的。这样的好处是,可以很轻松的修改层的属性或者在该层上运行一个动作来影响层上的所有子节点。例如你可以对某一层施加一个动作,然后这个动作会对该层上的所有对象产生影响。当然,不使用层也能达到这样的效果,只要对每个对象分别进行操作即可,但是显然,不使用层的做法是非常低效的。
CCLayer能够接收触摸事件和加速剂事件,但是接收触摸或者加速计事件的开销是很大的,这也就导致有人说使用多个层会影响性能。实际上你可以使用任意多个蹭,与其他的节点相比,他们对于性能并没有太大的影响。如果太多的层需要接收和处理触摸或者加速计事件,可以只用一个蹭来接收和处理这些输入,然后在必要的情况下,通过这个层将输入事件通知给其他节点或者类。
1、接收触摸事件
使用self.isTouchEnabled = YES来显示启动接收触摸事件,一般会在init方法中开启此功能。下面列出几个常用单点触控的触摸事件:
a)当手指接触到屏幕时被调用:
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
b)当手指离开屏幕时候被调用:
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
c)当触摸时间被取消时调用:
-(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)even
d)当手指在屏幕上移动的时候被调用:
-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
在使用单点触摸之前,要向层中添加以下方法来启用有针对性的触摸处理:
-(void) registerWithTouchDispatcher { [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INIT_MIN + 1 swallowsTouches:YES]; }CCTouchBegan返回一个bool值,如果返回YES,就意味着不想让这个触摸被传送到其他优先级更低的有针对性的触摸处理,也就相当于你直接吞噬掉了这个触摸事件。
由于触摸事件是由Cocoa Touch API接收的,因此一定要吧触摸位置转换成cocos2d所用的OpenGL坐标:
-(CGPoint) locationFromTouch:(UITouch *)touch { CGPoint touchLocation = [touch locationInView:[touch view]]; return [[CCDirector sharedDirector] convertToGL:touchLocation]; }2、接收加速计事件
同样,需要self.isAccelerometerEnabled = YES来显示启动加速计来接收加速计事件,但是这个事件的处理比触摸时间就简单多了,只需要向层里面添加一个特定方法来接收加速计事件:
- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration { //可以利用以下参数来决定三维中任意方向的加速度 //acceleration.x acceleration.y acceleration.z }- CCSprite

CCSprite是cocos2d种最为常用的类,它用一副图像将精灵显示到屏幕上。要创建一个精灵很简单,比如你的工程的Resources分组下有一张叫做monster.png的图,那么只需要使用如下方法,就能将精灵显示在层上:
CCSpirt *sprite = [[CCSprite spriteWithFile:@"monster.png"]]; [self addChild:sprite];
通过上面的操作后,cocos2d内部会把该图片加载到CCTexture2D类的图像资源中。在这里,顺便提一下,由于ios设备只支持尺寸为“2的n次幂”的纹理,即图片的长宽只能伟:2、4、8等像素。如果你有一张贴图,大小为260*260像素32位色的图片,那么就比较悲剧了。你觉得它在内存中应该只占用260*260*4=270KB左右的空间,单实际上,它占用了512*512*4=1MB的内存。
CCSprite还有一个比较重要的就是位置问题,想象下现实生活中,如果你要把一张照片钉在墙上某个问题,你会怎么做?首先,你会把图钉插在照片上的某个点(在cocos2d中称为anchorPoint),然后你会确定要把这个图钉订在墙上的某个位置(在cocos2d种称为positon),这两个点就能确定照片在墙上的位置了。比如你想把照片放到左下角,那么你可以选择将图钉钉在照片的左下角(0,0),然后钉在墙的左下角(0,0).或者,你可以选择把图钉定在照片的右上角(1,1),然后把照片订在墙的(照片长,照片宽)的位置。auchorPoint表示的其实是一个百分比,用来标明相对于图片左下角的(长*百分比,宽*百分比)像素的位置,比如auchorPoint为(0.5, 0.5), 那么在图片的坐标系里,它标明的位置就应该是(长*0.5, 宽*0.5)的位置,也就是图片的中心点。最好好anchorPoint设置成(0.5, 0.5),也就是在图片的中心,这样,当你进行旋转、缩放等动作的时候,会比较方便。幸运的是,anchorPoint的默认位置就是(0.5,0.5).
- CCLabelTTF

这个类的作用就是在屏幕上显示文本。cocos2d内部会以制定的字体作为参数创建一个CCTexture2D对象,也就是一张纹理,然后再用改纹理渲染出最后显示的文本.因为每次文本发生改变,就要做一次上述工作,所以cocos2d的文档中也建议改用CCLabelAtlas或者CCLabelBMFont代替。
你可能会发现,每次修改标签上的文本时候,这些文本都会自动中对齐,如果要改成左对齐,或者右对齐这些,只需要改变anchorPoint的属性就可以了。
- 动作
动作是可以用来让节点执行诸如移动、旋转、缩放、变色、消失等很多动作。由于他们能作用在所有的节点上,因此可以对精灵、标签甚至菜单或整个场景施加动作。动作在完成后,会自动从节点上清除并释放它所占用的内存。
动作又分为即时动作和延时动作。延时动作就是我们一般理解上的动作,比如让一个精灵移动到哪里。即时动作,一般就类似于设置精灵的属性等,及时动作平时看起来是没有多大意义的,一般要配合后文所述的动作序列。
1)重复动作
这个很容易理解,就是让一个动作不停的重复,可以用这个方法创建无限循环的动画。使用起来也很简单,例如下面这个让一个节点不停的旋转:
CCRotateBy* rotateBy = [CCRotateBy actionWithDuration:2 angle:360]; CCRepeatForever *repeat = [CCRepeatForever actionWithAction:rotateBy]; [myNode runAction:repeat];
还有一个类CCRepeat是让一个动画重复多少次,函数原型如下:
actionWithAction:(CCFiniteTimeAction *)action times:(NSUInteger) times;2、流畅动作(CCEaseAction)
一般的动作,比如你定义了一个物体是向哪个方向移动,那么它就会匀速的过去,但是很显然,我们喜欢更有点变化的动作,比如加速进入,然后迅速一段时间,再减速停止,流畅动作就是用来做这个的。
3、动作序列
CCSequence,这个比较好理解,就是定义一组动作,然后让他们按照这个顺序执行。
上面介绍了cocos2d种一些重要的、常用的类,接下来的文章,会采用这些来做一个小demo,来温习一下这一篇文章的内容,不正确的地方,还请各位斧正。
一条评论 -
cocos2d,开搞!
其实想写cocos2d的东西很久了,一直因为一些乱七八糟的事情,而没有写。前几天跟popple聊天的时候,popple说想要做一些这方面的东西,于是决定还是开始写这一系列的东西吧,记录自己学习,同时也分享给喜欢这个的朋友。
ios上开发游戏有很多方法,最原始的就是用原生的cocoa框架加上OpenGL ES开发,但是这种方法太复杂了,而且操作OpenGL也挺麻烦的,所以我选择了cocos 2d来作为框架开发。这个框架比较简单,而且资料也比较全,内置的box2d引擎,很多同学应该都听说过,比如《愤怒的小鸟》就采用了此引擎。
既然选择了cocos 2d,那么就先继续吹捧下这个框架吧。首先,它是免费的,你用它来做商业开发都没关系,其次,它是开源的,但是现在这点对我不是很重要,因为目前只能做一个伸手党,确实没有太多的能力去贡献cocos 2d社区。最后,也是我选择它最重要的一个原因,就是简单而且文档丰富,遇到的问题,google一下,很多时候,都能找到答案。顺便提一下,现在使用cocos2d还有个额外的好处,就是可以跨平台开发,但是这个不是coos2d实现的,而是一个叫做cocos2dx的项目。cocos2dx可以理解成一个cocos2d的c++版本(因为接口基本上一样),但是它却可以编译成各种平台上的app,非常强大。它的主要贡献者来自中国,大家可以关注下他的微博。
这一系列的文章,是以《Learn iPhone and iPad Cocos2d Game Development》为基础,总结一些书里面的知识以及自己对这些的理解。还请各位大牛多多指点。
-
mac下我常用的一些软件
在苹果发布了mountain lion的开发者预览版后,我就毫不犹豫的升级了。刚开始的时候,用起来感觉还挺好的,跟ios融合的很好,我在手机上记录的一些东西,在mountain lion中都能立即同步过来。更让我期待的是,新加的通知功能很不错,以后就可以把一些不太重要的消息设置成不弹出来提示,有时间的时候,再去通知中心查看。
但是跟mountain lion过了几天美好的生活后发现,开发者预览版还是不适合做日常的稳定系统,首先就是跟一些软件不兼容,比如大名鼎鼎的虚拟机——PD,其次就是功能有些不太稳定,新版的safari浏览的时候,有时候滑动页面,会出现一些卡顿感,这也是直接导致我装回lion的导火线。
这里继续吐槽下苹果,在升级到mountain lion后,发现想退回去太难了,尝试了用网络恢复,结果wifi的部件有问题,老连接不上,不过网上有朋友说,就算连上了,也是直接恢复成新版的mountain lion,那又有什么意义呢?然后借用了boris在lion下做的恢复盘,发现也没办法恢复,最后只能自己重新做了一个lion的安装U盘,这才搞定。
不过这样转了一大圈,也有好处,一是体验了下新的系统,二来,也重新梳理了下mac里我常用的一些软件:
1、iterm 2:非常好用的终端,完全可以替代系统自带的。
2、Eclipse:我主要是把它当做c/c++的编辑器。
3、Secure CRT:用来登陆远程的服务器。
4、xcode:苹果自己的IDE,装完后,gcc这些也就自动装好了。
5、搜狗输入法:以前一直用QQ拼音,但是后来发现在长词组上,搜狗还是好很多。
6、the unarchiver:mac store上免费的解压软件。
7、MPlayerX:很不错的视频播放器,类比与windows平台的QQ影音。
8、totalfinder:可以简单的把它当做有标签的finder,但是我最喜欢的是可以用快捷键呼出,就像在windows里面使用win+e一样。
9、dropbox:同步不同电脑、手机里面的文件,主要是上传和下载速度非常快,我使用中上传和下载最快都有400k/s。不过由于某东西的存在,用dropbox一直不太安心。等金山快盘出了mac版后,准备先试试金山的。
10、evernote:记录笔记。
11、ipuff:这个就是翻越某物体的,买个商业版的账号,很稳定。
12、reeder:我最喜欢的rss客户端
13、Microsoft Office和iWork:这个应该不用多说,都会装吧。
14、iPhoto:主要是要使用icloud的照片流功能。
15、QQ
16、有道词典:在mac下其实有更好的,或者就用自带的也行,但是windows下习惯了有道,而且也对网易有信心,所以选择了这个,不过本地词库太弱了,没有网络,基本上等于不能用。
17、brew:这个要强烈推荐下,因为在ubuntu下习惯了apt,所以装软件的生活,总是习惯了apt-get install ***,这个软件让你在mac下也能在终端下装软件,使用起来也非常简单,比如brew install ***
18、synergy:如果你有几台电脑,又不想用几套键鼠,那么这个虚拟的切换器能帮你做到,非常推荐。
19、Scroll Reverser:在lion下,触摸板和鼠标的滚轮方向是绑死的,要么是传统的方式,要么是iphone一样的自然方式,但是我比较喜欢触摸板使用自然方式,而鼠标依旧使用传统模式,所以,这个软件就很有必要了
-
google proto buffer使用
听说google proto buffer(以下简称protobuf)已经很久了,但是一直没有尝试使用它。其中一个原因是,项目组自己写了个打包和解包的工具,而且代码也简单,可以很方便的扩展到自动生成xml之类的配置文件,已经能很好的符合项目的需要。但是最近发现protobuf有个很不错的功能,就是可以向已有的协议中添加新的字段,而不影响采用旧协议的服务。所以就想试试protobuf。
要使用google proto buffer,首先要进行的就是安装,先说说我的(mac os X 10.7.2)安装过程吧:
1、下载google proto buff。
2、解压下载的包,并且阅读README.txt,根据里面的指引进行安装。
3、 $ ./configure
$ make
$ make check
$ make install没有意外的话,前面三步应该都能顺利完成,第四步的时候,需要root权限。我采用的默认的路径,所以,仅仅用root权限,还是安装不了,要自己先在/usr/local下新建一个lib的目录,然后执行make install,这样,应该就能顺利安装google proto buffer了。
安装完后,先写一个测试程序来测试下安装,先来看看proto文件:
package hello; message Hello{ required int32 id = 1; //user id required string name = 2; //user name optional string email = 3; //user email }接着,要用protoc生成一个对应的类,我把它生成在./out目录里:protoc hello.proto –cpp_out=./out
接下来,在out目录下,会生成两个文件:
$> ls
hello.pb.cc hello.pb.h
接下来,编写测试用的c++代码:
#include <stdio.h> #include <string.h> #include "out/hello.pb.h" using namespace std; using namespace hello; int main() { Hello a; a.set_id(101); a.set_name("huangwei"); string tmp; bool ret = a.SerializeToString(&tmp); if (ret) { printf("encode success!\n"); } else { printf("encode faild!\n"); } Hello b; ret = b.ParseFromString(tmp); if (ret) { printf("decode success!\n id= %d \n name = %s\n", b.id(), b.name().c_str()); } else { printf("decode faild!\n"); } return 0; }接着,编译一下这个代码,由于使用了protobuf的库,所以编译的时候,要把这些库也链接进来:
g++ hello.cc ./out/hello.pb.cc -o hello -I./out -I/usr/local/protobuf/include -L/usr/local/lib -lprotobuf
这样,就生成了测试程序。
运行一下:
$> ./hello
encode success!
decode success!
id= 101
name = huangwei这样,简单的google proto buffer的使用就完成了。有什么错误的地方,还请各位斧正。
-
android,说好的公正
昨天晚上发微博,说自己欠android一个公正,今天要写一片文章来公正的谈谈android。
其实,坦白来说,我算不上一个android黑,反而还是偏android粉一点,但是最近在跟人聊天的时候,或多或少贬低了下android,或许,这应该描述成恨铁不成钢比较何时吧。本文就从G1开始将起我和android的故事吧。
-
个人站点启用
-
简单的时间服务程序
-
利用LSM实现更安全的linux
LSM的全称是Linux Security Modules,它是linux内核中用来支持更灵活的安全策略的一个底层框架,虽然听起来比较复杂,但是可以就把它理解成一组安插在linux内核的钩子函数和一些预留的被称为安全域的数据结构,下面先说说这个框架的由来吧。
-
利用信号实现写优先的读写锁
以前利用linux系统提供的读写锁写过一些小程序,但是linux系统提供的读写锁是线程级的,如果是进程间的同步的话,就没那么轻松了。而且由于linux系统提供的读写锁是读优先的,在有些情况下,也不能满足我们的要求。下面就说说利用信号量来实现写优先的读写锁。
-
google C/C++编程风格的一些摘要