Cocos2d-x 2.x读书摘要


按:Cocos2d-x高级开发教程——制作自己的《捕鱼达人》、Cocos2d-x游戏开发技术精解这两本书,都是基于2.0.4版本讲解且于2013年6月份出版的。
Cocos2d-x游戏开发技术精解
刘剑卓 著
2013年6月第1版
chap2 Cocos2d-x引擎的开发环境
2.1跨平台的开发
2.2建立开发环境
2.2.1 PC开发环境
本书将会选择使用稳定的2.0.4引擎版本。
在本书的讲解中,将会以Windows下的Visual Studio 2010为主要的开发环境。
注意:读者最好不要选用VS 2008版本进行开发,因为引擎开发者已经明确未来不再支持此版本的开发环境。
2.2.1 PC开发环境
在引擎包中,提供了三个版本的项目工程。它们分别针对VS2008、VS2010以及VS2012。
注意:VS2010只支持Win7以后的操作系统。【XP也支持】

F:\hxhwin7\Cocos2d-xVC2010\cocos2d-2.0-x-2.0.3
用VC2012编译PC版通过
“常规|包含目录”去掉
D:\SixDivisions\Cocos2d-x\2.0-x-2.03_branch_231_NoScript\extensions\GUI\CCControlExtension
D:\cocos2d-2.1rc0-x-2.1.2\extensions
D:\cocos2d-2.1rc0-x-2.1.2\extensions\GUI
“常规|库目录”去掉
$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib
2.1.5版本LAYER_CREATE_FUNC改为CREATE_FUNC
2.0.3引擎包的Bug:添加CCEditBox.h和.cpp到libExtensions工程,作如下修改并重新编译
#ifndef WIN32
    CCEditBoxImpl*      m_pEditBoxImpl;
#endif
“链接器|高级|导入库”
$(OutDir)$(TargetName).lib改为$(TargetDir)$(TargetName).lib
ADT+Builder/VC2012+Cocos2d-x 2.0.3可以正常编译捕鱼原型的Android版和PC版。
静态库libExtensions.lib
CCControl.win32工程|预处理定义:WIN32;_DEBUG;_WINDOWS;
工作目录
$(ProjectDir)..\Resources或$(SolutionDir)samples\CCControl\Resources
Android下路径文件名大小写敏感

2.2.2 Android开发环境
2.2.3 iOS开发环境

20150614问题:在Classes目录下新建gui目录、HelloWorldScene1.h、HelloWorldScene1.cpp
Xcode7重新编译,会出现如下链接失败的错误提示:
Undefined symbols for architecture armv7:
  "HelloWorld1::scene()", referenced from:
      AppDelegate::applicationDidFinishLaunching() in AppDelegate.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)
解决办法:
选择TARGETS|Build Phases|Compile Sources(230 items)
点击+|Add Other...
选择HelloWorldScene1.cpp
在弹出的Choose options for adding these files:界面中选择Create groups,然后点击【Finish】
可以发现变为Compile Sources(231 items)
重新编译,就可以正常运行了。

在Xcode界面中,左侧为项目路径。
在iOS平台,系统库是以framework的形式引入的。开发者可以点击页面下的“+”按钮进行添加。
而由引擎编译而来的程序库,则是以“.a”为文件后缀的,比如所有游戏项目都需要引入libcocos2dx.a库作为引擎。
除此之外读者还要设置项目依赖关系。
2.3.2 Objective-C与C++的混合编译
为了介绍方便,以后的内容就简写为OC。
编译器允许用户在同一个源文件里自由地混合使用C++和Objective-C,混编后的语言叫Objective-C++。
说明:尽量避免在一个文件中写入两种编程语言的类声明,这很容易造成混乱,不宜阅读。
在项目路径proj.ios下,存放可以混合编写的代码文件。这些文件的后缀为“.mm”。Xcode编译器允许开发者在同一个源文件里自由地混合使用C++和OC,混合后的语言叫Objective-C++,简称为OC++。编译器就是通过文件后缀名来标识OC++文件的。在OC++文件中,可以用C++代码调用方法,也可以从Objective-C调用方法。在两种语言里对象都是指针,可以在任何地方使用。
AppController.mm文件是引擎中应用开启的类。它负责管理游戏应用运行周期。在这里作为例子,主要是为读者介绍OC++的编程方式。
注意:OC++没有为OC类增加C++的功能,也没有为C++类增加OC的功能。例如,你不能用OC语法调用C++对象,也不能为OC对象增加构造函数和析构函数,也不能将this和self互相替换使用。类的体系结构是独立的。C++类不能继承OC类,OC类也不能继承C++类。另外,多语言异常处理是不支持的。也就是说,一个OC抛出的异常不能被C++代码捕获,反过来C++代码抛出的异常也不能被OC代码捕获。
再来看看iOS平台入口文件的内容。
main
//初始化自动释放池
//启动应用程序
代码来自项目路径proj.ios\main.m
这就是iOS应用程序的入口,同样是由引擎为开发者准备妥当了。这段代码也是只有在iOS项目中才能发挥作用。
2.4.2引擎应用入口
在项目路径Classes中,存在一个AppDelegate类文件。此文件的命名是OC编程语言的风格。在此代码文件中,就是与引擎应用生命周期有关的函数。所谓的生命周期,就是游戏应用开始与结束的过程。在此过程中,引擎应用会存在许多的状态。
引擎应用的生命周期
//应用开启的入口
applicationDidFinishLaunching
//当应用进入待机状态时调用的函数
applicationDidEnterBackground
//当应用从待机恢复
applicationWillEnterForeground
引擎中没有提供多款应用同时运行的情况。当引擎启动之后,就会执行唯一的游戏应用。引擎将会调用applicationDidFinishLaunching函数作为游戏应用开启的入口。在引擎应用运行的状态中,还存在一个待机状态。这就是当手机来电话或者退入后台时,游戏进入了暂停状态,同时还要暂停音乐的播放。
2.3引擎中的混合编译
2.3.1 Java与C++的混合编译
2.3.2 Objective-C与C++的混合编译
2.4引擎的起点
2.4.1应用程序入口
2.4.2引擎应用入口
2.5丰富的示例程序
2.5.1 TestCpp示例项目
2.5.2脚本示例项目
2.5.3 MoonWarriors示例项目
2.6本章小结
chap3 引擎的核心——渲染框架
3.1基本框架
3.1.1引擎的位置
3.1.2根源种子
3.1.3子类结构
3.2渲染框架
3.2.1框架结构
导演、场景、层次和精灵。它们对应了引擎当中的四个类:CCDirector、CCScene、CCLayer和CCSprite。
3.2.2摄像机类CCCamera
在每一个CCNode对象中,都存在一个摄像机对象CCCamera。
注意:摄像机控制与物体属性控制,读者只能二选其一。如果同时使用,将会导致引擎的坐标系出现错误。
开发者在使用摄像机时还有一些注意事项。
(1)一些特殊的CCNode对象,比如CCParallaxNode、CCParticle依据的是世界坐标系,它们将不会受到摄像机影响。
(2)当精灵对象CCSprite是来自精灵集合CCSpriteBatchNode时,也将不受摄像机的影响。
(3)如果开发者只需要二维的画面效果,则无需控制摄像机。摄像机只是为了体现三维效果而准备的。
3.2.3导演类CCDirector
说明:单例模式也存在一个缺点,就是随处可见的调用关系,很容易导致代码结构的混乱。
说明:在不同的平台,因为显示设备不同,显示窗口(EAGLView)初始化的方式略有不同。
在类CCDirector的代码中,为了便于管理场景对象,采用了队列[栈:先进后出]方式来管理场景对象。
    /* The running scene */
    CCScene *m_pRunningScene;
   
    /* will be the next 'runningScene' in the next frame
     nextScene is a weak reference. */
    CCScene *m_pNextScene;
/* scheduled scenes */
    CCArray* m_pobScenesStack;
在类CCDirector的源代码中,runningScene_表示当前正在显示的场景,nextScene表示下一个将要显示的场景。而用于储存场景队列的对象则是一个动态可变数组sceneStack_。
3.2.4场景类CCScene
场景通常不包含游戏逻辑,仅仅是做为一个容器,将不同的层组合到一起,最终呈现给玩家一个完整的画面。它代表了游戏运行中的一个状态,其包含的图层是更小一级的容器。图层中包含了游戏逻辑、用户响应以及精灵对象。
所有与显示有关的类几乎都是继承自CCNode。
说明:类CCNode中提供了更改父节点的函数setParent()。
3.2.5图层类CCLayer
图层也是渲染框架中很重要的内容。场景类用来划分游戏状态。图层就用来划分游戏画面。通常图层的尺寸会与屏幕尺寸一致。
图层之间可以叠加,也可以彼此包含。
为了让不同的层能够叠加来产生整体的画面效果,图层中包含了一些透明的区域。不仅如此,图层叠加还可以进行颜色混合。引擎当中就通过类CCLayer提供了上述图层的功能。引擎中图层对象包含了三个功能。
(1)接受用户操作,比如触屏、重力加速度计的信息。
(2)作为游戏内容元素的容器,用于显示游戏画面、承载精灵类、字体文本等对象。
(3)填充背景游戏背景颜色。
在CCLayer头文件的源代码中,还存在一个函数node。它的作用与函数create一样,只不过是旧版本留下来的程序接口。用不了多久,它就会被弃用。
类CCLayer中也没有实际的绘制内容。它的主要作用在于建立用户交互的功能。
注意:默认情况下,图层是不接受用户操作的。开发者需要调用函数来开启图层将要接受的用户操作,比如setTouchEnabled、setAccelerometerEnabled以及isKeypadEnabled。
引擎按照游戏内容提供了一些特殊的图层类。
1、CCLayerColor颜色层
2、CCMenu菜单图层
3、CCMultiplexLayer复合层
3.2.6精灵类CCSprite
精灵类CCSprite继承自CCNode,这是为了满足渲染框架的结构。
精灵类还继承了两个协议类,它们分别为CCRGBAProtocol和CCTextureProtocol。这两个协议类是用于处理精灵类中的纹理图片,前者是负责颜色的管理,后者是用于纹理图片的管理。
3.2.7精灵集合类CCSpriteBatchNode
精灵集合类CCSpriteBatchNode,它的对象常常包含了许多的精灵对象。这些精灵对象具有一个共同的特点,那就是使用同一张纹理图片。虽然是同一张纹理图片,但每个精灵所用的矩形区域不一样。
3.2.8精灵帧缓冲CCSpriteFrameCache
精灵帧缓冲CCSpriteFrameCache就是一个存放精灵帧CCSpriteFrame对象的缓冲池。
它甚至都不是CCNode子类。
3.2.9 Zwoptex纹理编辑器
3.3文字与字体
3.3.1 TTF类型标签(CCLabelTTF)
3.3.2 BMFont标签类(CCLabelBMFont)
3.3.3 Atlas标签类(CCLabelAtlas)
3.4菜单按钮
3.5几何绘制DrawPrimitives
3.6 CocosBuilder编辑器
3.6.1 CocosBuilder使用指南
3.6.2引擎中的应用
3.7本章小结
chap4 动作功能
本章是Cocos2d-x引擎中最有魅力的部分。
4.1概述
4.2动作基类
4.2.1动作类的继承关系
4.2.2动作基类CCAction的成员函数
4.2.3 类CCNode中与动作有关的函数
4.3时间动作
动作基类CCAction首要的继承子类,其实就是CCFiniteTimeAction类。
从字面的意思来理解是与时间相关的动作类,因此在类CCFiniteTimeAction的属性中就加入了一个与时间有关的成员变量,同时提供了如下两个操作函数。
getDuration
setDuration
与时间相关的动作被划分为两类:即时动作和延时动作。
4.3.1即时动作这些继承自类CCActionInstant的子类都是即时动作。这意味着当此类动作被作用在精灵或者其他的CCNode对象时,将会立即被执行,发挥其动作的作用。
现在先来看看每一个即时动作所发挥的作用吧!
6、函数调用动作(CCCallFunc、CCCallFuncND、CCCallFuncN以及CCCallFuncO)
与前几个类的作用一样,函数调用的动作也经常用在动作序列当中。
此系列包含了四个动作类。类CCCallFunc是另外三个的父类。它们只是因为传递的参数不同,而有所区分。
CCCallFunc类的调用函数没有任何参数。
CCCallFuncND类的调用函数有两个参数,分别为CCNode对象和Data数据指针。
虽然有四个函数调用的动作类,但是它们的区别也仅仅是在参数上。其他部分的作用则是一样的。

void CBulletManage::Shoot(int iPlayerID, CCPoint ptTouch, CCPoint ptShip, float fRotation, bool bReBound)
{
 if (NULL == s_AllBullet)
  CCAssert(0, "请先调用 CBulletManage::Init(...) 函数!");
 // 子弹间隔延迟控制
 DWORD dwNow = ::timeGetTime();
 if (dwNow < m_LastShootTime+d_Max_Shoot_Delay)
  return;
 m_LastShootTime = dwNow;
 CCPoint ptMuzzle = CountTwoPointOneCoordinate(ptTouch, ptShip, 150); // 计算枪口位置
 CBullet * pBullet = CBullet::create( CCString::createWithFormat("bullet_01_00000.png")->getCString() );
 pBullet->autorelease();
 pBullet->setRotation( fRotation );
 pBullet->setIsCatching( false );
 pBullet->setIsReBound( bReBound );
 pBullet->setAnchorPoint(CCPoint(0.5, 1.0));
 pBullet->setPosition( ptMuzzle );
 pBullet->setPlayerID( iPlayerID );
 
 float fDistance = sqrtf( pow(ptTouch.x - ptMuzzle.x,  2)  + pow(ptTouch.y - ptMuzzle.y,  2) ) ; // 两点间距离
 float fTime = fDistance / d_Bullet_Speed; // 子弹需要时间
 CCActionInterval *pMove = CCMoveTo::create( fTime, ptTouch );
 
 CCActionInstant * pCallBack = CCCallFuncND::create(pBullet, callfuncND_selector( CBullet::FinishAnimation ), (void *)&ptTouch);
 CCActionInterval * pBulletRun = CCSequence::create(pMove, pCallBack, NULL);
 pBullet->runAction( pBulletRun );
 CCArray* pArray = CCArray::create();
 for (int i=0; i<10; i++)
 {
  CCString * pStrBuffer = CCString::createWithFormat( "bullet_01_%05d.png", i);
  CCSpriteFrame* pSpriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName( pStrBuffer->getCString() );
  pArray->addObject( pSpriteFrame );
 }
 pBullet->runAction( CCRepeatForever::create( CCAnimate::create( CCAnimation::createWithSpriteFrames( pArray, 0.1f ) ) ) );
 s_AllBullet->addChild( pBullet );
}
void CBullet::FinishAnimation(CCNode* pSender, void* data)
{
 stopAllActions();
 setVisible( false );
 CCPoint * pTouch = (CCPoint *)data;
 // 鱼网
 CCArray *pArray = CCArray::create();
 for (int i=0; i<10; i++)
 {
  CCString *pStrBuffer = CCString::createWithFormat("FishNet_01_%05d.png", i);
  CCSpriteFrame * pFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName( pStrBuffer->getCString() );
  pArray->addObject( pFrame );
 }
 CCActionInterval * pAnimate = CCAnimate::create( CCAnimation::createWithSpriteFrames( pArray, 0.05f ) );
 setAnchorPoint(CCPoint(0.5,0.5));
 // 结束自己
 CCActionInstant *pCallBack = CCCallFunc::create(this, callfunc_selector( CBullet::Release ));
 runAction( CCSequence::create(CCShow::create(), pAnimate, pCallBack, NULL) );
}
void CBullet::Release()
{
 removeAllChildren();
 removeFromParent();
}

4.3.2持续动作
按照CCNode类的对象属性来划分,我们可以将上述动作分为以下几个类型。
1、与位置有关的持续动作
CCMoveBy、CCMoveTo、CCJumpBy、CCJumpTo、CCBezierBy、CCBezierTo,上述三对动作类在执行时都会通过修改类CCNode对象中的位置属性来发挥执行效果。
To代表了具体移动的结果。
有By的动作,表示动作执行的程度或者速率。
之后,还会接触许多成对出现、采用类似命名规则的动作类。
先从CCMoveTo和CCMoveBy开始。
在创建此动作类的对象时,第一个参数就是时间,第二个参数就是目标点或者移动距离。

 /// 划船动画
 void OnRowingAnimation(float fTime);
 void OnRowingCompleteAnimation();
void Player::OnRowingAnimation(float fTime)
{
 unschedule( schedule_selector(Player::OnRowingAnimation) );
 float fOffset = 110.0f;
 if (PLAYER_COUNT/2 <= m_PlayerPT)
  fOffset = -110.0f;
 CCSprite * pShip = (CCSprite *)getChildByTag( t_Ship );
 pShip->setVisible( true );
 pShip->setPositionY( pShip->getPositionY()+fOffset );
 CCActionInterval * pMove = CCMoveBy::create(1.5f, ccp(0, -fOffset));
 CCActionInstant * pComplete = CCCallFunc::create(this, callfunc_selector(Player::OnRowingCompleteAnimation));
 CCActionInterval * pShipAnimation = CCSequence::create(pMove, pComplete, NULL);
 pShip->runAction( pShipAnimation );
}
void Player::OnRowingCompleteAnimation()
{
 // 玩家划船进入,未到达捕鱼现场,除了炮与船其他信息暂隐藏。
 CCSprite *pChild = NULL;
 CCObject* pObj = NULL;
 CCARRAY_FOREACH(getChildren(), pObj)
 {
  pChild = (CCSprite*)pObj;
  pChild->setVisible( true );
 }
}

在Cocos2d-x引擎中存在一个专门用来表示[三阶]贝塞尔曲线的配置类ccBezierConfig。此类的对象包含了三个CCPoint对象。它们分别用来表示贝塞尔曲线的三个属性点。
通过四个点P0、P1、P2、P3,就能表示出一条[三阶]贝塞尔曲线。在ccBezierConfig对象中保存了P1、P2、P3这三个点属性。而P0则是CCNode对象的初始位置属性。
3、旋转动作类
CCRotateBy和CCRotateTo,这对动作类是通过修改CCNode对象的角度属性来达到旋转的效果。
4.4组合动作类
在游戏当中,一个角色通常并不是只有一个动作在执行中的。
Cocos2d-x引擎提供了一些将其他动作进行组合的动作类。这些类就好比是一个动作对象的容器。
4.4.1序列动作类CCSequence
序列动作类CCSequence是从CCIntervalAction类派生而来的,因此它也是一个与时间有关的类。
每一个组合动作类都有其特定的执行规则。序列动作类就是将放置在自身序列当中的若干个动作类对象,按照前后的线性顺序逐个执行。
以action开头的的是旧版本中延续下来的函数,在不久的将来就会消失。而create函数则是2.0版本中简化后的创建函数。
如果需要使用序列动作,那么至少要准备两个动作对象。
创建函数的参数恰好就是动作类的对象。
4.4.2同步动作类CCSpawn
组合动作只是一群特殊的持续动作类。
类CCSpawn同样是来自CCIntervalAction类的派生,它的创建函数也与序列动作类CCSequence非常类似。
该类与序列动作类CCSequence的区别就是,它使得CCNode对象可以同时执行若干个动作。

void CFish::addPath()
{
 switch(rand() % 7)
 {
  case 0:
   this->moveWithParabola(this, ccp(1200, 200), ccp(-500, 800), 0.0f, 20.0f, rand()%10+15);
   break;
  case 1:
   this->moveWithParabola(this, ccp(-200, 300), ccp(1300, 400), 180.0, 170.0, rand()%10+18);
   break;
  case 2:
   this->moveWithParabola(this, ccp(-200, 300), ccp(1000, -200), 190.0, 200.0, rand()%10+18);
   break;
  case 3:
   this->moveWithParabola(this, ccp(1300, 400), ccp(-200, 300), 10.0, 5.0, rand()%10+18);
   break;
  case 4:
   this->moveWithParabola(this, ccp(400, -1200), ccp(600, 1000), 90.0, 93.0, rand()%10+18);
   break;
  case 5:
   this->moveWithParabola(this, ccp(600, 1000), ccp(400, -200), -70.0, -80.0, rand()%10+18);
   break;
  case 6:
   this->moveWithParabola(this, ccp(1200, 2100), ccp(-200, 300), 30.0, -30.0, rand()%10+18);
   break;
 }
}
void CFish::moveWithParabola(cocos2d::CCSprite* mSprite, cocos2d::CCPoint startP, cocos2d::CCPoint endP, float startAngle, float endAngle, float time)
{
 float sx = startP.x;
 float sy = startP.y;
 float ex =endP.x+rand()%50;
 float ey =endP.y+rand()%150;
 float h = mSprite->getContentSize().height * 0.5f;
 CCPoint pos = CCPointMake(sx - 200 + rand()%400, sy -200 + rand() %400);
 mSprite->setPosition(pos);
 mSprite->setRotation(startAngle);
 // 贝塞尔曲线
 ccBezierConfig bezier;
 // 控制点1(起点)
 bezier.controlPoint_1 = ccp(sx, sy);
 // 控制点2
 bezier.controlPoint_2 = ccp(sx+(ex-sx)*0.5, sy+(ey-sy)*0.5+rand()%300);
 // 终点
 bezier.endPosition = ccp(endP.x-30, endP.y+h);
 CCBezierTo* actionMove = CCBezierTo::create(time, bezier);
 CCRotateTo* actionRotate = CCRotateTo::create(time, endAngle);
 CCFiniteTimeAction* action = CCSpawn::create(actionMove, actionRotate, 0);
 CCFiniteTimeAction* sq = CCSequence::create(action,CCCallFunc::create(this, callfunc_selector(CFish::removeSelf)), 0);
 mSprite->runAction(sq);
}

4.4.3重复动作类CCRepeat & CCRepeatForever
类CCRepeat和类CCRepeatForever也是开发者经常会使用的组合动作类。它是用来重复某一个动作对象的。此处的动作对象,可以是单一的基本动作对象,也可以是组合动作对象。
此动作类的执行效果就是能够将一个动作对象重复许多次或者永无止境地循环执行。
它可以使用任何动作对象作为参数,其中包含了单个的基本动作对象,也包含了前面介绍过的序列动作以及同步动作。
对于类CCRepeatForever而言,其创建函数没有第二个参数,因为它是永不停止的执行动作对象。
类CCRepeatForever并不是类CCRepeat的子类,虽然它们有着类似的功能,但它是由类CCActionInterval直接派生的。

void CFashManage::addOneFish(CFish::Fish_Type eType/*=Fish_1*/)
{
 if (NULL == s_AllFish)
  CCAssert(0, "请先调用 CFashManage::Init(...) 函数初始化");
 char charBuffer[256] = {0};
 CCArray* fish01 = CCArray::create();
 // 鱼帧
 for(int i = 1; i < d_Fish_Frame_Count; i++)
 {
  memset(charBuffer, 0, sizeof(charBuffer));
  _snprintf(charBuffer, sizeof(charBuffer), "fish0%d_0%d.png", eType, i);
  CCSpriteFrame* spriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(charBuffer);
  fish01->addObject(spriteFrame);
 }
 // 由帧缓存生成action,帧延迟0.1f
 CCActionInterval * pFishAction = CCRepeatForever::create(CCAnimate::create(CCAnimation::createWithSpriteFrames(fish01, 0.1f)));
 // 通过起始帧生成鱼实体
 CFish* fish = CFish::createWithSpriteFrameName(CCString::createWithFormat("fish0%d_0%d.png", eType, 1)->getCString());
 fish->setIsCatching( false );
 fish->setTag( eType );
 fish->runAction( pFishAction );
 fish->addPath();
 s_AllFish->addChild( fish );
}

4.5可变速度类CCEaseAction
4.5.1CCEaseIn、CCEaseOut、CCEaseInOut
4.5.2EaseSineIn、EaseSineOut、EaseSineInOut
4.5.3CCEaseBackIn、CCEaseBackOut、CCEaseBackInOut
4.5.4EaseExponentialIn、EaseExponentialOut、EaseExponentialInOut
4.5.5CCEaseBounceIn、CCEaseBounceOut、CCEaseBounceInOut
4.5.6CCEaseElasticIn、CCEaseElasticOut、CCEaseElasticInOut
4.6速度类CCSpeed
4.7延迟动作类CCDelay
4.8跟随动作类CCFollow
4.9扩展动作类
4.9.1概述
4.9.2翻页动作类CCPageTurn3D
4.9.3波纹动作CCWaves3D
4.9.4格子动作类CCGridAction
4.10动画动作类
在最后的内容中,留给大家一个最重要的动作类,这个动作类就是动画动作。它同样是来继承自持续动作类CCActionInterval。
没有哪个游戏是没有动画的。
下面的内容,也将不仅仅局限于动画动作,而是将动画动作的实现机制以及引擎当中对其优化的技术都展现出来。
4.10.1精灵帧
最新版的Cocos2d-x引擎专门设计了类CCAnimationFrame为动画帧对象。在旧版本的引擎当中,开发者更习惯直接使用类CCSpriteFrame(精灵帧)。

CFish* CFish::createWithSpriteFrameName(const char *pszSpriteFrameName)
{
 CCSpriteFrame *pFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(pszSpriteFrameName);
 char msg[256] = {0};
 sprintf(msg, "Invalid spriteFrameName: %s", pszSpriteFrameName);
 CCAssert(pFrame != NULL, msg);
 return createWithSpriteFrame(pFrame);
}

4.10.2精灵帧缓冲
所谓的精灵帧缓冲类CCSpriteFrameCache,其实就是一个存放精灵帧对象的缓冲池。在引擎运行时,它将会作为一个单例对象。
它的目的在于提升动画的性能。

void CFashManage::Init(CCNode * pNode)
{
 if (NULL == s_AllFish)
 {
  for (int i=0; i<d_Fish_Plist_File_Count; i++)
  {
   CCString *pListName = CCString::createWithFormat("./play/fish%02d%s",i+1,".plist");
   CCString *pBatchName = CCString::createWithFormat("./play/fish%02d%s",i+1,".png");
   CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(pListName->getCString());
   s_AllFish = CCSpriteBatchNode::create(pBatchName->getCString());
   pNode->addChild( s_AllFish );
  }
 }
 while(NULL != s_AllFish && sharedFish()->getChildren()->count() < d_Fish_Max_Count)
 {
  // 鱼种
  CFish::Fish_Type fishTytpe = (CFish::Fish_Type)(rand() % (CFish::Fish_Type_Count-1) + 1);
  addOneFish( fishTytpe );
 }
}

4.10.3动画类
动画类CCAnimation就是用在精灵之上的动画对象。它包含了一系列的动画帧以及动画帧之间的播放间隔。所以说动画类的对象是将动画帧元素组织起来的、准备播放的集合对象。它决定了动画帧的播放顺序以及时间间隔。
4.10.4动画动作
动画动作虽然也是持续动作类CCActionInterval的一个子类,但是其实现机制却是最为复杂的。
CCAnimation并不是能够执行的动作。它只是作为一个精灵帧的有序集合。同时,它也存有一些与动画相关的播放属性。
Cocos2d-x引擎也提供了一个专门用来执行动画的持续动作类,那就是类CCAnimate。
动画动作也是存在反序动作的。它的执行效果看上去就像是录像的倒带播放。

 /// 设置炮类型
 void SetGunType(bool bAdd);
 /// 发炮动作
 void EmitGun(CCPoint pt);
 /// 旋转炮
 /// @return 返回旋转的角度值
 float whirlGun(CCPoint &pt);
CCAnimation * m_pGunAnimation;
void Player::SetGunType(bool bAdd)
{
 if ( bAdd )
 {
  m_iGunType = m_iGunType % d_Gun_Count+1;
 }
 else
 {
  m_iGunType = (m_iGunType-1) % d_Gun_Count;
  m_iGunType = (0 >= m_iGunType) ? d_Gun_Count : m_iGunType;
 }
 char cBuffer[64]="";
 _snprintf(cBuffer, sizeof(cBuffer), "gun_%d_00000.png", m_iGunType);
 CCSprite * pShip = (CCSprite *)getChildByTag( t_Ship );
 CCSprite * pGun = (CCSprite *)pShip->getChildByTag( t_Gun );
 pGun->setDisplayFrame( CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName( cBuffer ) );
 // 创建发炮动画
 CCArray *pGunArray = CCArray::create();
 for (int i=0; i<d_Gun_Frame_Count; i++)
 {
  char cBuffer[64]="";
  _snprintf(cBuffer, sizeof(cBuffer), "gun_%d_0000%d.png", m_iGunType, i);
  CCSpriteFrame* pGunFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName( cBuffer );
  pGunArray->addObject( pGunFrame );
 }
 if (NULL != m_pGunAnimation)
 {
  m_pGunAnimation->release();
  m_pGunAnimation = NULL;
 } 
 m_pGunAnimation = CCAnimation::createWithSpriteFrames( pGunArray, 0.05f );
 m_pGunAnimation->retain();
}
void Player::EmitGun(CCPoint pt)
{
 // 设置炮旋转
 CCSprite * pShip = (CCSprite *)getChildByTag( t_Ship );
 CCSprite * pGun = (CCSprite *)pShip->getChildByTag( t_Gun );
 float angle = whirlGun( pt );
 CCLog("xy:(%f,%f),(%f,%f), angle:%f\r", pt.x, pt.y, pGun->getPosition().x, pGun->getPosition().y, angle);
 pGun->runAction( CCAnimate::create(m_pGunAnimation) );
 CCPoint ptBullet[PLAYER_COUNT] = {ccp(0, 0), ccp(0, 0), ccp(0, 0), ccp(1, 17)};
 ptBullet[m_PlayerPT].x += pShip->getPositionX();
 ptBullet[m_PlayerPT].y += pShip->getPositionY();
 m_BulletManage->Shoot(getPlayerPT(), pt, ptBullet[m_PlayerPT], pGun->getRotation(), false);
 CCLog("ZOrder: Bullet=%d, pShip=%d, pGun=%d", m_BulletManage->sharedBullet()->getZOrder(), pShip->getZOrder(), pGun->getZOrder());
}
float Player::whirlGun(CCPoint & pt)
{
 // 设置炮旋转
 CCSprite * pShip = (CCSprite *)getChildByTag( t_Ship );
 CCSprite * pGun = (CCSprite *)pShip->getChildByTag( t_Gun );
 float angle = (pt.y - pShip->getPosition().y)/(pt.x - pShip->getPosition().x);
 angle = atanf(angle)/M_PI*180;
 angle = (0 > angle) ? -(90 + angle) : 90 - angle;
 // 单击炮水平线以下,旋转90,-90
 if (pt.y < pShip->getPositionY())
 {
  angle = (pt.x >= pShip->getPositionX()) ? 90 : -90;
  pt.y = pShip->getPositionY()+15;
 }
 pGun->setRotation( angle );
 return angle;
}

4.11动画编辑器
4.11.1概述
4.11.2CocosBuildr编辑器中的精灵动画
4.11.3SpriteX草莓编辑器
4.11.4MotionWelder动画编辑器
4.12样例程序
4.13本章小结
chap5 用户交互
5.1概述
5.2玩家交互信息
5.3触摸操作的处理机制
以iOS为例,引擎使用了EAGLView来处理画面显示与用户交互。而根据iOS SDK的设计,它为开发者提供了四个用于响应用户操作的函数。
上面代码,来自于引擎目录当中的\cocos2dx\platform\ios\EAGLView.mm。
它的功能是将iOS平台中的用户操作信息传递到了引擎当中。然后,让引擎的用户操作机制来处理。
进入到引擎源代码中的platform\目录,就会看到针对不同平台而编写的CCEGLView文件。
在引擎当中,用户操作将会经过接收、分发、处理三个步骤。
5.4接收操作
引擎开发者设计了一个专门存储用户操作的类CCTouch。
每个类CCTouch的对象都包含了一个用户操作信息。其属性当中存储了id标识、x坐标、y坐标。这就是类CCTouch的作用。它能够将采集自不同平台的触摸信息,保存为统一的格式。
5.5分发机制
代码是来自于CCEGLViewProtoco.cpp文件的代码片段。函数handleTouchesBegin就是将各个平台的用户操作数据转化为引擎所用的用户操作数据。
在代码中,读者可以看到新创建的CCTouch对象。它们作为用户操作信息,被传递了一个m_pDelegate对象。这是一个用户操作的分发对象。
引擎专门提供了一个负责分发用户操作信息的类。类CCTouchDispatcher的作用就是响应对象分发用户操作信息,即类CCTouch对象。
所谓分发,就是类CCTouchDispatcher不仅仅只发送一次。它会向所有需要响应的对象发送用户操作信息。
类CCTouchDispatcher被一个单例对象持有成为了一个成员变量。
类CCTouchDelegate就是分发器发送用户操作信息的目标对象。我们姑且将此类型的对象称为用户操作委托对象吧!
类CCTouchDelegate具有三个子类:CCLayer、CCStandardTouchDelegate、CCTargetTouchDelegate。
5.6处理响应
类CCLayer是一个标准的委托对象。
作为目标委托对象,其响应函数所传递的参数都为单一的用户操作信息。而标准委托对象,其响应函数所传递的参数则是一个用户信息的集合。说的明白一点,目标委托对象是用来响应单点触摸的,而标准委托对象是用来响应多点触摸的。
说明:多点触碰是可以包含单点触碰的,因此标准委托对象可以替代目标委托对象的功能。
单点触摸却无法实现如捏合、分离的用户操作。
函数ccTouchBegan是唯一一个具有返回值的。如果返回值为真值,则分发器将会停止此次事件的分发。换句话说,在分发器中后续的委托对象将不能再接收到此次用户操作数据。
5.7多点触碰
5.8加速计的响应函数
在Cocos2d-x引擎当中,使用了类CCAccelerometer来存储加速度计的信息。类CCAccelerometer的作用与用户操作的分发器类似。区别在于用户操作的分发器可以拥有很多的委托对象。而加速度计只存在一个委托对象。
类CCAccelerometerDelegate就是加速度计的委托对象。开发者同样需要采用注册的方式来使用它。
5.9本章小结
chap9 文件操作模块
9.1概述
9.2引擎文件操作模块
9.3读取文件
9.4写入文件
9.5游戏中用户数据
9.5.1游戏中的用户数据
9.5.2用户数据的基本类型
9.5.3读取与写入操作
9.6示例程序
9.7本章小结
chap10 内存管理机制
10.1内存管理概述
10.2引用计数
10.3自动释放池
10.3.1使用方法
10.3.2实现原理
10.4管理模式
10.4.1引擎当中的应用
10.4.2缓冲区
10.5日志调试方式
10.6本章小结
chap14
引擎之外的附加功能
14.1概述
14.2网络通信支持
14.2.1HTTP介绍
14.2.2 curl库(libcurl)
14.2.3 HTTP在引擎中的运用
14.2.4 HTTP示例项目
14.2.5 Socket的介绍
14.2.6 BSD Socket在引擎中的应用
14.3收费模式
14.3.1下载计费
14.3.2内置计费
14.3.3广告版本
14.4社交网络游戏在游戏中的应用
14.4.1 Game Center
14.4.2 OpenFeint
14.5数据分析
14.5.1 Flurry介绍
14.5.2友盟 
20160612添加:
Cocos2d-x缺了什么:
底层通信模块(TCP/UDP、HTTP)
协议解析
文件跨平台读写
消息推送
游戏付费
第三方平台集成

如何扩展跨平台模块:
定义统一接口
分平台实现底层组件
隔离业务与底层组件的耦合
Android下通过JNI+Java实现平台功能扩展
类工厂模式隔离第三方平台的SDK差异

 (9)checkout单个文件到本地
 如果用 svn checkout 单个文件的URL 来检出一个文件到本地的话,会得到如下的错误提示:
svn: E200007: URL ' https://xxx' refers to a file, not a directory
那么,如何checkout单个文件呢?答案是用svn export命令即可。
HsqtekiMac-2:bin Hsq$ svn export https://192.168.0.103:443/svn/ZhuQue/WH20141225/hpkj.txt --username=hxhdell --password=123 hpkj.txt
A    hpkj.txt
Export complete.

HsqtekiMac-2:bin Hsq$ svn export https://192.168.0.103:443/svn/ZhuQue/WH20141225/hpkj.txt /Users/Hsq/Desktop/WH/hpkj.txt
A    /Users/Hsq/Desktop/WH/hpkj.txt
Export complete.
20160613添加:
8.5 JSON解析
除了使用XML作为数据交换格式之外,JSON也是一种广泛使用的数据交换格式,JSON同样具有跨平台、跨语言的优势,而且使用JSON作为数据交换格式时数据传输量更小。
从iOS5开始,iOS SDK提供了NSJSONSerialization类来支持JSON解析或生成。但有些时候,为了兼容以前版本的iOS,或者获得更强大的JSON支持,我们依然会选择使用第三方库来处理JSON。
常见的第三方库有SBJson、JsonKit等。
http://wenku.baidu.com/view/5e5ad34dccbff121dc368360.html?from=search
JSON学习总结及cJSON代码分析
JSON建构于两种结构
(1)键值对的集合
(2)值的有序列表
简单理解,JSON的定义由以下四句话就全部定义了。
1、并列的数据之间用逗号分隔。
2、映射用冒号表示。
3、并列数据的集合(数组)用方括号表示。
4、映射的集合(对象)用大括号表示。
typedef struct cJSON数据结构对JSON格式数据进行了描述。
cJSON_Parse
解析函数
传入一个字符串,返回一个cJSON
cJSON_Print
打印cJSON
传入一个cJSON,将会以排好版的格式打印JSON
cJSON_Delete
释放cJSON内存空间
因为返回的cJSON是通过malloc的方式分配的,如果用完不及时释放会造成内存泄露。
cJSON_GetArraySize
获取cJSON大小
返回数组或对象中的大小
cJSON_GetArrayItem
以index的方式获取cJSON数组或对象相应的项
找不到会返回NULL
cJSON_GetObjectItem
以名称的方式获取cJSON数组或对象相应的项
找不到会返回NULL
20160614添加:
3.5使用SQLite3数据库
iOS系统集成了一个轻量级的数据库:SQLite,SQLite并不想成为像Oracle、MySQL那样的数据库。SQLite只是一个嵌入式的数据库引擎,专门适用于资源有限的设备上(如手机、PDA等)适量数据存取。
虽然SQLite支持绝大部分SQL 92语法,也允许开发者使用SQL语句操作数据库中的数据,但SQLite并不像Oracle、MySQL数据库那样需要安装、启动服务器进程,SQLite数据库只是一个文件,SQLite不需要服务器进程。
提示:从本质上来看,SQLite的操作方式只是一种更为便捷的文件操作。手机的存储能力、计算能力都不足以让它充当服务器的角色。
3.5.1 iOS的SQLite编程
iOS的SQLite编程并没有使用Objective-C面向对象的语法,而是使用了原生的C函数库。为了在项目中使用iOS的SQLite编程API,需要先完成如下两步。
1、 为项目增加libsqlite3.dylib。
在Xcode的项目导航面板中单击需要增加SQLite支持的项目,然后单击项目导航面板右边TARGET目录下的项目名,再单击项目编辑区的“Build Phases”标签页。
单击“+”按钮添加函数库libsqlite3.dylib
添加SQLite函数库与《疯狂iOS讲义》上册介绍的添加Quartz Core、AudioToolbox等框架的方法完全相同——只是此处添加的不是框架,而是函数库。
在搜索框中输入sqlite,下面列表区内显示了libsqlite3.0.dylib、 libsqlite3.dylib,选择添加libsqlite3.dylib(它总代表最新版本的SQLite3)。
添加完成后,还是建议将libsqlite3.dylib拖入项目的Frameworks目录下——也就是将libsqlite3.dylib与项目的其他框架放在一起。

libsqlite3.dylib和libsqlite3.tbd有什么不一样?
Xcode7版本中找不到libsqlite3.dylib
Xcode6之前的版本用.dylib,之后的版本换成.tbd
基本上是一样的
libsqlite3.dylib与libsqlite3.0.dylib区别
实际上libsqlite3.dylib本身是个链接,它指向libsqlite3.0.dylib。也就是说在项目里如果你添加libsqlite3.dylib和添加libsqlite3.0.dylib其实是添加了同一个文件,没有区别,那为什么要添加libsqlite3.dylib呢?
其实这个指针总是指向最新的sqlite3动态库,比如说sqlite3库更新了,如果我们引用的是libsqlite3.dylib你就不需要做任何修改了。

2、在需要使用SQLite API的Objective-C类中使用如下代码导入libsqlite3.dylib。
#import<sqlite3.h>
接下来即可在程序中使用SQLite的API执行数据库访问了。libsqlite3.dylib提供了如下常用的函数。
sqlite3_close:关闭所代表的数据连接,并释放底层数据库连接资源。在调用该函数之前,必须先调用sqlite3_finalize函数所有的预编译Statement,调用sqlite3_blob_close函数关闭所有的BLOB处理器,否则该函数将会返回SQLITE_BUSY。
sqlite3_exec:用于执行没有返回值的SQL语句,其中第1个参数代表打开的数据库连接,第2个参数代表SQL语句,第3个参数代表执行完成的回调函数,第4个参数代表传给回调函数的调用参数,第5个参数用于封装执行SQL语句出错后的错误信息。
sqlite3_last_insert_rowid:返回代表的数据库最后一次插入行的ID。
sqlite3_changes:当执行某条DML语句之后,该函数用于返回受该条DML语句影响的记录条数。
sqlite3_total_changes:返回受DML语句影响的所有记录条数。该函数并非返回某条SQL语句影响的记录条数,而是返回本次数据库连接打开后,所有SQL语句影响的记录条数。
sqlite3_interrupt:中断一个长时间执行的查询语句。
sqlite3_complete:用于判断SQL语句是否执行完成。
提示:与该函数功能类似的还有sqlite3_complete16函数,该函数适用于使用UTF-16字符集的情形,而sqlite3_complete函数则适用于使用UTF-8字符集的情形.SQLite的函数库中还存在大量的这种情形,一个函数分两个版本:一个适用于UTF-8字符集,一个适用于UTF-16字符集。
sqlite3_open:打开与文件关联的数据库连接,并让第二个参数引用被打开的数据库连接。
提示:sqlite3_open16支持UTF-16字符集。sqlite3_open_v2支持使用更多的参数。
sqlite3_errcode:获取该数据库连接执行SQL语句的错误代码。
sqlite3_extended_errcode:获取该数据库连接执行SQL语句额外的错误代码。
sqlite3_errmsg:获取该数据库连接执行SQL语句的错误提示。该函数还有sqlite3_errmsg16版本,用于处理UTF-16字符集。
sqlite3_prepare:对SQL语句执行预编译,该函数的第1个参数代表打开的数据库连接,第2个参数代表SQL语句,第3个参数代表SQL语句的最大长度,第4个参数是传出参数,指向预编译SQL语句产生的sqlite3_stmt,第5个参数指向SQL语句中未使用的部分。
提示:该函数还有sqlite3_prepare_v2版本,代表该函数的最新版本,sqlite3_prepare16、sqlite3_prepare16_v2英语处理UTF-16字符集。
提示:iOS的SQLite支持都是面向C语言,而不是面向Objective-C的,因此这些API所需要的字符串都是C风格的字符串,而不是Objective-C的NSString对象。
3.5.4使用sqlite3工具
Mac OS X的lion版或更高版本的系统里已经自带了sqlite3工具,它是一个简单的SQLite数据库管理工具,类似于MySQL提供的命令行窗口。 有些时候,开发者可以利用该工具来查询、管理数据库。
3.5.5使用SQLite Manager管理数据库
20160616添加:
Cocos2d-x设计模式
http://www.docin.com/p-1485227612.html
1、观察者模式又称为发布-订阅模式
一个目标对象或被观察者可以注册多个观察者,当目标对象的状态改变的时候,可以通知观察者对象作出相应的响应。
这是标准的观察者模式的实现。
优点:
实现了目标对象和观察者、消息与观察者之间的抽象耦合。可以定义一种消息与消息处理对象的一对多关系,而不用担心彼此的实现细节。
Java实现
Office.java报社
interface Office
//添加观察者
void addObserver(People p);
//删除观察者
void deleteObserver(People p);
//通知所有的观察者
void notifyObserver(String msg);
People.java人
interface People
//收到来自观察者的消息
void update(String msg);
BrightOffice.java光明日报
class BrightOffice
//所有观察者的集合
ArrayList<People> peopleList=new ArrayList<People>();
OldPeople.java老人
class OldPeople
在Cocos2d-x中的被观察者是NotificationCenter,但它不是通过自身状态改变来通知观察者,而是通过显示地发送观察者感兴趣的消息(postNotification)来通知它们。
每一种消息类型可以对应多个观察者,同时,每一个观察者也可以观察多个消息类型。
其次,观察者定义相应的响应事件同消息类型关联,当某个地方触发postNotification来广播一个消息的时候,Notification会遍历所有的观察者,判断它们注册的消息类型是否匹配,如果匹配,则触发相应的注册响应事件。
最后,该观察者模式采用的是推模式,即由目标对象去通知所有的观察者。
其实NotificationCenter和NotificationObserver更准确的叫法是:订阅发布模式。
CCNotificationObserver相当于一个组装器,把对象object、对象的方法func、事件name组装到一起,变成一个Observer实体。
CCNotificationCenter中封装了一个CCArray容器,同一个对象、不同事件可以当做不同的Observer添加,总之,是以event来区别不同的观察者而不是object。
20160619添加:
Android C++高级编程——使用NDK
2014年1月第1版
chap2深入了解Android NDK
2.3.6检测Android NDK项目的结构
jni:该目录包含原生组件的源代码以及描述原生组件构建方法的Android.mk构建文件。Android NDK构建系统将该目录作为NDK项目目录并希望在项目根目录中找到它。
Libs:在Android NDK构建系统的构建过程中创建该目录。它包含指定的目标机体系结构的独立子目录,例如ARM的armeabi。在打包过程中该目录被包含在APK文件中。
Obj:这是一个中间目录,编译源代码后所产生的目标文件都保存在该目录下。开发人员最好不要访问该目录。
Android NDK项目最重要的组件是Android.mk构建文件,该文档描述了原生组件。理解构建系统是熟练运用Android NDK及其所有组件的关键。
2.4.1 Android.mk
Android.mk是一个向Android NDK构建系统描述NDK项目的GUN Makefile片段。它是每一个NDK项目的必备组件,构建系统希望它出现在jni子目录中。
#注释块后的第一条指令是用来定义LOCAL_PATH变量的。
#Android构建系统利用LOCAL_PATH来定位源文件。因为将该变量设置为硬编码值并不合适,所以Android构建系统提供了一个名为my-dir的宏功能。
LOCAL_PATH := $(call my-dir)
#Android构建系统将CLEAR_VARS变量设置为clear-vars.mk片段的位置。包含Makefile片段可以清除除了LOCAL_PATH以外的LOCAL_<name>变量,例如LOCAL_MODULE与LOCAL_SRC_FILES等。
include $(CLEAR_VARS)
#每一个原生组件被称为一个模块。LOCAL_MODULE变量用来给这些模块设定一个唯一的名称。
LOCAL_MODULE := helloworld_shared
#可选变量,用来重新定义生成的输出文件名称。默认情况下,构建系统使用LOCAL_MODULE的值作为生成的输出文件名称,但变量LOCAL_MODULE_FILENAME可以覆盖LOCAL_MODULE的值。
#helloworld_shared模块会生成一个共享库文件且构建系统会将它命名为libhelloworld.so。
LOCAL_MODULE_FILENAME := libhelloworld
#用LOCAL_SRC_FILES变量定义用来建立和组装这个模块的源文件列表。LOCAL_SRC_FILES变量可以包含用空格分开的多个源文件名。
LOCAL_SRC_FILES := helloworld/main.cpp \
                   ../../Classes/AppDelegate.cpp \
                   ../../Classes/ClientSocket.cpp \
                   ../../Classes/HelloControlScene.cpp \
                   ../../Classes/HelloXmlScene.cpp \
                   ../../Classes/moveLabel.cpp \
                   ../../Classes/MTNotificationQueue.cpp \
                   ../../Classes/SingleThread.cpp \
                   ../../Classes/SkillButton.cpp \
                   ../../Classes/tinyxml/tinyxmlparser.cpp \
                   ../../Classes/tinyxml/tinystr.cpp \
                   ../../Classes/tinyxml/tinyxml.cpp \
                   ../../Classes/tinyxml/tinyxmlerror.cpp \
                   ../../Classes/HelloWorldScene.cpp
#可选目录列表,NDK安装目录的相对路径,用来搜索头文件
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../Classes/tinyxml
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../../CocosDenshion
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../../CocosDenshion/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../../extensions
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../../external
#实际的Android应用程序并不直接使用静态库,并且应用程序包中也不包含静态库。静态库可以用来构建共享库。
#LOCAL_STATIC_LIBRARIES的变体,用来指明应该被包含在生成的共享库中的所有静态库内容。当几个静态库之间有循环依赖时,LOCAL_WHOLE_STATIC_LIBRARIES很有用。
LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static
LOCAL_WHOLE_STATIC_LIBRARIES += cocos_extension_static
#LOCAL_WHOLE_STATIC_LIBRARIES += box2d_static
#构建共享库。Android NDK构建系统将BUILD_SHARED_LIBRARY变量设置成build-shared-library.mk文件的保存位置。该Makefile片段包含了将源文件构建和组装成共享库的必要过程。
include $(BUILD_SHARED_LIBRARY)
$(call import-add-path,E:/2.0-x-2.03)
$(call import-add-path,E:/2.0-x-2.03/cocos2dx/platform/third_party/android/prebuilt)
#默认情况下,import-module函数宏只搜索<Android NDK>/sources目录。
$(call import-module,CocosDenshion/android)
$(call import-module,cocos2dx)
$(call import-module,extensions)
2.4.2 Application.mk
Application.mk是Android NDK构建系统使用的一个可选构建文件。和Android.mk文件一样,它也被放在jni目录下。Application.mk也是一个GUN Makefile片段。它的目的是描述应用程序需要哪些模块;它也定义所以模块的通用变量。
#默认情况下,Android NDK构建系统使用作用最小STL运行库,也被称为system库。可以用该变量选择不同的STL实现。
#APP_STL := stlport_shared
APP_STL := gnustl_static
#APP_CPPFLAGS变量列出了一些编译器标志,在编译任何模块的C++源文件时这些标志都会被传给编译器。
APP_CPPFLAGS := -frtti
#APP_CFLAGS变量列出了一些编译器标志,在编译任何模块的C和C++源文件时这些标志都会被传给编译器。
APP_CFLAGS += -Wno-error=format-security

20151123添加:
https://github.com/walzer
Cocos2d-x版本变迁:
2010年8月,HelloWorld发布
用OpenGL ES 1.1绘制静态图片
Boolean THelloWorldApp::initCocos2d()
{
    // init director
    CCDirector::getSharedDirector()->setOpenGLView(m_pMainWnd);
    CCDirector::getSharedDirector()->setDeviceOrientation(kCCDeviceOrientationLandscapeLeft);
    // load background image texture and get window size
    CCTexture2D * pTexture = CCTextureCache::sharedTextureCache()->addImage("splash-angry-01.png");
    CGSize size = CCDirector::getSharedDirector()->getWinSize();
    // create sprite instance
    CCSprite * pSprite = (new CCSprite())->initWithTexture(pTexture);
    pSprite->setPosition(CGPoint(size.width / 2, size.height / 2));
    pSprite->autorelease()->retain();
    // create layer instance
    CCLayer * pLayer = new CCLayer();
    pLayer->addChild(pSprite)->autorelease();
    // add layer to scene
    CCScene * pScene = CCScene::node();
    pScene->addChild(pLayer);
    // add scene to director
    CCDirector::getSharedDirector()->runWithScene(pScene);
    return TRUE;
}
2010年11月30日,Cocos2d-x第一个版本发布
第一年有125个基于Cocos2d-x的移动游戏或App,总下载量超过2000万。
2010年11月,0.99.4-x-0.7.0发布
2010年12月,0.99.4-x-0.7.1发布
2011年3月,0.8.0发布
2011年4月,0.8.2发布
更新日志:
支持Zwoptex输出的.plist格式
2011年4月,集成了网络库libcurl
2011年4月,在不同平台保存或读取文件文件,困难是保存或读取文件的路径
2011年4月,Cocos2dxSimpleGame和新手教程发布
2011年4月,设置默认的ndk版本为ndk-r5
ndk-r5支持STL
2011年5月,0.99.5-x-0.8.3发布
2011年5月,实现Android 3.0支持
2011年5月,0.99.5-x-0.8.4发布
2011年6月,0.99.5-x-0.8.5发布
支持Lua,xcode4模板
HelloLua/Resource/hello.lua
install-templates-xcode.sh
CCApplication::getCurrentLanguage()
Android上CCLabelTTF支持换行符
2011年7月,Cocos2dxSimpleGame更新至0.8.5并重新发布
2011年7月,1.0.0-x-0.9.0发布
与cocos2d-iphone v1.0.0同步发布的第一个版本
2011年8月,1.0.1-x-0.9.1发布
2011年10月,Cocos2d-x移植到BlackBerry
2011年10月,1.0.1-x-0.9.2发布
文档:
iOS有4种设备的物理方向:
Portrait
Upside Down
Landscape Left
Landscape Right
改变Android的设备的物理方向:
landscape
portrait
在Win32下模拟Android行为:
action on win32|equal to behavior on android
Shift + F1|Back key pressed
Shift + F2|Menu key pressed
minimize the window|switch to background
maximize the window|resume to foreground
0.9.2的更新日志:
2011年12月,1.0.1-x-0.10.0发布
主要特性:
集成pthread,实现CCTextrueCache::addImageAsync(),支持bada平台、android x86平台,升级Box2d到2.2.1,添加一些音效函数。
新文档:
如何使用pthread:
1、不要调用任何调用了Ref::retain()、Ref::release()、Ref::autorelease()的函数,因为AutoreleasePool不是线程安全的,除了数据结构之外,不要在一个新线程里调用任何cocos2d-x API
2、如果你想在新线程里加载资源,可以使用TextureCache::addImageAsync()
3、pthread_cond_wait好像有bug,第一次不会等待,随后就正常了
你应该牢记,OpenGL context不是线程安全的。
cocos2d-x/extensions/network/HttpClient.cpp使用pthread_t和pthread_mutex_t创建了一个网络线程。
传递一个结构给一个分离线程并设置互斥体的例子:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
struct SimpleStructure
{
    int data;
    float otherData;
};
void* ThreadFunction(void* arg)
{
    pthread_mutex_lock(&mutex);
    SimpleStructure* args = (SimpleStructure*)arg;
    // do something with args->data and args->otherData
    delete args;
    pthread_mutex_unlock(&mutex);
    return NULL;
}
void CreateThread()
{
    pthread_t thread;
    SimpleStructure* args = new SimpleStructure();
    args->data = 1;
    args->otherData = 2.0f;
    pthread_create(&thread, NULL, &ThreadFunction, args);
}
使用ndk-r7生成工程
在Android x86平台生成HelloWorld
ndk-r6开始支持x86平台
2012年3月,1.0.1-x-0.13.0-beta发布
请用ndk-r7b生成本机代码
2012年6月,2.0-rc2-x-2.0.1与cocos2d-iphone v2.0 rc2同步发布
实现CCBIReader,支持CocosBuilder
大的改进:
引擎的所有java文件移到cocos2dx/platform/android/java目录
Win32下,用OpenGL代替OpenGL ES
2012年8月,CCEditBox在iOS上实现了
2012年8月,2.0.2发布
2012年9月,2.0.3发布
更新extensions/CCBReader到v2.1 beta2支持骨骼动画
增加CCTableView代替CCListView
更新CCControlExtension
大的改进:
Javascript绑定更稳定
重构lua绑定
重构java库代码
2012年10月,Windows Phone 8版出来了
2012年11月,2.0.4发布
2013年2月,2.1发布
2013年6月,2.1.4发布
2013年9月,3.0-alpha版发布
2013年11月,编译Android例程的python脚本
build/android-build.python
不用安装cygwin了,删掉build_native.sh
# build hellocpp
$ cd cocos2d-x
$ python build/android-build.python hellocpp
# build all cpp samples
python build/android-build.python cpp
# build all lua samples
python build/android-build.python lua
# build all jsb samples
python build/android-build.python jsb
# build all samples
python build/android-build.python all
# pass parameter to ndk-build
python build/android-build.python -n clean hellocpp
2013年11月,在Android ARM上,char默认是无符号的,在Application.mk的APP_CPPFLAGS加上-fsigned-char变为有符号的,因为其它平台默认是有符号的
2013年11月,增加ThreadHelper::runOnGLThread()
cocos2d-x和OpenGL ES不是线程安全的。不必使用Schedule做类似的事情了。
2014年1月,3.0-beta版发布
2014年1月,2.2.2发布
2014年3月,3.0rc0版发布
2014年3月,2.2.3发布
2014年4月,3.0正式版发布
支持WinPhone8,C++基础底层优化:新渲染器、新API、性能飞跃
2014年5月,3.1发布
支持3D模型
2014年6月,2.2.4发布
2014年7月,2.2.5发布
2014年7月,3.2.0正式版发布
支持3D骨架动画、支持游戏手柄
2014年8月,3.3 alpha0发布
2014年9月,3.3 beta0发布
2014年12月,3.3正式版发布
2014年12月,2.2.6正式版发布
支持iOS 64位
2015年2月,3.4正式版发布
2015年3月,3.5发布
2015年4月,3.6发布
2015年8月,3.7发布
新增3D物理引擎和3D地图导航
2015年8月,3.7.1发布
2015年8月,3.8 beta0、3.8正式版发布
2015年11月,3.9发布

F:\hxhwin7\ProtoGen1>protoc --version
libprotoc 2.5.0
解决方案protobuf共有9个项目:
gtest:
gtest_main:
libprotobuf:libprotobuf.lib
libprotobuf-lite: libprotobuf-lite.lib
libprotoc:libprotoc.lib
lite-test:
protoc:protoc.exe
test_plugin:test_plugin.exe
tests:tests.exe
在F:\hxhwin7\ProtoGen1下写一个person.proto文件:
package Im;
message helloworld
{
       required int32         id=1;
       required string        str=2;
       optional int32         opt=3;
}
输入命令行:
F:\hxhwin7\ProtoGen1>protoc -I=F:\hxhwin7\ProtoGen1 --cpp_out=F:\hxhwin7\ProtoGe
n1 F:\hxhwin7\ProtoGen1\person.proto
就会自动生成person.pb.h和person.pb.cc这两个文件
F:\hxhwin7\ProtoGen1>protoc.exe --proto_path=. --cpp_out=. addressbook.proto

F:\hxhwin7\ProtoGen1>protoc -I=./ --cpp_out=./ model.proto
将生成对应的model.pb.h model.pb.cc

生成Java类:
F:\hxhwin7\ProtoGen1>protoc -I=./ --java_out=./ model.proto
F:\hxhwin7\ProtoGen1>protoc -I=./ --java_out=./ addressbook.proto
F:\hxhwin7\ProtoGen1\cn\vicky\model\seri\Model.java
F:\hxhwin7\ProtoGen1\com\example\tutorial\AddressBookProtos.java

附加包含目录:F:\client\protobuf-2.5.0\src
附加库目录:F:\client\protobuf-2.5.0\vsprojects\Debug
运行库:多线程调试 DLL (/MDd)
#include<iostream>
#include"person.pb.h"
#pragma comment(lib,"libprotobuf.lib")
#pragma comment(lib,"libprotoc.lib")
using namespace std;
using namespace Im;

int main()
{
 helloworld msg1;
 msg1.set_id(100);
 msg1.set_str("hello world");
 cout<<msg1.str()<<endl;
 cout<<msg1.id()<<endl;
 system("pause");
 return 0;
}

20150529添加:
在2.0.3中使用python脚本创建工程:

D:\hxhwin7\cocos2d-x-2.2.6\template\multi-platform-cpp
D:\hxhwin7\cocos2d-x-2.2.6\tools\project-creator
拷贝至
D:\hxhwin7\SixCocos2d-xVC2008\2.0-x-2.03\tools\project-creator
D:\hxhwin7\SixCocos2d-xVC2008\2.0-x-2.03\template\multi-platform-cpp
python create_project.py -project HelloSocket -package org.cocos2dx.application -language cpp
D:\hxhwin7\SixCocos2d-xVC2008\2.0-x-2.03\tools\project-creator>python create_pro
ject.py -project HelloSocket -package org.cocos2dx.application -language cpp
proj.ios                : Done!
proj.android            : Done!
proj.win32              : Done!
proj.winrt              : Done!
proj.wp8                : Done!
proj.mac                : Done!
proj.blackberry         : Done!
proj.linux              : Done!
proj.marmalade          : Done!
proj.tizen              : Done!
proj.wp8-xaml           : Done!
New project has been created in this path: D:\hxhwin7\SixCocos2d-xVC2008\2.0-x-2
.03\tools\project-creator/../../projects/HelloSocket
Have Fun!


D:\hxhwin7\cocos2d-x-2.2.6\tools\project-creator>python create_project.py -project HelloProtobuf -package org.cocos2dx.helloprotobuf -language cpp
附加包含目录添加
$(ProjectDir)..\..\..\cocos2dx\platform\third_party\win32\pthread
附加依赖项添加
libprotobuf.lib
#define GOOGLE_PROTOBUF_VERSION 2004001
#define GOOGLE_PROTOBUF_VERSION 2005000
protobuf版本要求:
C#版本使用protobuf-net r668
C++版本使用protobuf-2.5.0


python create_project.py -project HelloHttp -package org.cocos2dx.hellohttp -language cpp
cocos2d-x使用CCHttpClient类进行网络请求:
按钮请求处理:
void TestLayer::btncallback( CCObject* pSender )
{
 bool requestType_is_get=true;//采用get方式或者post方式
 if (requestType_is_get)
 {
  CCHttpRequest* request = new CCHttpRequest();//创建请求对象
  string str1 = "127.0.0.1:81/index.php?";
  string str2 = p_User_EditBox->getText();
  string str3 = p_Psw_EditBox->getText();
  string struser="username=";
  string strpsw="&password=";
  str1=str1+struser+str2+strpsw+str3;
  request->setUrl(str1.c_str());//设置请求的url,username和password已经包含在url中
  request->setRequestType(CCHttpRequest::kHttpGet);//设置为Get模式
  request->setResponseCallback(this, httpresponse_selector(TestLayer::onHttpRequestCompleted));//设置响应的回调
  request->setTag("GET test");
  CCHttpClient::getInstance()->send(request);//发送请求
  request->release();//释放请求
 }
 else
 {
  CCHttpRequest* request = new CCHttpRequest();//创建请求对象
  string str1 = "127.0.0.1:81/index.php";
  string str2 = p_User_EditBox->getText();
  string str3 = p_Psw_EditBox->getText();
  string struser="username=";
  string strpsw="&password=";
  str2=struser+str2+strpsw+str3;
  request->setUrl(str1.c_str());//设置请求的url,只是请求页面的url,并不包含username和password
  request->setRequestType(CCHttpRequest::kHttpPost);//设置为Post模式
  request->setResponseCallback(this, httpresponse_selector(TestLayer::onHttpRequestCompleted));//设置响应的回调
  const char* postData = str2.c_str();
  request->setRequestData(postData, strlen(postData));//设置请求数据,也就是username和password
  request->setTag("POST test");
  CCHttpClient::getInstance()->send(request);//发送请求
  request->release();//释放请求
 }
}
响应回调处理:
void TestLayer::onHttpRequestCompleted( CCHttpClient* client, CCHttpResponse* response )
{
 if (!response->isSucceed())//如果响应失败,输出错误信息
 { 
  CCString strError;
  strError.initWithFormat("Receive Error! \n%s\n",response->getErrorBuffer());
  m_labelStatusCode->setString(strError.getCString());
  return ;  
 }  
 std::vector<char> *buffer = response->getResponseData();//接收响应信息
 string recieveData;
 for (unsigned int i = 0; i < buffer->size(); i++)
 { 
  recieveData += (*buffer)[i]; 
 }
 size_t begin= recieveData.find("<body>")+6;//这里简单处理,获取<body>标签内数据,即是响应内容
 size_t end= recieveData.find("</body>");
 string result(recieveData,begin,end-begin);
 m_labelStatusCode->setString(result.c_str());
}

 
IE8里面输入:
http://localhost:81/index.php?username=jackystudio&password=123
GET方式会显示
Login Success
POST方式会显示
No Username or Password

采用get方式代码index.php
<html>
<body>
<?php
$open=fopen("log.txt","a" );
if(isset($_GET["username"]) && isset($_GET["password"]))  
{
if($_GET["username"]=="jackystudio" && $_GET["password"]=="123")  
{  
fwrite($open,"Username:".$_GET["username"]);  
fwrite($open,"\r\n");  
fwrite($open,"Password:".$_GET["password"]);  
echo "Login Success";
}  
else  
{  
fwrite($open,"Wrong Username or password!");  
echo "Login Failed";
}  
}  
else  
{  
fwrite($open,"No password");  
echo "No Username or Password";
}  
fclose($open);  
?>
</body>
</html>

采用post方式代码index.php
<html>  
<body>  
<?php  
$open=fopen("log.txt","a" ); //Save password  
if(isset($_POST["username"]) && isset($_POST["password"]))  
{  
if($_POST["username"]=="jackystudio" && $_POST["password"]=="123")  
{  
fwrite($open,"Username:".$_POST["username"]);  
fwrite($open,"\r\n");  
fwrite($open,"Password:".$_POST["password"]);  
echo "Login Success"; //return to client  
}  
else  
{  
fwrite($open,"Wrong Username or password!");  
echo "Login Failed"; //return to client  
}  
}  
else  
{  
fwrite($open,"No password");  
echo "No Username or Password"; //return to client  
}  
fclose($open);  
?>  
</body>  
</html>  

遇到的问题1:
HTTP 错误 500.0 - Internal Server Error
发生未知 FastCGI 错误
解决办法:
第一步:打开Internet信息服务(IIS)管理器,在左侧的树形列表找到“应用程序池”
第二步:在右侧的列表中右击“DefaultAppPool”弹出菜单,选择“高级设置”,弹出“高级设置”对话框。
第三步:找到“标识”选项卡,点击右侧的方形按钮,弹出“应用程序标识”对话框中的“内置账户”的下拉菜单中选择“LocalSystem”,然后重启IIS服务器,至此,这个问题就彻底解决了。
Cocos2d-x高级开发教程——制作自己的《捕鱼达人》(王哲作序推荐)读书摘要(20130715、20150529、20151123、20160107、20160128、20160603)
2013年6月第1版

锚点指定了贴图上和所在节点原点(也就是设置位置的点)重合的点的位置。因此只有在CCNode类节点使用贴图的情况下,锚点才有意义。
2.3 C++中的Cocos2d-x内存管理
基于Cocos2d-iPhone的Objective-C风格的内存管理是Cocos2d-x的一个特色。把Objective-C的内存管理方式引入C++,使得游戏开发的内存管理下降了一个层次。 
2.3.1复杂的内存管理
Boost库引入的只能指针从对象所有权传递的角度来解决内存管理问题。
2.3.2现有的智能内存管理技术
目前,主要有两种实现智能管理内存的技术,一是引用计数,一是垃圾回收。
引用计数是资源自我管理的一种机制,资源本身以引用计数为零来得知别人不再需要自己,从而把自己kill掉。
引用计数:它是一种很有效的机制,通过给每个对象维护一个引用计数器,记录该对象当前被引用的次数。当对象增加一次引用时,计数器加1;当对象失去一次引用时,计数器减1;当引用计数为0时,标志着该对象的生命周期结束,自动触发对象的回收释放。引用计数解决了对象的生命周期管理问题,但堆碎片化和管理繁琐的问题依然存在。
垃圾回收:回收机制包括分代复制垃圾回收、标记垃圾回收和增量垃圾回收。
chap3游戏的基本元素
3.1CCDirector:大总管
在CCDirector中,我们定义了以下管理场景的方法:
启动游戏,并运行指定场景。 这个方法在主程序启动时第一次启动主场景时调用。      
三种切换场景的方法
暂停当前运行场景中的所有计时器和动作,场景仍然会显示在屏幕上。
恢复当前运行场景中被暂停的计时器和动作。
结束场景,同时退出应用。
3.2场景
场景只是层的容器,另一个作用是流程控制。
3.3层
层也扮演了容器的角色。
ZOrder值越大显示顺序越靠上。ZOrder的默认值是0。
捕鱼游戏场景大致由背景层、动作层、触摸层和菜单层组成。
层可以接受用户输入时间,包括触摸、加速度计和键盘输入等。

3.1.1CCNode类的成员数据
CCNode类的主要保护成员数据(子类可见,Protected关键字)如表3-2所示。
3.12CCNode类的函数
CCNode类的主要函数如表3-3所示。
函数名,返回类型,描述
getScale,浮点型,获得缩放系数
setScale,空,设置缩放系数
3.1.3坐标系简介
通过前面的学习,大家会对CCNode类的属性和方法有所了解,但是可能有些名词会令你困惑,如OpenGL坐标系,世界坐标系,节点相对坐标系,仿射变换等。本节就来解决这些问题。
1.OpenGL坐标系
Cocos2D-x以OpenGL和OpenGL ES为基础,所以自然支持OpenGL坐标系。该坐标系原点在屏幕左下角,x轴向右,y轴向上。
屏幕坐标系使用的是不同的坐标系统,原点在屏幕左上角,x轴向下。iOS的屏幕触摸事件CCTouch传入的位置信息使用的是该坐标系。因此在Cocos2D-x中对触摸事件做出响应前,需要首先把触摸点转化到OpenGL坐标系。这一点在后面的触屏信息中会详细介绍,可以使用CCDirector的convertToGL方法来完成这一转化。

3.4.5常用成员
除了前面介绍过的部分成员外,CCSprite还拥有以下常用的成员。 
1.初始化方法
CCSprite拥有许多不同的初始化方法,可以方便地创建精灵。
使用这些方法,我们不仅可以通过图片文件来创建精灵。还可以直接使用纹理或精灵框帧来创建精灵。
a.使用图片文件:
使用两个静态工厂方法
使用它们的构造函数加初始化方法
b.使用CCTexture2D
使用CCTexture2D纹理创建精灵的相关方法也有两个静态工厂方法和构造函数加初始化方法。
CCTexture2D类型的pTexture参数为纹理对象,可以使用CCTextureCache类的addImage方法把图片文件加载为纹理并返回,而rect与使用图片文件创建精灵的rect参数相同。
c.使用CCSpriteFrame创建
使用CCSpriteFrame精灵框帧创建精灵也有一个静态工厂方法和构造函数加初始化方法。
CCSpriteFrame类型的pSpriteFrame参数为纹理框帧。CCSpriteFrame保存了一个CCTexture2D的引用与一个CCRect来表示纹理中的一部分。使用CCSpriteFrame初始化精灵时,也可使精灵显示部分纹理。
2.纹理相关的属性
CCSprite提供了一下与纹理有关的属性,用于获取或设置精灵的内容。

3.5精灵类
精灵类CCSprite是一张二维的图片对象,它可以用一张图片或者一张图片的一块矩形部分来定义。CCSprite和它的子类可以作为精灵批处理类的子类。
3.5.5精灵帧缓存类CCSpriteFrameCache
CCSpriteFrameCache是一个单例模式,不属于某个精灵,是所有精灵共享使用的。
CCSpriteFrameCache类的主要函数见表3-15。
函数名,返回类型,描述
spriteFrameByName,精灵帧,根据定义的名称找到精灵帧,如果没有对应的,返回空。
4.1动作类
CCAction类继承于对象类CCObject,有三个子类:有限时间动作,跟随,移动速度,其中有限时间动作分为瞬时动作和延时动作。
4.16组合动作
1.CCSequence
定义一个动作序列,可以使用动作的CCArray数组;也可以把所有的动作作为参数传入create函数中,最后结尾参数使用NULL(空值)即可;还可以把两个有限时间动作按顺序传入create函数中。

3.5.3定时器事件
Cocos2d-x为我们提供了两种方式实现定时机制——使用update方法以及使用schedule方法。
1.update定时器
第一种定时机制是CCNode的刷新事件update方法。
2.schedule定时器
另一种定时机制是CCNode提供的schedule方法,可以实现以一定的时间间隔连续调用某个函数。由于引擎的调度机制。这里的时间间隔必须大于两帧的间隔,否则梁振期间的多次调用会被合并成一次调用。 
3.定时器相关方法
定时器机制是Cocos2d-x调度机制的基础。Cocos2d-x的调度是纯粹的串行机制,因此所有函数都运行在同一个线程。
3.7Cocos2d-x调度原理
3.7.1游戏主循环
在主循环中,我们主要进行了以下3个操作:
(1)调用了定时调度器的update方法,引发定时器事件。
(2)如果场景需要被切换,则调用setNextStage方法,在显示场景前切换场景。
(3)调用当前场景的visit。

摄像机CCCamera继承自CCObject类,

每一个节点都需要使用CCCamera。主要函数:

init初始化函数

setEyeXYZ设置眼睛(视角位置)的坐标

setCenterXYZ设置中心(目标位置)的坐标

setUpXYZ设置上方(摄像机方向)的坐标

getEyeXYZ获取眼睛的坐标

getCenterXYZ获取中心的坐标

getUpXYZ获取上方的坐标

12.1Camera类的设计----借鉴了微分几何中的活动标架(P,R,U,L)
我们用4个摄像机向量:右向量,上向量,观察向量以及位置向量来定义摄像机相对于世界坐标系的位置和朝向。这些向量实质上为相对世界坐标系描述的摄像机定义了一个局部坐标系。由于右向量,上向量,观察向量定义了摄像机在世界坐标系中的朝向,有时我们也将这三个向量统称为方向向量。方向向量必须是标准正交的。如果一个向量集合中的向量都彼此正交,且模均为1,则称该向量是标准正交的。引入这些约束的原因是在后面我们要将这些向量插入到一个矩阵的某些行中,以使该矩阵成为标准正交矩阵(如果一个矩阵的行向量是标准正交的)。标准正交矩阵的一个重要性质是其逆矩阵与其转置矩阵相等。
用上述4个向量来描述摄像机,我们就可对摄像机实施如下6种变换。
绕向量right的旋转(俯仰,pitch)
绕向量up的旋转(偏航,yaw)
绕向量look的旋转(滚动,roll)
沿向量right方向的扫视(strafe)
沿向量up方向的升降(fly)
沿向量look的平动
通过上述6种运算,摄像机可沿3个轴平动以及绕3个轴转动,即摄像机具有6个自由度(degrees of freedom)。
12.2.2绕任意轴的旋转
D3DXMatrixRotationAxis绕由向量A确定的任意轴进行旋转
12.2.3俯仰,偏航和滚动
由于方向向量描述了摄像机在世界坐标系中的朝向,所以当摄像机发生俯仰pitch,偏航yaw或滚动roll时,我们必须指定方向向量应如何更新。
俯仰,即绕摄像机的right向量旋转
偏航,即绕摄像机的up向量旋转
滚动,即绕摄像机的look向量运动
12.2.4行走,扫视和升降
这里的“行走(walking)”是指沿着摄像机的观察方向(即沿着向量look的方向)的平动。
“扫视(strafing)”是指保持观察方向不变,沿向量right方向从一边平移到另一边。“升降(flying)”是指沿着向量up方向的平动。为了能够沿这些轴中的任意一个进行平动,我们只需将摄像机当前位置向量和一个与该轴方向相同的向量相加即可。
12.4小结
我们通过维护4个向量——right,up,look和position来表示摄像机在世界坐标系中的位置和朝向。有了这些描述工具,我们就可轻松地实现具有6个自由度的摄像机,这样就为飞行模拟器和第一人称视角游戏提供了一个灵活的摄像机接口。


chap5动画与场景特效
5.1动画
我们需要引入一种特殊的动作:动画。
5.1.1概述
理论上来说,帧动画可以实现任何一种效果。
帧动画与电影胶片类似。动画的帧就是指被显示出来的每一张图片。
考虑到制作成本以及回放成本,如果没有必要,我们一般不在游戏中大规模使用动画。
5.1.2使用动画
动画由帧组成。显卡在绘图时,在纹理间切换时一个开销巨大的操作,由于精灵可以显示部分纹理,因此通常更为高效的做法是把动画用到的多个纹理按照一定顺序排列起来,然后放置在同一个纹理下。在创建动画时,我们需要制定动画所使用的纹理以及每一帧使用的是纹理的哪一部分。
一个CCSpriteFrame框帧包含两个属性,纹理与区域。 一个框帧可以完整地描述精灵显示的内容,因此在动画中,我们使用框帧来表示每一帧的内容。
为了描述一帧,除了框帧,显然我们还需要记录帧的持续时间。动画帧类CCAnimationFrame同样包含两个属性,其一是对一个框帧的引用,其二是帧的延时。动画类CCAnimation是对一个动画的描述,它包含显示动画所需要的动画帧。对于匀速播放的帧动画,只需设置所有帧的延时相同即可。
我们使用CCAnimation描述一个动画,而精灵显示动画的动作则是一个CCAnimate对象。动画动作CCAnimate是精灵显示动画的动作,它由一个动画对象创建,并由精灵执行。动画与动画动作的关系就如同CD光盘和CD播放机的关系一样——前者记录了动画的内容,而后者是播放动画的工具。
5.2场景特效
特效类CCTransitionScene派生自CCScene,换句话说,场景特效本身也是一个场景。场景特效的实现方式与复合动作类似,场景特效是一类特殊的场景,它们包含了另一个场景(称作原场景),把原场景当做参数来创建一个特效场景。

chap6 Cocos2D-x中的事件处理机制
在智能手机中,主要的输入操作是通过触摸屏幕,重力感应等方式实现的,而输入文字主要通过虚拟键盘等实现的。
6.1触屏事件
在Cocos2D-x中,继承自触屏代理协议CCTouchDelegate的布景层类CCLayer可以检测触屏事件并调用回调函数。首先来看CCTouchDelegate类的继承关系。
CCTouchDelegate的子类中,CCStandardTouchDelegate协议是标准的获得多点触摸点的范例,CCTargetedTouchDelegate不用处理触摸点的集合,它是返回单点的。
此外,我们常用的类是布景层类CCLayer,也就是说,在布景层类中可以重写ccTouchesBegan等函数获得触屏的信息。
6.1.1触点类CCTouch
一般把触摸点的信息放入触点类CCTouch中。CCTouch类的公共函数见表6-1。
函数名,返回类型,描述
locationInView,坐标点,获得点在画布中的位置
previousLocationInView,坐标点,之前在画布中的位置
setTouchInfo(ID号,x坐标,y坐标),空,设置信息
getID,整形,获得ID号



chap8粒子效果
当我们希望在游戏中模拟这些大规模运动的物体时,通常有如下两种方法。
使用帧动画来模拟。设计帧动画并把它渲染为图片序列来模拟特效,不但生成的动画体积庞大,也无法调整其运动参数,因此有失灵活性。
本章即将介绍的粒子效果。我们把每一个对象都看做一个粒子,赋予它们一定的属性(例如外观、位置、速度、加速度和生成时间等),使它们按照一定的规律产生、运动并最终消失。
在粒子效果中,通常存在一个对所有粒子进行统一调度的引擎,称作粒子系统,它负责粒子的产生,随时间改变粒子的状态,以及最后回收不再需要的粒子。如果按照粒子系统的维数来区分,粒子系统可以分为二维粒子系统与三维粒子系统两种。
8.1Cocos2d-x中的粒子系统
与其他的粒子引擎一样,CCParticleSystem实现了对粒子的控制与调度,对粒子的操作包括如下几种。
产生粒子:这部分也被称作粒子的发射器(emitter)。
更新粒子状态:引擎会随时间更新粒子的位置、速度以及其他状态。
回收无效粒子:当粒子的生命周期结束后,就会被系统回收。
因此,为了创建一个粒子效果,我们需要定义粒子如何产生以及状态如何改变。

在粒子系统中,至少要包括四大部分:
大量的粒子对象、每个粒子遵守的规律、每个粒子的随机性和持续更新的粒子状态。
两种模式:
重力式粒子系统;放射式粒子系统。
粒子系统说明了这些粒子要遵守某种规则,而规则是通过一系列参数定义的。
参数名称,参数表述,适用范围
重心,粒子系统的重心,重力式或放射式
速度,粒子的初速度,重力式
方向,粒子的初速方向,重力式或放射式
尺寸,粒子的大小,重力式或放射式
生命,粒子存在的时间,重力式或放射式
颜色,粒子的颜色,重力式或放射式
自转角度,粒子是否要绕着自己的轴心旋转,重力式或放射式
公转角度,粒子是否要以重心为轴心旋转,放射式

chap9大型地图
超过屏幕大小的地图,玩家可以像在即时战略游戏中一样在地图中滚动游戏画面。
9.1瓦片地图
把这些瓦片拼接在一起,一个完整的地图就组合出来了,这就是瓦片地图的原理。
在Cocos2d-x中,瓦片地图实现的是TileMap方案。
chap7 Cocos2d-x中的瓦片地图集
地图编辑器的tile(瓦片,瓷砖,瓦块)是贴图的元素和事件引发的记录点。
地图编辑器最大的优点就在于:重复使用性高,背景地图制作速度快,简单易用等。
所准备的tile也不能太少,有些tile可能同样都是墙壁,却有好几种不同的样式,有的tile上面有斑驳的痕迹,有的tile上面可能有涂鸦等,
又如树之类的背景,可能也要准备个好几种不同树的tile。

在很多游戏中,整个游戏场景中除了主角精灵之外,游戏的地图背景也是“重头戏”。在手机游戏的开发中,为了节约内存空间,使用图素拼接的方法组成整个地图。也就是说,首先确定图素块(一般为正方形)的大小,其次美术人员绘制图素块,再次由策划和美术人员根据不同项目的需求使用地图编辑器将图素拼接成大地图,最后将生成的数据文件和图素交给程序处理。
7.1瓦片地图集及编辑器
Cocos2d-x中支持瓦片地图集,Tiled地图编辑器可以生成Cocos2d-x支持的地图文件。
7.1.1瓦片地图的种类及用途
Cocos2d-x中的瓦片地图集支持普通视角地图和45度角地图。
普通视角地图在多种类型的游戏中被使用。如横版动作闯关游戏、俯视视角游戏等。这种情况下,一般在使用地图中为不同的地图块赋予不同的“意义”,如部分地图块含有阻挡,部分地图块含有机关等,一般通过给图素“编号”的方法获得。
45度角地图一般应用于塔防游戏,战旗游戏和建造类游戏。在这些游戏中,经常要求用户点击相应的地图图素块,并在图素块上“建设”某些“建筑”。获得图素的索引,并修改图素便可实现该功能。
地图编辑器之地形标示:
障碍物的设定
行走速度:高山河流=0,沼泽地带=1,沙漠区=2,草原=3,路面=4,
tile的数值:
草原=2,沙漠=4
行走能力是每回合8步,
走到草原区的tile时,会消耗掉2步的能力,剩下6步
一直都在草原区行走的话,算算每一回合应该可以走4格tile的长度;
在沙漠区行走的话,每一个tile的长度会消耗掉4步,一回合只能走两个tile的长度;
经过两个草原和一个沙漠的话,能在一回合走完(2个2步+1个4步=8步)
地图编辑器之事件处理:每一个tile除了地形数值之外,还有一个事件数值,用来表示事件的处理。
玩过角色扮演游戏的人应该都知道,当玩家控制主角行经某处时,会出现一些偶发事件,像是忽然有人会跑出来跟你讲话,或是遇到特定的敌人等等,像这些事件,通常都是由地图编辑器来予以设定的

7.1.2Tiled地图编辑器
Tiled地图编辑器的特性如下:
使用基于XML编码形式的地图数据文件使其可以在不同的游戏引擎中通用。
支持普通和45度角两种视角。
对象的放置位置可以精确到像素。
支持撤销/重做和复制/粘贴的操作。
支持图素,层次和对象等通用的概念。
自动重新载入图素集。
可以充值图素的大小和偏移。
支持图章刷和填充等高效工具。
支持以通用的格式输入输出打开和存储文件。
7.1.3用Tiled地图编辑器编辑地图
7.1.4添加精灵层
精灵层其实就是没有图素格位置限制的地图层。精灵层一般放置到图素和机关(如传送门)。精灵层和地图层结合叠加就组成了整个地图。
7.1.5Tiled地图编辑器数据文件
Tiled地图编辑器生成的TMX数据文件类似于XML文件。
7.1.6瓦片地图集类CCTMXTiledMap
7.1.7地图层类CCTMXLayer
地图由地图层组成。
7.1.8地图精灵组类CCTMXObjectGroup

Chap10 Cocos2d-x绘图原理及优化
Cocos2d-x是对不同平台下OpenGL的包装。下面我们介绍更为底层却又十分重要的内容,那就是Cocos2d-x的绘图原理以及游戏优化方法。
OpenGL是一个开放的、跨平台的高性能图形接口。OpenGL ES则是OpenGL在移动设备上的衍生版本,具备与OpenGL一致的结构。Cocos2d-x就是一个基于OpenGL的游戏引擎,因此它的绘图部分完全由OpenGL实现。
OpenGL是一个基于C语言的三维图形API,基本功能包含绘制几何图形、变换、着色、光照、贴图等。除了基本功能, OpenGL还提供了诸如曲面图元、光栅操作、景深、shader编程等高级功能。在本书中,我们仅介绍一些必要的概念与技术。
1.状态机
状态机的设计有许多优势。OpenGL把所有的参数作为状态来保存,如果没有设置新的参数,则会一直采用当前的状态来绘图。
另一个优势在于,我们可以把绘图设备认为地分为两个部分:CPU和GPU分别充当客户端与服务器的角色。在实际使用中,OpenGL的客户端与服务器端是可以分离的,因此可以轻而易举地实现远程绘图
2.坐标系
OpenGL是一个三维图形接口,在程序中使用右手三维坐标系。
屏幕向右的方向为X方向,屏幕向上的方向为Y方向,由屏幕指向我们的方向为Z方向

DirectX9.0 3D游戏开发编程基础(段菲译)
第Ⅰ部分基础知识 必备的数学知识
左手坐标系和右手坐标系的差别体现在z轴的正方向上。在左手坐标系中,z轴正方向穿进纸面。在右手坐标系中,z轴正方向传出纸面。[+x水平向右,+y垂直向上。]
第Ⅱ部分Direct3D基础Chap2绘制流水线
2.3.8视口变换
视口变换的任务是将顶点坐标从投影窗口转换到屏幕的一个矩形区域中,该矩形区域称为视口。在游戏中,视口通常是整个矩形屏幕区域。但视口也可以是屏幕的一个子区域或客户区。矩形的视口是相对于窗口来描述的,因为视口总处于窗口内部并且其重要位置要用窗口坐标来指定。
[DX9的3D世界坐标系是左手三维坐标系,+z穿进纸面,+x水平向右,+y垂直向上]

OpenGL负责把三维空间中的对象通过投影、光栅化转换成二维图像,然后呈现到屏幕上。
在Cocos2d-x中,我们只需要呈现二维的图像,因此Z坐标只用作控制游戏元素的前后顺序,通常不做讨论。
当我们绘制图形的时候,OpneGL会把图形绘制在当前的绘制坐标系中。
3.渲染流水线
当我们把绘制的图形传递给OpenGL后,OpenGL还要进行许多操作才能完成3D空间到屏幕的投影。通常,渲染流水线过程有如下几步:显示列表、求值器、顶点装配、像素操作、纹理装配、光栅化和片段操作等。
OpenGL ES 1.0版本中采用的是固定渲染管线。
OpenGL从2.0版本开始引入了可编程着色器(shader)。
http://book.51cto.com/art/201305/394859.htm
10.1.3矩阵与变换
在10.1.1节中,我们曾经提到过坐标系变换。作为绘图的一个强大工具,坐标系变换在OpenGL开发中被广泛采用。为了理解坐标系变换,首先需要了解一些坐标系变换所需的数学知识,这些知识也是计算机图形学的数学基础。
OpenGL对顶点进行的处理实际上可以归纳为接受顶点数据、进行投影、得到变换后的顶点数据这3个步骤。当我们设置好OpenGL的坐标系,并传入顶点数据后,OpenGL就会通过一系列计算把顶点映射到世界坐标系之中,再把世界坐标系中的点通过投影变换为可视平面上的点。这一系列变换的本质是通过对顶点坐标进行线性运算,得到处理后的顶点坐标。在计算机中,坐标变换是通过矩阵乘法实现的,用向量表示坐标,矩阵表示变换形式,则变换后的顶点坐标可以用向量与矩阵的乘法来表示。使用矩阵乘法的优点在于,计算机(包括移动设备)的图形硬件通常对矩阵乘法进行了大量优化,从而大大提高了运算效率。
点、向量与矩阵
在计算机中,通常不直接使用与点维度数量一样的向量来表示一个点,因为这样就无法利用矩阵乘法来对点进行平移等操作了。因此,在计算机图形学中,通常采用齐次坐标来表示一个顶点。具体地说,齐次坐标系中每一个点的维度比顶点维度多1,多出的一个维度值为1。对于任何三维中的顶点(x, y, z),它在齐次坐标系中的向量为[x, y, z, 1],例如,空间中的(1.2, 5, 10)对应的向量为[1.2, 5, 10, 1]。
变换利用矩阵表示。常见的变换包含平移变换、旋转变换和缩放变换等,它们分别对应了平移矩阵、旋转矩阵和缩放矩阵等。下面以平移矩阵为例,展示如何使用矩阵乘法实现坐标变换。平移矩阵为{{1,0,0,t_x},{0,1,0,t_y},{0,0,1,t_z},{0,0,0,1}}
其中(t_x,t_y,t_z)为平移的方向向量。若我们希望把点(1.2, 5, 10)平移(6, 5, 4)距离,则计算矩阵的乘法如下:
{{1,0,0,6},{0,1,0,5},{0,0,1,4},{0,0,0,1}}×{{1.2},{5},{10},{1}}={{7.2},{10},{14},{1}}
可以看到,我们得到了平移后的点(7.2, 10, 14)。上面是对一个点进行一次变换的情况,如果希望对点进行多次变换,则应该依次构造每个变换对应的矩阵,并利用矩阵乘法把所有矩阵与顶点向量相乘。例如,对点P依次进行缩放、平移、缩放和旋转操作,则分别构造它们对应的变换S_1、T、S_2、R,按照如下公式计算变换后的点P':P'=R×S_2×T×S_2×P
OpenGL维护了一个当前绘图矩阵,用于表示当前的绘图坐标系。这个矩阵被初始化为单位矩阵,此时绘图坐标系与世界坐标系相同,当我们不断地在绘图矩阵后乘上新的矩阵时,会相应地改变绘图坐标系。在上面的例子中,R×S_2×T×S_2即为绘图矩阵,它表示了一个绘图坐标系。在此点上绘制的P点坐标经过映射后,可以得到它在世界坐标系中对应的坐标P'。
OpenGL为我们提供了一系列创建变换矩阵的函数(如表10-1所示),因此,在实际开发中,我们并不需要手动构造变换矩阵。这些函数的作用是创建一个变换矩阵,并在当前绘图矩阵的后方乘上这个矩阵。现在对刚才的例子稍作修改,我们不再希望只对点P进行一系列变换,而是希望对一个完整的图形进行变换。以下代码绘制一个任意的图形,并将此图形首先放大2.5倍,然后平移(1, 2, 3)距离,最后缩小0.8倍:
//OpenGL ES 1.0
glScalef(0.8f, 0.8f, 0.8f);//乘上缩放矩阵
glTranslatef(1.0f, 2.0f, 3.0f);//乘上平移矩阵
glScalef(2.5f, 2.5f, 2.5f);//乘上缩放矩阵
DrawObject();//绘制任意图形
表10-1 常见的OpenGL ES 1.0变换函数
函数名 描述
glTranslate  平移变换
glRotate  旋转变换
glScale  缩放变换
必须指出,无论是表10-1还是上面的代码,都明确提到了这些变换函数隶属于OpenGL ES 1.0。实际上,在Cocos2d-x 2.0采用的OpenGL ES 2.0中,这些函数已经不可使用了。OpenGL ES 2.0已经放弃了固定的渲染流水线,取而代之的是自定义的各种着色器,在这种情况下变换操作通常需要由开发者来维护。所幸引擎也引入了一套第三方库Kazmath,它使得我们几乎可以按照原来OpenGL ES 1.0所采用的方式进行开发。表10-2列出了常用OpenGL矩阵操作函数的替代函数,而下面的代码则可以在Cocos2d-x 2.0中实现变换操作:
//Cocos2d-x 2.0(OpenGL ES 2.0)
kmGLScalef(0.8f, 0.8f, 0.8f);//乘上缩放矩阵
kmGLTranslatef(1.0f, 2.0f, 3.0f);//乘上平移矩阵
kmGLScalef(2.5f, 2.5f, 2.5f);//乘上缩放矩阵
DrawObject();//绘制任意图形
表10-2 Cocos2d-x 2.0中矩阵函数的替代函数
OpenGL ES 1.0函数 替代函数 描述
glPushMatrix  kmGLPushMatrix 把矩阵压栈
glPopMatrix kmGLPopMatrix 从矩阵栈中弹出
glMatrixMode  kmGLMatrixMode 设置当前矩阵模式
glLoadIdentity  kmGLLoadIdentity 把当前矩阵置为单位矩阵
glLoadMatrix  kmGLLoadMatrix 设置当前矩阵的值
glMultMatrix  kmGLMultMatrix 右乘一个矩阵
glTranslatef  kmGLTranslatef 右乘一个平移矩阵
glRotatef  kmGLRotatef 右乘一个旋转矩阵
glScalef kmGLScalef 右乘一个缩放矩阵

10.2.2渲染树的绘制
无论如何复杂的游戏场景也都是精灵通过不同的层次、位置组合构成的,因此只要可以把精灵按照前后层次、不同的位置绘制出来就完成了游戏场景的绘制。
渲染树是由各种游戏元素按照层次关系构成的树结构,它展示了Cocos2d-x游戏的绘制层次,因此游戏的渲染顺序就是由渲染树决定的。
回顾Cocos2d-x游戏的层次:导演类直接控制渲染树的根节点——场景,场景包含多个层,层中包含多个精灵。实际上,每一个上述的游戏元素都在渲染树中表示为节点,游戏元素的归属关系就转换为了节点间的归属关系,进而形成树结构。
10.2.3坐标变换
在绘制渲染树中,最关键的步骤之一就是进行坐标系的变换。
没有坐标系的变换,则无法在正确的位置绘制出纹理。
许多以“km”为前缀的函数,是Cocos2d-x使用的一个开源几何计算库Kazmath。它是OpenGL ES 1.0变换函数的代替,可以为程序编写提供便利。形象地讲,transform方法的任务就是根据当前节点的属性计算出如何把绘图坐标系变换为新坐标系的矩阵。
坐标系变换除了在绘图时有很重要的作用,它还为我们提供了一个有利的坐标转换工具。
“节点坐标系”指的是以一个节点作为参考而产生的坐标系,换句话说,它的任何一个子节点的坐标值都是由这个坐标系确定的。
10.3TexturePacker与优化
在游戏开发初期,通常同时显示在屏幕上的精灵并不会很多,此时游戏的性能问题并不明显,游戏可以顺利流畅地运行(通常以60帧每秒作为流畅运行的标准)。
然而随着游戏规模的扩大,屏幕上的精灵数量激增,精灵执行的动作越来越复杂,游戏的帧率也会随之下降。当帧率不足30帧每秒时,延迟现象还不是很明显,但是当帧率更低时,明显的延迟现象会导致极差的游戏体验,此时对游戏进行优化就十分必要了。
10.3.1绘图瓶颈
在Cocos2d-x中,影响游戏性能的瓶颈通常只有以下几个方面。
a.纹理过小:OpenGL在显存中的纹理长宽像素一定是2的幂,对于大小不足的纹理,则在其余部分填充空白。
b.纹理切换次数过多:当我们连续使用两个不同的纹理绘图时,GPU不得不进行一次纹理切换,这是开销很大的操作,然而当我们不断地使用同一个纹理进行绘图时,GPU工作在同一个状态,额外开销就小了很多,因此,如果我们需要批量绘制一些内容相近的精灵,就可以考虑利用这个特点来减少纹理切换的次数。
c.纹理过大:显存是有限的,如果在游戏中不加节制地使用很大的纹理,则必然会导致显存紧张,因此要尽可能减少纹理的尺寸以及色深。
针对以上绘图瓶颈,我们接下来介绍几种优化方式以显著提高游戏性能。
10.3.2碎图压缩与精灵框帧
到目前为止,我们都是使用各自的纹理来创建精灵,由此导致的纹理过小和纹理切换次数过多是产生瓶颈的根源。针对这个问题,一个简单的解决方案是碎图合并与精灵框帧。碎图合并可以将许多零碎的小图片合并到一张大图里,并且这张大图的大小恰好符合OpenGL纹理规范,从空间上减少无谓的浪费。框帧是纹理中的一部分,当我们把小纹理合并好之后就可以利用精灵框帧来创建精灵了。
这里我们介绍一款强大的碎图合并工具TexturePacker,这是一个收费工具,但是它提供的免费版已经足以应付日常开发的大部分需求了。
Cocos2d-x和TexturePacker的对接是非常平滑的,只要一句代码即可完成:
CCSpriteFrameCache().sharedSpriteFrameCache()->addSpriteFrameWithFile("all.plist");
我们把碎图信息放在了精灵框帧的缓存内,而不是纹理缓存内。
10.3.3批量渲染
有了足够大的纹理图后,就可以考虑从渲染次数上进一步优化了。如果不需要切换绑定纹理,那么几个OpenGL的渲染请求时可以批量提交的,也就是说,在同一纹理下的绘制都可以一次提交完成。在Cocos2d-x中,我们提供了CCSpriteBatchNode来实现这一优化。
CCSpriteBatchNode可以一次批量提交所有子节点的绘图请求,以减少提交次数,提高绘图性能。这个优化要求每个子节点都使用同一张纹理。
10.3.4色彩深度优化
控制游戏包的尺寸:纹理尺寸优化,降低色彩深度。
默认情况下,我们导出的纹理图片是RGBA8888格式的,因此一个像素总共需要使用4个字节表示。若降低纹理的品质,则可以采用RGBA4444格式来保存图片,因此一个像素总共占用2字节。对于不透明的图片,我们可以选择无Alpha通道的颜色格式,例如RGB565。
565模式 (rrrrrggggggbbbbb)G值有6位,一个像素有2字节
555模式(0rrrrrgggggbbbbb)G值有5位,一个像素有2字节

15.2缓存机制:预加载与重复使用
15.3Cocos2d-x中的缓存
幸运的是,我们不需要自己实现缓存,因为Cocos2d-x已经为我们提供了足够强大的实现。
引擎中存在3个缓存类,都是全局单例模式。
15.3.1CCTextureCache
首先是最底层也最有效的纹理缓存CCTextureCache,这里缓存的是加载到内存中的纹理资源,也就是图片资源。
15.3.2CCSpriteFrameCache
第二个是精灵帧缓存。
15.3.3CCAnimationCache
最后一个是CCAnimationCache动画的缓存。


郑阿奇版
chap5纹理映射
纹理映射是一种将2D图像映射到3D物体上的技术。3D物体的每个顶点都包含了一对纹理坐标,它指定了该顶点所对应到2D图像上特定点的颜色值。D3D根据这些纹理坐标进行插值运算,将纹理贴图映射到3D物体的每个三角形单元中。
5.1纹理映射基础
纹理实际上是一张二维图像,用来表示物体的表面细节,如物体的颜色和图案等。
在D3D中,为了使渲染的图形更具真实感,可以使用纹理映射技术将二维图像映射到三维物体表面。
纹理映射实际上就是对指定区域的像素颜色进行计算的一个过程。
5.1.1纹理坐标
纹理映射所使用的2D图像被称作纹理贴图。D3D支持多种文件格式的纹理贴图文件,如BMP,JPG,PNG,TGA等。
5.1.2创建纹理
5.1.3启用纹理
5.2纹理过滤
D3D在将一个图元绘制到二维屏幕上时,如果该图元具有对应的纹理,那么D3D就必须用纹理产生屏幕上每个像素的颜色,而这一过程称为纹理过滤。
在执行纹理过滤操作时,由于屏幕显示的图形大小总是和实际提供的纹理贴图大小不一致,而此时纹理贴图的纹理元素会被方法或缩小,从而导致颜色丢失。当纹理元素被放大时,多个像素会映射到一个纹理元素上,得到的图像可能会劝马赛克现象。而当纹理元素被缩小时,一个像素将映射到多个纹理元素上,得到的图像可能会模糊不清或有锯齿。
为了解决纹理元素被放大或缩小所造成的图像失真问题,D3D提供了四种纹理过滤方式:最近点采样纹理过滤,线性纹理过滤,各向异性纹理过滤盒多级渐进纹理过滤。

chap7深度、融合及模板
在复杂的场景中,通常有多个物体需要绘制,这些物体之间通常会存在遮挡关系,离观察点较远的物体会因为近处物体的遮挡而不可见或只有部分可见。在这种情况下,为了正确地绘制场景需要使用深度测试。
半透明物体的绘制不同于不透明物体,Direct3D通过Alpha混合实现半透明物体的绘制。深度测试可以简化复杂场景的绘制,而Alpha混合可以使绘制的三维场景更完整,更逼真。
7.1深度测试
深度测试是指D3D通过比较当前绘制的像素点的深度和对应深度缓冲区的点的深度值决定是否绘制当前像素。如果深度测试结构为TRUE,则绘制当前像素,并用当前像素点的深度更新深度缓冲区;反之则不予绘制。
7.2融合技术
在经过深度测试而绘制的场景中,处于前面的物体部分总是遮挡后面的物体。但是,若需要绘制类似玻璃,水及具有透明效果的物体时,这种方法显然不能够满足需求。为了得到具有类似于透明的效果,可以将当前计算得到的像素(即源像素)的颜色值与先前计算得到的像素(目标像素)的颜色值进行合成,这种方式称作融合。
D3D在将集合像素的颜色值进行融合时,它是将当前进行光栅化的像素与已经写入后台缓存的像素进行融合。因此,如果需要在D3D程序中使用融合技术,那么首先应该绘制那些不需要进行融合的物体,然后将需要进行融合的物体按照自后向前的顺序逐个进行绘制。
7.2.1融合因子
D3D通过Alpha通道实现多个像素颜色值的融合。像素的Alpha分量用于指定像素的透明度,其取值范围在0~255之间,0表示像素完全透明,而255表示像素完全不透明。玻璃会拥有很高的透明度,而一块木头可能就没什么透明度可言。
D3D通过定义一个表示物体半透明度的Alpha值和一个融合计算公式,可将源像素的颜色值与目标像素的颜色值相混合,因此该过程也称作是Alpha融合。
OP表示源和目标的融合计算方式,由D3DBLENDOP枚举指定,其默认值为+。
ARGB=K_srcARGB_src+K_dstARGB_dst
[四维向量]K_src和K_dst分别表示源融合因子和目标融合因子,其[分量]取值范围在区间[0,1]内。[KARGB仍然是一个四维向量。]
7.2.2Alpha来源
像素的Alpha值可以来自顶点颜色,材质,纹理中的Alpha值。如果没有使用材质和纹理,那么当前像素的Alpha分量来自每个顶点颜色的Alpha值。如果使用了光照和材质,那么像素的Alpha值来自物体表面的材质。如果使用了纹理贴图,那么Alpha值则来自纹理贴图的Alpha通道。
1.顶点Alpha分量
2.材质Alpha分量
3.纹理Alpha分量
7.2.3启用Alpha融合
在默认情况下,D3D是禁用Alpha融合运算的。
7.5本章小结
深度测试是D3D根据存储在深度缓存中的深度值,从而判断位于同一像素的显示优先权。
深度缓存只保存像素的深度信息,以用于计算每个像素的深度值从而进行深度测试。深度缓存的格式决定了深度测试的精度,通常使用24位表示每个像素的深度值。
Alpha融合用于将源像素与目标像素的颜色值进行融合。其中源像素是当前需要光栅化的像素,而目标像素是已经写入后台缓存中同一位置的像素。可以通过指定不同的融合因子控制源像素与目标像素的融合方式,前提是已经指定Alpha分量来自于材质的漫反射或者所创建的纹理的Alpha通道。
chap12文字,拾取及碰撞检测
12.1字体及文本绘制
ID3DXFont接口用于在D3D应用程序中创建字体及实现二维文本的绘制,该接口封装了Windows字体和D3D设备指针,并且其内部实际上使用GDI实现文本的绘制。


第14章网络
14.1 网络传输架构
直接使用socket传输;使用HTTP传输
14.2 CURL
CURL 是Cocos2d-x推荐使用的网络传输库,随引擎代码一起分发了CURL的一份CPP实现。它是免费开源的,而且支持FTP、HTTP、LDAP等多种传输方式,同时横跨了Windows、UNIX、Linux平台,可以在各种主流的移动设备上良好工作。
14.8小结
在游戏开发中,通常利用socket产生的长连接来维持游戏的同步,然而现在也有许多游戏采用HTTP。
CURL是一套URL通信库,提供了HTTP、FTP等协议的支持,因此可以利用CURL方便地建立HTTP连接。
直接在主线程中执行网络传输任务称作阻塞式传输,而在新线程中一部地进行网络传输任务则称为非阻塞式传输。
网络游戏需要保持用户终端数据与服务器的数据一致,这个过程称为同步。
 
A.3编译create-android-project脚本
在Cocos2d-x项目的根目录下,可以找到“create-android-project”脚本。在Windows下,对应的是“create-android-project.bat”,而在其他系统下对应的是“create-android-project.sh”,这个脚本用于生成游戏的Android工程。
使用任何支持UNIX风格换行的编辑器(例如Ultra Editor 32和Vim)打开脚本文件,并根据不同的系统进行下面所述的修改。
对于Windows用户:在脚本文件中找到以下语句,并设置为相应的路径,其中_CYGBIN变量设置为Cygwin安装目录下的“bin”文件夹路径,_ANDROIDTOOLS设置为Android SDK安装路径下的“tools”文件夹路径,_NDKROOT设置为NDK解压路径。
set _CYBIN=e:\cygwin\bin
set _ANDROIDTOOLS=e:\android\android-sdk\tools
set _NDKROOT=e:\android\android-ndk-r8d
对于非Windows用户:在脚本文件中找到以下语句,并设置为相应的路径,其中NDK_ROOT_LOCAL设置为NDK的解压路径,ANDROID_SDK_ROOT_LOCAL设置为Android SDK的安装路径。
完成设置后,在Cygwin或终端中运行“create-android-project”脚本,若提示如下,则修改成功:
Input package path.For example:org.cocos2dx.example
A.4执行create-android-project脚本
此时输入要创建的程序包名(程序包的命名应遵守Android程序包命名规范)。输入后,脚本程序会列出计算机中安装的所有Android SDK版本,此时选择我们所需要的版本。
完成这一步后,脚本程序会提示“input your project name”,此时输入我们希望创建的文件夹名称。在此处填入“FishingJoy2”,然后稍等片刻,则脚本会在根目录下创建“FishingJoy2”目录,并在此目录中生成Android项目文件。
通常,我们把源代码复制到“Classes”目录下,而把资源文件放入“Resources”目录下。  
A.5修改“Android.mk”文件
“Android.mk”文件位于项目的“proj.android\jni”目录中,它记录了项目所包含的源码文件信息。
其中需要修改的部分列举如下。
LOCAL_MODULE:项目生成的名称,可以随意指定。
LOCAL_MODULE_FILENAME:项目生成的文件名。
LOCAL_SRC_FILES:这里需要加入所有需要编译的源代码文件。
LOCAL_C_INCLUDES:这里添加头文件所在的目录。
LOCAL_WHOLE_STATIC_LIBRARIES:这里添加项目所需的库文件。
A.6执行“build_native.sh”
现在我们执行“build_native.sh”脚本以编译我们的游戏。
A.7导入Eclipse
接下来需要做的是为游戏创建一个Eclipse工程,并生成Android程序包。                   
20160603添加:
D:\cocos2d-x-2.2.5\tools\project-creator> python
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> exit();
D:\cocos2d-x-2.2.5\tools\project-creator>python create_project.py -project HelloWorld -package org.cocos2dx.application -language cpp
proj.ios                : Done!
proj.android            : Done!
proj.win32              : Done!
proj.winrt              : Done!
proj.wp8                : Done!
proj.mac                : Done!
proj.blackberry         : Done!
proj.linux              : Done!
proj.marmalade          : Done!
proj.tizen              : Done!
proj.wp8-xaml           : Done!
New project has been created in this path: D:\cocos2d-x-2.2.5\tools\project-crea
tor/../../projects/HelloWorld
Have Fun!

2.2.5打包APK时,官方推荐方式:
http://www.cnblogs.com/chenyt/p/3786368.html
系统环境变量Path:;H:\cygwin64\bin
Administrator@hxh ~
$ cd $NDK_ROOT
Administrator@hxh /cygdrive/d/Hanxiaohua/android-ndk-r9
$ cd $COCOS2DX_ROOT
Administrator@hxh /cygdrive/d/cocos2d-x-2.2.5
$

Administrator@hxh /cygdrive/d/cocos2d-x-2.2.5/projects/HelloWorld/proj.android
$ export NDK_MODULE_PATH=/cygdrive/d/cocos2d-x-2.2.5/projects/HelloWorld:/cygdrive/d/cocos2d-x-2.2.5/projects/HelloWorld/proj.android
$ bash build_native.sh

20160608:
H:\cygwin64\bin改为D:\Hanxiaohua\cygwin64\bin
用UE修改.bash_profile
ANDROID_NDK_ROOT=/cygdrive/D/Hanxiaohua/android-ndk-r9
export ANDROID_NDK_ROOT
NDK_ROOT=/cygdrive/D/Hanxiaohua/android-ndk-r9
export NDK_ROOT
COCOS2DX_ROOT=/cygdrive/d/cocos2d-x-2.2.5
export COCOS2DX_ROOT

紫金岛游戏 http://hd.91zjd.com/
一元诚信购 http://117.18.5.229/
1、Win7下64位JDK 1.6的安装
C:\Users\Administrator>java -version
java version "1.6.0_43"
Java(TM) SE Runtime Environment (build 1.6.0_43-b01)
Java HotSpot(TM) 64-Bit Server VM (build 20.14-b01, mixed mode)
2、Win7下在D盘安装VMware12虚拟机+虚拟机苹果补丁unlocker203+OS X 10.11.3
3、将Win8.1笔记本上的虚拟机OS X 10.8从C盘移动到E盘
4、
http://www.2cto.com/os/201406/307272.html
http://blog.csdn.net/ldl22847/article/details/9406855
http://www.myhack58.com/Article/sort099/sort0100/2015/58873.htm
http://bbs.qcloud.com/thread-2208-1-1.html
20160107:Win7下Cocos2d-x iOS开发环境搭建
0、先前已经搭好虚拟机OS X 10.8.5+Xcode4.6.3环境,原生iOS App也已经能真机调试了。
1、将cocos2d-x根目录2.0-x-2.0.3拷贝到文稿中;
2、启动终端,输入命令:
cd /Users/Hsq/Documents/2.0-x-2.0.3
sudo ./install-templates-xcode.sh
Password:输入密码
然后开始安装Xcode4 cocos2d-x iOS模板
sudo ./install-templates-xcode.sh -f是重装模板命令
安装后,打开Xcode发现找不到cocos2d-x的模板,这是因为黑苹果的管理权限问题。
打开Finder|前往|前往文件夹,输入~/Library/Developer/Xcode/Templates/cocos2d-x
将共享与权限处的权限都改为“读与写”,然后应用到包含的项目,重启Xcode,发现已经能看到cocos2d-x工程模板了。
3、
iOS模拟器-iPhone/iOS 6.1(10B141可跑)
iOS模拟器-iPad/iOS 6.1(10B141可跑)
生成SimpleGame.ipa,越狱iPhone4真机可跑
注意生成.ipa时选择TARGETS|Build Phases,Run Script填写如下内容:
export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate
codesign -fs "iPhone Developer" --entitlements="/Applications/Xcode.app/Contents/Developer/iphoneentitlements/Entitlement1.plist" "${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/$TARGETNAME" 

1.1.3 Cocos2d-Lua的发展
2012年,网龙科技利用tolua++,将Cocos2d-x的C++接口转为了Lua接口(这层C++与Lua之间的胶水代码叫Lua Binding)。
2012年上半年,廖宇雷的公司开始使用Cocos2d-x+Lua来开发游戏。廖宇雷重写了整个Lua Binding代码,解决了内存泄漏和只能使用全局函数做回调 等问题。
廖宇雷继续改进Lua代码并以Quick-Cocos2d-x为代号fork了一个新的开源引擎。
最终Quick-Cocos2d-x被Cocos2d-x并入主线,成为新的引擎版本:Cocos2d-Lua,而廖宇雷也成为这个版本的核心开发者。
chap3 Cocos2d-Lua基础
3.1 Windows下的Cocos2d-Lua开发环境配置
3.1.1安装Cocos2d-Lua
注:编写本教材时最新的版本为Cocos2d-Lua v3.3 Final。
3.1.2安装Sublime与QuickXDev
3.2引擎架构
Cocos2d-x与ThirdPart Library对外暴露C++ API,Lua Binding把C++ API映射为Lua API,而Quick Framework基于Lua API进行二次封装并扩展了接口。 游戏在最上层,可以同时使用Lua API和Quick框架。 
3.2.2引擎文件结构
quick目录下的Quick框架是本书的重点内容。
(1)bin:Quick框架相关的可执行脚本。
(2)cocos:cocos2d-x Lua binding接口。
(3)framework:Quick框架的Lua源码。
(4)lib:Quick框架的C++源码。
(5)player:模拟器的源码。
(6)samples:Quick框架测试案例。
(7)templates:项目创建模板。
(8)welcome:模拟器启动后显示的欢迎界面。
chap7 Cocos2d-Lua高级
7.1网络通信
Cocos2d-Lua提供了以下3个通信模块:
(1)network,http协议的客户端解决方案,包含了网络状态的获取。
(2)SocketTCP,基于LuaSocket封装的tcp协议客户端解决方案。
(3)WebSocket,WebSocket协议客户端解决方案。
chap8打包与发布
8.1Mac下编译Android版本
8.2Mac下编译iOS版本
8.3Windows下编译Android版本


 
Cocos2d-x引擎捕鱼达人多人游戏功能的设计和实现.pdf
http://max.book118.com/html/2016/0113/33145341.shtm
4.6.1智能电视平台移植的介绍
在Android系统中有onKeyDown和onKeyUp两个函数,
这两个函数是响应按键的按下和弹起状态的两个函数,装有Android系统的智能电视中,遥控器不同的按有着不同的键值。
含义|宏|键值
确认键|KEYCODE_ENTER|23或者66
返回键|KEYCODE_BACK|4
上键|KEYCODE_DPAD_UP|19
下键|KEYCODE_DPAD_DOWN|20
左键|KEYCODE_DPAD_LEFT|21
右键|KEYCODE_DPAD_RIGHT|22
我们通过重写这两个函数,在函数中添加自己的逻辑,用来截获遥控器的按键消息,通过JNI使用Java调用C++。
消息响应函数如下:
keyEnterClicked
keyBackClicked
keyUpClicked
keyDownClicked
keyLeftClicked
keyRightClicked

Cocos2d-X面试题答案
——可以作为开发规范
http://wenku.baidu.com/view/c1510150aaea998fcc220efa.html?from=search
1、autorelease和release的区别
release是立即释放引用计数,如果达到0,对象被销毁。
autorelease是延迟释放,是为了更好管理内存产生的。
CCObject *fun()
{
CCObject *myobj=new CCObject();
//myobj->release();//语句1
//myobj->autorelease();//语句2
return myobj;
}
如果不调用语句1和语句2,会导致内存泄露,根据函数定义原则,谁污染谁治理,如果要求外部调用者释放,不科学。
如果调用语句1,会立即被释放,外部调用者无法获取对象。
调用语句2,延迟被释放,可以保证外部调用者获得对象指针,而又会被释放。
autorelease的实现机制,是将对象加入一个pool统一管理,当pool被release时,pool里面每个对象都会被release。pool基于一个栈式结构管理,每一个mainloop会pop一次。同一个mainloop里面调用autorelease,会把引用加入栈顶pool。





你可能感兴趣的:(Cocos2d-x 2.x读书摘要)