Cocos2d-x 3.x读书摘要(2016-6-25 07:18)


Cocos2d-x 3.x手游开发实例详解
于浩洋 著
2014年9月第1版
前言
以《疯狂的小鸟》为代表的第一批手机游戏
本书以Cocos2d-x 3.0版本为基础。
博客是 http://blog.watchtech.net
chap1 准备
1.3.1 Windows开发环境搭建
系统为Windows7 32位,编译工具为Visual Studio 2012.
笔者下载的是3.0版本。
1.3.2 Mac开发环境搭建
操作系统需为Mac OS X 10.8+,编译工具为Xcode 4.6.2+。
chap8 Cocos2d-x中的事件机制
包括触摸事件EventTouch、鼠标事件EventMouse、键盘事件EventKeyboard、Acceleration(重力感应)事件EventAcceleration和自定义事件

chap10 网络编程
Cocos2d-x提供了3种网络通信方式,分别是使用HTTP协议、Socket协议和WebSocket协议。
10.1 HTTP实现网络通信
HTTP有3种数据提交方式,分别是GET、POST、PUT。
Cocos2d-x封装了3个类来处理HTTP请求,HttpRequest、HttpClient和HttpResponse。它们在命名空间cocos2d-x::network中定义,所以使用时要先声明该命名空间。
using namespace cocos2d::network;
1.HttpRequest
常用方法包括下面几种:
设置请求连接
void setUrl(const char *url);
设置请求类型
void setRequestType(Type type);
Type是Cocos2d-x定义的一个枚举类型,包括5种类型。
设置请求完成后的回调函数
void setResponseCallback(Ref *pTarget,SEL_HttpResponse pSelector);
设置请求的数据,参数buffer是提交的数据,len是请求数据的长度
void setRequestData(const char *buffer,unsigned int len);
为请求设置一个标记
void setTag(const char *tag);
格式为字符串,可以通过HttpResponse->getHttpRequest->getTag()获取该标记。标记是HTTP请求的可选设置,不是必须设置的。
设置请求头信息,比如Content-Type等:
void setHeaders(std::vector<std::string> pHeaders);
上面的设置函数都有一个对应的get函数用来获取设置的信息,比如getUrl用来获取setUrl设置的请求连接。

附录B 3.X主要版本间的区别
使用V3.2进行开发时用到的编译工具要满足以下要求:
Xcode 5.1+
gcc 4.9+
NDK R9D+
VS2012+
使用V3.1开发的游戏的运行平台要求如下:
Android 2.3+
iOS 5.0+
OS X 10.7+
Windows7+
Windows Phone 8+
Linux Ubuntu 12.04+
编译环境要求如下:
Xcode 4.6+
gcc 4.7+
NDK R9+
VS2012+
使用V3.0开发的游戏的运行平台要求如下:
Android 2.3+
iOS 5.0+
OS X 10.7+
Windows7+
暂不支持Windows Phone 8
Linux Ubuntu 12.04+
编译环境要求如下:
Xcode 4.6+
gcc 4.7+
NDK R9+
VS2012+

Cocos2d-x 3.x游戏开发详解
郭志宏 编著
2015年1月第1版
第1章 开发环境搭建
1.1下载Cocos2d-x
本书使用的是3.0、3.1版本。
1.2下载安装Python
Python安装配置成功
C:\Users\DELL->python
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>>
本书使用的是Python 2.7.6(2013.11.10)。
1.4下载安装JDK
本书使用的是jdk_1.7.0_05。
1.8在Windows平台使用Visual Studio创建项目
本书使用的是VS2012。
第2章 编程起步
本书使用的是开发环境是Mac OS+Xcode,所以这里打开proj.ios_mac。
2.1.4场景类的实现
场景类是用户逻辑主要实现的地方,场景类通常由一个或者多个图层组成,图层里面可以有菜单、标签和精灵等游戏对象。
// 条件编译语句,防止头文件的重复包含
#ifndef __LOGIN_SCENE_H__
#define __LOGIN_SCENE_H__
#include "cocos2d.h"//3.x中也是这个头文件
#include "SimpleAudioEngine.h"
#include "cocos-ext.h"
class CLogin : public cocos2d::CCLayer, cocos2d::extension::CCEditBoxDelegate
{
public:
 /*
 init方法是一个初始化方法,该方法沿用了OC中的实现方式,OC中没有构造方法,类的初始化是通过init方法来实现的。
 init在这里充当构造方法的作用,CREATE_FUNC宏定义会调用init。
 */
    virtual bool init(); 
 // 创建场景类,是一个静态方法,用来创建场景,添加图层到其内部,并返回该场景
    static cocos2d::CCScene* scene();
 virtual void editBoxReturn(cocos2d::extension::CCEditBox* editBox);
   
    void RegisterCallback(CCObject* pSender, cocos2d::extension::CCControlEvent controlEvent);
 void LogoinCallback(CCObject* pSender, cocos2d::extension::CCControlEvent controlEvent);
 // a selector callback
 // 2.x中菜单回调方法
 virtual void menuCloseCallback(cocos2d::CCObject* pSender);
 // 3.x中菜单回调方法
 //是一个菜单事件回调方法,在OC中被称为Selector选择器,其实就是一个函数指针。
 virtual void menuCloseCallback(cocos2d::Ref* pSender);
 // 一个宏,实现静态的create方法。3.x中也有这个宏。
 CREATE_FUNC(CLogin);
 CCNode * m_pDefaultEdit;
 CCNode * m_pActionEdit;
 cocos2d::extension::CCEditBox         * m_peditAccount;
 cocos2d::extension::CCEditBox         * m_peditPW;
};
#endif  // __LOGIN_SCENE_H__
// 创建场景
CCScene* CLogin::scene()
{
#if 1
//3.x
  // 创建场景
     auto scene = CCScene::create();
  // 创建图层
  auto layer = CLogin::create();
  // 将图层添加到场景
     scene->addChild(layer);
#else
//2.x
    CCScene * scene = NULL;
    do
    {
        // 'scene' is an autorelease object
        scene = CCScene::create();
        CC_BREAK_IF(! scene);
        // 'layer' is an autorelease object
        CLogin *layer = CLogin::create();
        CC_BREAK_IF(! layer);
        // add layer as a child to scene
        scene->addChild(layer);
    } while (0);
#endif
    // return the scene
    return scene;
}
// on "init" you need to initialize your instance
// 初始化方法
bool CLogin::init()
{
    bool bRet = false;
    do
    {
        //////////////////////////////////////////////////////////////////////////
        // super init first
        //////////////////////////////////////////////////////////////////////////
  //2.x
        CC_BREAK_IF(! CCLayer::init());
  //3.x中初始化父类
  if(!Layer::init())
  {
   return false;
  }
  //2.x
        CCSize size = CCDirector::sharedDirector()->getVisibleSize();
  //3.x中获得屏幕大小
  Size size = Director::getInstance()->getVisibleSize();
  //2.x
        CCSprite* pSprite = CCSprite::create("login/bg.jpg");
        CC_BREAK_IF(! pSprite);
        pSprite->setPosition(ccp(size.width/2, size.height/2));
        this->addChild(pSprite, 0);
  //3.x中添加一个精灵
  Sprite* pSprite = Sprite::create("login/bg.jpg");
  //3.x中设置精灵位置
  pSprite->setPosition(Vec2(size.width/2, size.height/2));
  //3.x中将精灵添加到图层
  this->addChild(pSprite, 0);
  int nX = size.width*3/4;
  int nY = size.height*6/10;
  //TextFieldTTFDefaultTest * pDefaultInput = EditBox::create(CCRect(nX, size.height*5/10, 200, 40));
  //TextFieldTTFActionTest * pActionInput = EditBox::createAnimation(CCRect(nX, nY, 200, 40));
  //this->addChild( pDefaultInput, 1, k_Default_Tag );
  //this->addChild( pActionInput, 1, k_Action_Tag );
  m_peditAccount = EditBox::create(this, CCRect(nX, nY, 200, 40), "login/white_edit.png", "Name:", 8);
  addChild( m_peditAccount );
  m_peditPW = EditBox::create(this, CCRect(nX, size.height*5/10, 200, 40), "login/white_edit.png", "PW:", 8, "微软雅黑", 20, kEditBoxInputFlagPassword, kEditBoxInputModeSingleLine);
  addChild( m_peditPW );
  
  //2.x
  CCLabelTTF *titleButton = CCLabelTTF::create("Login", "微软雅黑", 20);
  titleButton->setColor(ccc3(159, 168, 176));
  addChild( Button::create(this, CCPoint(nX-65, nY - 120), cccontrol_selector(CLogin::LogoinCallback), titleButton, "login/button1.png", "login/button2.png", NULL, NULL) );
  CCLabelTTF *titleRegister = CCLabelTTF::create("Register", "微软雅黑", 20);
  titleRegister->setColor(ccc3(159, 168, 176));
  addChild( Button::create(this, CCPoint(nX+65, nY - 120), cccontrol_selector(CLogin::RegisterCallback), titleRegister, "login/button1.png", "login/button2.png", NULL, NULL) );
  //3.x中创建一个标签
  auto titleButton = LabelTTF::create("Login", "微软雅黑", 20);

        bRet = true;
    } while (0);
    return bRet;
}

// 菜单回调函数
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
 // "close" menu item clicked
        //2.x
 CCDirector::sharedDirector()->end();
        //3.x中结束游戏
        Director::getInstance()->end();
}
 
2.2.1导演类Director
2.窗口尺寸相关方法
返回以点为单位的OpenGL窗口大小
//2.x
CCSize s = CCDirector::sharedDirector()->getWinSize();
//3.x
Size s = Director::getInstance()->getWinSize();
返回可视窗口大小
//2.x
CCSize sVisible = CCDirector::sharedDirector()->getVisibleSize();
//3.x
Size sVisible = Director::getInstance()->getVisibleSize();
返回窗口的起始点
//2.x
float fMinX = CCDirector::sharedDirector()->getVisibleOrigin().x+pShip->getContentSize().width/2;
//3.x
float fMinX = Director::getInstance()->getVisibleOrigin().x+pShip->getContentSize().width/2;
UI坐标转换为OpenGL坐标
//2.x
whirlGun(CCDirector::sharedDirector()->convertToGL(pTouch->getLocationInView()));
//3.x
whirlGun(Director::getInstance()->convertToGL(pTouch->getLocationInView()));
3.场景管理相关方法
运行某个场景
// 2.x和3.x
pDirector->runWithScene(pScene);
停止动画
//2.x
CCDirector::sharedDirector()->stopAnimation();
//3.x
Director::getInstance()->stopAnimation();
开始动画
//2.x
CCDirector::sharedDirector()->startAnimation();
//3.x
Director::getInstance()->startAnimation();
2.2.2节点类Node
设置位置
//2.x
bg->setPosition(ccp(s.width/2, s.height/2));
//3.x
bg->setPosition(Vec2(s.width/2, s.height/2));
添加子节点
//2.x
pNode->addChild(pPlayer);
添加子节点,并指定z坐标和tag标签
//2.x
addChild( pShip, Z_SHIP,  t_Ship);
根据标签获得节点
//2.x
CCSprite * pShip = (CCSprite *)getChildByTag( t_Ship );
开启定时器,指定间隔interval
//2.x
schedule(schedule_selector(Player::OnRowingAnimation), 1.0f);

20160708添加:
第5章 菜单
在Cocos2d-x中通过Menu和MenuItem及其子类MenuItemLabel(标签菜单项)、MenuItemFont(字体菜单项)、MenuItemAtlasFont(图集字体菜单项)、MenuItemSprite(精灵菜单项)、MenuItemImage(图片菜单项)和MenuItemToggle(开关菜单项)来实现菜单。
菜单类Menu继承自Layer图层类,可以响应事件处理。MenuItem菜单项类继承自Node节点类,具有节点类的所有特性。Menu菜单类是MenuItem菜单项类的容器类,多个菜单项被放置在菜单类Menu中显示。
5.2 Menu菜单类
create静态函数:
指定若干个菜单项来创建菜单,注意最后以NULL结尾。
5.4精灵菜单项(MenuItemSprite)
可以通过精灵来创建一个菜单项,使用精灵创建菜单可以指定三个状态:默认状态、选中状态和实效状态,另外,还可以让精灵执行一些动作,使得游戏画面更加生动。
create静态函数:
第一个参数是默认精灵,第二个是选中精灵,第四个参数是回调函数。
5.5 图片菜单项(MenuItemImage)
继承自MenuItemSprite。可以使用图片直接创建菜单项。
create静态函数:
第一个参数是默认图片,第二个参数是选中图片,第四个参数是菜单回调函数。

第6章 精灵及其相关类
本章内容如下:
精灵类Sprite[2.x中是CCSprite]
精灵帧类SpriteFrame[2.x中是CCSpriteFrame]和精灵帧缓存类SpriteFrameCache[2.x中是CCSpriteFrameCache]
精灵批量节点类SpriteBatchNode[2.x中是CCSpriteBatchNode]
精灵动画类Animation[2.x中是CCAnimation]和精灵动画缓存类AnimationCache[2.x中是CCAnimationCache]
6.1精灵类Sprite
指定图片路径创建一个精灵
//2.x
CCSprite * pShip = CCSprite::create("play/ship.png");
使用精灵帧创建一个精灵
//2.x
CCSprite * pGun = CCSprite::createWithSpriteFrame( pGunFrameCache->spriteFrameByName("gun_1_00000.png") );
6.2精灵帧类SpriteFrame和精灵帧缓存类SpriteFrameCache
通过plist配置文件添加所有精灵帧到缓存
//2.x
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("play/bulletNet.plist");
//3.x
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("play/bulletNet.plist");
根据精灵帧名称获得精灵帧
//2.x
CCSpriteFrame *pFrame=CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(pszName);
//3.x
SpriteFrame *pFrame=SpriteFrameCache::getInstance()->getSpriteFrameByName(pszName);
第7章 事件处理
Cocos2d-x 3.0采用了全新的事件处理方式,由原来的代理模式,改为了现在的事件监听器模式。每一个事件都由三部分组成,事件源(也就
是发出事件的游戏对象)、事件本身(如触屏事件)和事件监听器Listener,事件源和监听器要绑定起来才能起作用。
7.1单点触屏事件
//2.x单点触屏事件的回调函数
virtual bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);
//3.x单点触屏事件的回调函数
virtual bool onTouchBegan(Touch *pTouch,Event *pEvent);
virtual void onTouchMoved(Touch *pTouch,Event *pEvent);
virtual void onTouchEnded(Touch *pTouch,Event *pEvent);
virtual void onTouchCancelled(Touch *pTouch,Event *pEvent);
7.2多点触屏事件
//2.x多点触屏事件的回调函数
virtual void ccTouchesBegan(CCSet* touches, CCEvent* event);
virtual void ccTouchesMoved(CCSet* touches, CCEvent* event);
//void ccMousesMoved(CCSet *touches, CCEvent *pEvent);
virtual void ccTouchesEnded(cocos2d::CCSet* touches, cocos2d::CCEvent* event);
virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent);
//3.x多点触屏事件的回调函数
virtual void onTouchesBegan(const std::vector<Touch*>& touches,Event* event);
virtual void onTouchesMoved(const std::vector<Touch*>& touches,Event* event);
virtual void onTouchesEnded(const std::vector<Touch*>& touches,Event* event);
virtual void onTouchesCancelled(const std::vector<Touch*>& touches,Event* event);

2.x中的触摸输入:
7.1触摸输入
鼠标可以实现悬停效果,触摸屏不可以;鼠标只有一个焦点,而触摸屏大多数支持多个触摸点;鼠标通常包含两个功能键从而区分左右键,而触摸屏只能实现一种点按操作。
7.1.1使用CCLayer响应触摸事件
/// 玩家
class Player : public CCLayer

public:
 Player(int iPosition, bool bMySelf=false);
 ~Player(void);
// ccTouchesXXX在CCLayer中都声明为虚函数,这4个函数来自于CCStandardTouchDelegate接口
// 传入参数pTouches是一个CCTouch对象(表示一个触摸点)的集合,其中包含当前触摸事件中的所有触摸点。
// 传入参数pEvent是由Cocos2d-iPhone引擎遗留下来的形式参数,在Cocos2d-x当前版本中没有意义。
// 当玩家的触摸动作完成时(例如抬手和手指离开屏幕等),会引起触摸结束事件。
// 而触摸取消的情况较少,仅当触摸过程中程序被调入后台时才会出现。
        // 触摸开始
 void ccTouchesBegan(CCSet* touches, CCEvent* event);
        // 触摸移动
 void ccTouchesMoved(CCSet* touches, CCEvent* event);
 void ccMousesMoved(CCSet *touches, CCEvent *pEvent);
 CC_SYNTHESIZE_READONLY(bool, m_MySelf, MySelf);    /// 设置自己
};
Player::Player(int iPosition, bool bMySelf/*=false*/) : m_PlayerPT( iPosition )
 , m_iGunType( 1 )
 , m_pGunAnimation( NULL )
 , m_MySelf( bMySelf )
{
 
// 一般情况下,我们可以通过TouchEnable属性来开启或关闭接收触摸输入。
// 开启层的触摸输入支持
setTouchEnabled( bMySelf ? true : false );
}
Player::~Player(void)
{
}
void Player::ccTouchesBegan(CCSet* touches, CCEvent* event)
{
 if ( !m_MySelf )
  return;
 CCSetIterator iter = touches->begin();
 for(; iter != touches->end(); iter++)
 {
  CCTouch* pTouch = (CCTouch*)*iter;
  EmitGun(CCDirector::sharedDirector()->convertToGL( pTouch->getLocationInView() ));
 }
}
void Player::ccTouchesMoved(CCSet* touches, CCEvent* event)
{
// 判断触摸点的数目
if(touches->count()==1){
// 取出该触摸点
CCTouch* pTouch = dynamic_cast<CCTouch*>(touches->anyObject());
// 获取游戏画面中的点位置
CCPoint position=pTouch->getLocationInView();
// 把屏幕坐标转换为游戏坐标
position=CCDirector::sharedDirector()->convertToGL(position);
// 在此处理触摸事件
}
else
{
// 如果不止一个触摸点,则在此处理多点触摸事件
}
}
void Player::ccMousesMoved(CCSet *touches, CCEvent *pEvent)
{
 CCSetIterator iter = touches->begin();
 for(; iter != touches->end(); iter++)
 {
  CCTouch* pTouch = (CCTouch*)*iter;
  whirlGun(CCDirector::sharedDirector()->convertToGL( pTouch->getLocationInView() ));
 }
}
7.1.2两种Cocos2d-x触摸事件
标准触摸事件的特点是任何层都会平等地接收全部触摸事件。

带目标的触摸事件
的特点是接收者并不平等,较早处理事件的接收者有权停止事件的分发,使它不再继续传递给其他接收者。
1、标准触摸事件
利用CCLayer可以方便地启用层上的标准触摸事件。
2、带目标的触摸事件
我们可以为任意对象添加标准触摸事件。

第8章 动作
大部分动作都继承自FiniteTimeAction,另外的两个动作是Follow和Speed。FiniteTimeAction的两个子类是ActionInstant和
ActionInterval,瞬时动作是持续时间为0的FiniteTimeAction动作,即FiniteTimeAction中duration属性值为0的动作。
Action是动作类的基类,动作作用于Node。
8.3瞬时动作
8.3.4 CallFunc
//2.x
CCFiniteTimeAction *pReleaseFishAnimation = CCCallFunc::create(pFish, callfunc_selector(CFish::removeSelf)); // 释放鱼
CCFiniteTimeAction *pBulletNetAnimation = CCCallFuncND::create(pBullet, callfuncND_selector(CBullet::FinishAnimation),
(void *)&ptHit ); // 子弹隐藏,鱼网打开
//3.x
FiniteTimeAction *pReleaseFishAnimation = CallFunc::create(CC_CALLBACK_0(CFish::removeSelf,pFish)); // 回调函数没有任何参数
FiniteTimeAction *pBulletNetAnimation = CallFunc::create(CC_CALLBACK_0(CBullet::FinishAnimation,pBullet,(void *)&ptHit));
// 给回调函数传递一个数据值
8.5复合动作
8.5.1 Spawn
8.5.2 Sequence
//2.x
CCFiniteTimeAction* catchSequence=CCSequence::create(pBulletNetAnimation,pStruggleAnimation,pReleaseFishAnimation,NULL);
//3.x
FiniteTimeAction* catchSequence=Sequence::create(pBulletNetAnimation,pStruggleAnimation,pReleaseFishAnimation,NULL);
第9章 调度器
绘制由Director来管理,而更新及更新的频率由调度器(Scheduler)来管理。
在游戏引擎内部,动作的执行是由调度器来控制的,另外,使用调度器可以实现游戏的逻辑函数回调,在指定的时间频率中调用这些函数。
下面我们再来看一下Scheduler的API。
update
更新调度器,每隔dt时间间隔
schedule
执行调度器,callback是回调函数,target是目标节点,interval是时间间隔,repeat是是否重复执行,delay是延迟执行时间,paused是暂停,key是标示该调度器的一个键。
unschedule
根据key,取消调度器的执行
unschedule
根据选择器,取消调度器的执行
unscheduleUpdate
取消update的更新
unscheduleAllForTarget
取消所有目标调度器的执行
unscheduleAll
取消所有调度器
pauseTarget
暂停目标节点调度器
resumeTarget
恢复目标节点调度器
9.2调度器的三种实现方式
Cocos2d-x提供了多种调度机制,在开发中我们通常会用到三种调度器。
1、默认调度器:schedulerUpdate
2、自定义调度器:schedule
3、单次调度器:scheduleOnce
9.2.1默认调度器
该调度器是使用Node的刷新事件update方法,该方法在每帧绘制之前都会被调用一次。
Cocos2d-x中Node默认是没有启用update事件的,因此需要重载update方法来执行自己的逻辑代码。
通过执行schedulerUpdate调度器,即可每帧执行update方法,如果需要停止这个调度器,则可以使用unschedulerUpdate方法。
9.2.2自定义调度器
由于引擎的调度机制,自定义时间间隔必须大于两帧的间隔,否则两帧内的多次调用会被合并成一次调用。所以自定义时间间隔应在0.1s以上。
同样,取消该调度器可以用unschedule。
我们可以定义多个调度器来完成游戏中不同的逻辑需求。
9.2.3单次调度器
单次调度器只会触发一次,用scheduleOnce来触发,用unschedule来取消该触发器。

第11章 数据结构和常用类
11.2字符串类CCString
CCString就是OC风格的一个字符串处理类,不过在3.0之后被废弃,推荐使用std::string。
CCString是一个可变字符串类。
//2.x字符串格式化
CCString *pBatchName = CCString::createWithFormat("play/bulletNet.png");
11.3数组CCArray
CCArray在3.0之后被废弃,建议使用cocos2d::Vector。
//2.x数组的创建、添加元素
CCArray* pArray = CCArray::create();
CCArray * pArray1=CCArray::createWithCapacity(iSize);
pArray1->addObject(pSpriteFrame);

20160702添加:
2.2.5中HelloWorld.png的尺寸是480*320。
第12章 屏幕适配
Android设备的屏幕分辨率可以任意大小,iOS设备的分辨率也至少有5种以上,因此,屏幕适配是Cocos2d-x中的一个难题。
本章内容如下:
FileUtils工具类
屏幕适配的相关接口
屏幕适配解决方案
12.3.2适配策略
在没有提出设计分辨率的概念之前,我们的程序有两种分辨率,分别是:资源分辨率和设备分辨率,如果增加了设计分辨率后,就有三种分辨率。

资源分辨率:RW=720,RH=1280
设计分辨率:DW=720,DH=1280
大厅场景竖屏:720*1280
游戏场景横屏:1280*720
Android测试机设备分辨率:SW=?,SH=?:
小米2S,Android 4.1.1,设备分辨率1280*720
红米2,Android 5.1.1,设备分辨率1280*720
华为G9 Younth,Android 6.0,设备分辨率1920*1080

Cocos2d-x游戏编程——C++篇
徐飞 著
2015年9月第1版
20160709添加:
1.3 Cocos2d-x中的C++ 11知识
自从C++标准委员会发布C++ 11标准后,引进了一些新的知识点,如auto指针、Lambda表达式、bind和function函数等,Cocos2d-x引擎把这些知识点也加入了引擎的编写过程中。
1.3.1 Lambda表达式
在C++中,有许多算法用来比对输入序列,如find_if、sort、for_each等,这些算法第三个断言(predicate)既可以是<或==操作符,也可以是一个能调用的对象(函数、函数指针等)。这些断言普遍的一个特点是,要么带一个参数,要么带两个参数。
find_if算法中的断言是带一个参数的,而sort算法中的断言是带两个参数的。
有时,我们想传递多于断言参数个数。
为了解决这个问题,C++中引入了Lambda表达式,它是一个可调用对象,可以认为它是一个未命名的内联函数,有返回值、参数列表和函数体等。
Lambda表达式原型:捕获列表、参数列表、返回类型、函数体
Lambda表达式中除了捕获列表外,其他的三个部分和普通函数类似。其中,参数列表和返回类型可以忽略,其他两个必须存在。
如果函数体中只有一个带return的语句,那么表达式可以推断出返回类型,否则将返回void类型。
 1、捕获列表
捕获列表捕获的是调用该表达式函数内的局部非静态变量,对于那些函数内的静态变量和定义在函数外的变量,Lamda表达式也可以直接使用。
捕获列表的类型如表所示。
类型|说明
[]|空的捕获列表
[a1,a2...]|捕获的参数通过逗号来分割,参数既可以是值捕获,也可以是引用捕获
[&]|隐式的引用捕获
[=]|隐式的值捕获
[&,a1,a2...]|a1,a2是值捕获,&表示其他值是隐式引用捕获,a1、a2等捕获必须在&参数捕获之后
[=,&a1,&a2...]|a1,a2是引用捕获,其他值是隐式值捕获
编译器在解释Lambda表达式时,会解释成一个包含未命名类的未命名对象,该类包含了一个重载函数调用操作符的函数,如果在捕获列表中包含有值捕获参数时,那么在该类中会有一个相对应的成员参数。
2、返回值
如果Lambda表达式的函数体不只是一个return语句,那么这时就应该指定表达式的返回值了,它由一个箭头后面带一个返回类型来制定。
对于Lambda表达式,通常只会使用在一个地方,且执行语句较少,如果有多个地方用到该功能,使用函数来实现会更方便些。另一种情况是,如果捕获列表为空,通常使用函数来实现比较直接。
1.3.2 bind函数
C++提供的库函数bind,用于函数绑定的模版,它可以指定被绑定函数中的部分参数,也可以是全部参数。
auto f=bind(func,arg_list);
其中:func是原函数,arg_list是func函数中的参数,是一个逗号分割的参数列表,其中参数可以用占位符来表示,_1表示func函数的第一个参数,_2表示该函数的第二个参数,以此类推,这些占位符可以交换顺序,它们位于std的placeholders命名空间下,f是一个新的可调用对象。
默认情况下,bind函数在不使用占位符时,参数是直接进行复制的。有时,某些绑定函数想通过引用传递或者有的参数是不能复制时,在这种情况下,C++引进了ref和cref
函数。其中,cref是const引用,使用ref函数解决了ostream &os不能复制的问题。
1.3.3 function函数
C++中的可调用对象,包括函数、函数指针、Lambda表达式、bind函数创建的对象和重载了函数调用操作符的类,这些对象可以存储在function函数模版中。
1、函数
function绑定函数
2、Lambda表达式
function绑定Lambda表达式
3、bind函数
function绑定bind函数
4、重载了()操作符的类
function绑定重载了()的类
1.3.4 auto和nullptr
C++ 11引入了auto关键字。由auto定义的变量,通过对该变量的初始化来推断它的类型。
nullptr是新标准中的一个关键字,表示一个空指针。
1.3.5 override和final
override关键字表明,子类的函数一定重写了父类函数。而final关键字表明,该函数不能被继承,已经是最终版本了,如果子类有重写该函数,则编译器就会报错。





你可能感兴趣的:(Cocos2d-x 3.x读书摘要(2016-6-25 07:18))