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

来源:互联网 发布:重庆seo博客cxkj188 编辑:程序博客网 时间:2024/05/29 13:50
20170326添加:
尽量使用最新的类,因为被遗弃的类一般都有功能和性能上的缺陷,所以不建议使用。
对于EditBox类,在2.2.6版本之前,在iOS 8上,如果单击输入,键盘弹出时,会发生界面偏移错误,出现黑色背景部分。关闭键盘时,界面偏移不回来了。
引擎3.5/2.2.6解决了这个Bug。
2.2.6版本中修复了iPhone6和iPhone6 Plus的一些BUG,支持苹果的64位架构。
对于游戏中用到文字的部分,尽量使用Label类和ui命名空间下Text类型的类来实现,LabelTTF等2.x中的类都被遗弃了。


TableView控件即表格控件
// 创建一个TableView对象,并返回其指针
m_table = TableView::create(this, cocos2d::Size(SCREEN_WIDTH, 604));
// 设置表格委托,pDelegate参数表示指向委托对象的指针 
m_table->setDelegate(this);
// 设置滚动方向
m_table->setDirection(TableView::Direction::VERTICAL);
// 设置网格垂直填充顺序,TOP_DOWN代表从上到下排列,BOTTOM_UP代表从下到上排列
m_table->setVerticalFillOrder(TableView::VerticalFillOrder::TOP_DOWN);
this->addChild(m_table, 0);
// 加载数据刷新表格绘制
m_table->reloadData();

表格控件涉及3个非常重要的辅助类:
TableViewCell类为表格行对象类
TableViewDataSource类为表格数据源类
TableViewDelegate类为表格的委托类
//用来响应表格触摸事件的方法,table参数为指向表格对象的指针,cell参数为指向行对象的指针
void LotteryKindScrollView::tableCellTouched(TableView* table, TableViewCell* cell)
{
 // getIdx得到此TableViewCell对象对应的行索引
        int tag = cell->getIdx();
 //if (tag < 0) return; 
 //
 //pCell = cell;
}
// 返回表格总行数,table参数为指向表格对象的指针
ssize_t LotteryKindScrollView::numberOfCellsInTableView(TableView *table)
{
 int result = m_Count / 4;
 int tempLast = m_Count % 4; //除4有余数,则加1
 if (tempLast != 0) result ++;
 return result;
}
// 返回给定表格的行对象尺寸,table参数为指向表格对象的指针
cocos2d::Size LotteryKindScrollView::cellSizeForTable(TableView *table)
{
 cocos2d::Size size = cocos2d::Size(SCREEN_WIDTH, 201); //高度定死
 return size;
}
// 返回表格每一行内容,table参数为指向表格对象的指针,idx参数为行对象的索引值
TableViewCell* LotteryKindScrollView::tableCellAtIndex(TableView *table, ssize_t idx)
{
 TableViewCell* cell = new TableViewCell();
 if(m_Data.size() < 1) return cell;
 for(int i = 0 ; i < 4 ; i ++)
 {  
  int data_index = idx * 4 + i + 1;
  if (data_index > m_Count) break;
  int kindId = m_Data.at(data_index - 1); 
  string nameStr = String::createWithFormat("%s%02d.png",m_name.c_str(),data_index)->getCString();
  if(data_index > 18)
  {   
   nameStr = String::createWithFormat("%s%02d_2.png",m_name.c_str(),data_index)->getCString();
  } 
  if (m_Count < 9) //游戏为4个,这里用9作参考
  {
   nameStr = String::createWithFormat("%s%02d_2.png",m_name.c_str(),data_index)->getCString();
   if(data_index == 1)
   nameStr = String::createWithFormat("%s%02d.png",m_name.c_str(),data_index)->getCString();
   if(data_index == 2)
   nameStr = String::createWithFormat("%s%02d.png",m_name.c_str(),data_index)->getCString();
   if(data_index == 4)
   nameStr = String::createWithFormat("%s%02d.png",m_name.c_str(),data_index)->getCString();
   if(data_index == 3)
    nameStr = String::createWithFormat("%s%02d.png",m_name.c_str(),data_index)->getCString();
   if(data_index == 5)
    nameStr = String::createWithFormat("%s%02d.png",m_name.c_str(),data_index)->getCString();
  } 
  Sprite *kindSprite = Sprite::createWithSpriteFrame(spriteFrame(nameStr));
  kindSprite->setPosition(Vec2(SCREEN_WIDTH * (i * 2 + 1) / 8, 100));
  kindSprite->setTag(LOTTERY_KIND_SPRITE_TAG+kindId);
  cell->addChild(kindSprite);  
 }
 return cell;
}

//辅助类——编辑文本框的委托类EditBoxDelegate
class KongJianLayer : public Layer,public EditBoxDelegate
{
//开始编辑回调方法
virtual void editBoxEditingDidBegin(EditBox* editBox);
//结束编辑回调方法
virtual void editBoxEditingDidEnd(EditBox* editBox);
//内容变化回调方法
virtual void editBoxTextChanged(EditBox* editBox,const std::string& text);
//编辑返回回调方法
virtual void editBoxReturn(EditBox* editBox);
CREATE_FUNC(KongJianLayer);
EditBox* m_peditAccount;
EditBox* m_peditPW;
};
 static EditBox* create(EditBoxDelegate* pDelegate, CCRect rcEditBox, const char *file, const char *PlaceHolder, int MaxLength,
  const char* pFontName="微软雅黑", int fontSize=20,
  //5种回显模式
  EditBox::InputFlag inputFlag=EditBox::InputFlag::PASSWORD,//密码模式
  EditBox::InputFlag inputFlag=EditBox::InputFlag::SENSITIVE,//敏感数据模式
  EditBox::InputFlag inputFlag=EditBox::InputFlag::INITIAL_CAPS_WORD,//单词首字母大写模式
  EditBox::InputFlag inputFlag=EditBox::InputFlag::INITIAL_CAPS_SENTENCE,//句子首字母大写模式
  EditBox::InputFlag inputFlag=EditBox::InputFlag::INITIAL_CAPS_ALL_CHARACTERS,//所有字母大写模式
  //7种输入模式
  EditBox::InputMode inputMode=EditBox::InputMode::ANY,//任何类型
  EditBox::InputMode inputMode=EditBox::InputMode::EMAIL_ADDRESS,//email地址类型
  EditBox::InputMode inputMode=EditBox::InputMode::NUMERIC,//数字类型
  EditBox::InputMode inputMode=EditBox::InputMode::PHONE_NUMBER,//电话号码类型
  EditBox::InputMode inputMode=EditBox::InputMode::URL,//URL类型
  EditBox::InputMode inputMode=EditBox::InputMode::DECIMAL,//小数类型
  EditBox::InputMode inputMode=EditBox::InputMode::SINGLELINE,//单行输入类型
  EditBox::KeyboardReturnType returnType=EditBox::KeyboardReturnType::Default)
 {
  CCEditBox *pEditBox = CCEditBox::create(rcEditBox.size, CCScale9Sprite::create( file ));
  pEditBox->setPosition(CCPoint(rcEditBox.getMinX(), rcEditBox.getMinY()));
  //setFont设置编辑文本框显示文本所采用的字体样式和字体尺寸,pFontName参数为目标样式字体文件路径,fontSize表示字体尺寸值
  //setFontName设置字体样式;setFontSize设置字体尺寸
  pEditBox->setFont(pFontName, fontSize);
  pEditBox->setPlaceholderFont(pFontName, fontSize);
  //setFontColor设置编辑文本框显示文本颜色
  pEditBox->setFontColor(ccBLACK);
  //setPlaceHolder设置输入为空时编辑文本框的显示内容
  pEditBox->setPlaceHolder(PlaceHolder);
  //setPlaceholderFontColor设置输入为空时编辑文本框显示内容的颜色
  pEditBox->setPlaceholderFontColor(ccWHITE);
  //setMaxLength设置编辑文本框输入文本最大长度,MaxLength参数为输入文本的最大长度
  pEditBox->setMaxLength(MaxLength);
  //setReturnType设置此文本编辑控件的返回类型,returnType参数为要设置的返回类型
  pEditBox->setReturnType(returnType);
  //setInputFlag设置输入回显模式,inputFlag参数为要设置的回显模式
  pEditBox->setInputFlag(inputFlag);
  //setInputMode设置编辑文本框的输入模式,inputMode参数为要设置的输入模式
  pEditBox->setInputMode(inputMode);
  //setDelegate设置编辑文本框的委托,pDelegate表示指向委托对象的指针
  pEditBox->setDelegate(pDelegate);
  return pEditBox;
 }

chap22 GUI框架概述
Cocos2d-x引擎自带的基础UI控件Menu、MenuItem、Label、TextFieldTTF等,以及2.x本意欲一统GUI框架的CCControlXXX系列控件。它们都没能形成系统的UI框架,直到CocosStudio的出现,以CocosStudio为基础的
Widget系列UI控件才逐渐形成了系统的UI框架。
在旧版本引擎当中,不存在动画帧的类AnimationFrame。
精灵帧缓冲类的函数
addSpriteFramesWithFile通过plist文件来添加精灵帧
addSpriteFramesWithFile通过plist文件和纹理图片的名字来添加精灵帧
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pic_show.plist","pic_show.png");
3.3 百分比动作特效
百分比动作的实现类
ProgressTo(从初始百分比为0%开始的动作)和ProgressFromTo这两个类都直接继承了ActionInterval类
duration参数表示动作持续的时间
percent参数表示目标百分比
reverse方法表示获取当前动作的逆动作,并返回其指针
fromPercentage表示初始百分比
toPercentage表示目标百分比
与普通动作不同,百分比动作不应该直接被精灵等可见物体执行,而是需要将希望执行这些动作的精灵包裹进ProgressTimer对象来执行。
//sp参数表示指向其他包裹的精灵对象的指针
Sprite* sp=Sprite::createWithSpriteFrame(spriteFrame((i==2||i==3||i==6||i==7)?texture_name::s_cd_bg_other_h:texture_name::s_cd_bg_other_v));
//创建ProgressTimer对象,返回其指针
m_pCountDown[i]=ProgressTimer::create(sp);
m_pCountDown[i]->setPosition(ccp(myConfig.m_CountDownPos[i][0],myConfig.m_CountDownPos[i][1]));
//设置工作模式,RADIAL代表半径模式,BAR代表水平/垂直模式
m_pCountDown[i]->setType(ProgressTimer::Type::RADIAL);
//设置动作是否逆序执行,true为逆序执行,false为非逆序执行 
m_pCountDown[i]->setReverseDirection(true);
m_pCountDown[i]->setVisible(true);
addChild(m_pCountDown[i],2);
CCLOG("m_pCountDown Pos%d=\"%f,%f\" ",i,m_pCountDown[i]->getPositionX(),m_pCountDown[i]->getPositionY());
if (iViewID == MY_VIEW_CHAIR_ID)
{
m_pCountDown[iViewID]->runAction(CCSequence::create(CCShow::create(),ProgressFromTo::create(45,95,5),CCHide::create(),CCCallFunc::create(this,callfunc_selector(DZPKLayer::selfTimeOut)),NULL));
}
else
{
m_pCountDown[iViewID]->runAction(CCSequence::create(CCShow::create(),ProgressFromTo::create(45,95,5),CCHide::create(),NULL));
}
OpenGL坐标系是指以屏幕左下角为原点的坐标系
屏幕坐标系是指以屏幕左上角为原点的坐标系
//getLocation获取触控点在OpenGL坐标系中的当前坐标
bool LotteryKindScrollView::onTouchBegan(Touch *pTouch, Event *pEvent)
{
    if(pTouch->getLocation().y > 150 + 604 || pTouch->getLocation().y < 150)
       return false; 
    start_pos = pTouch->getLocation();
    return true;
}
//getLocationInView获取触控点在屏幕坐标系中的当前坐标
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() ));
 }
}

Vec2类一些常用的求距离与夹角的方法  
//getDistance获取自身与另一个Vec2对象所代表的二维向量坐标点之间的距离
Vec2 pos = pTouch->getLocation(); 
if(pos.getDistance(start_pos) > 10) return;


Cocos2d-x 3.0之前是使用NotificationCenter来实现事件通知的,Cocos2d-x 3.0之后使用了EventDispatcher来实现。
16.1事件通知
最简单的一种方法是直接通知。
还有另外一种方法是轮询通知。
还有一种称之为消息队列的通知机制。
最后来看看观察者模式。
16.2 NotificationCenter和EventDispatcher
NotificationCenter是3.0之前的消息通知机制,因为功能比较简单,并且效率低下所以没有被广泛使用,最终从3.0开始被废弃了。
16.2.4 使用NotificationCenter
第一步是注册监听,但在这里并不需要创建一个listener。任何继承于Ref的对象都可以是NotificationCenter的listener,只需要将对象的指针和回调传入NotificationCenter即可,回调的原型是void callback(Ref*);
调用NotificationCenter::getInstance()->addObserver可以添加一个观察者,其会自动创建一个NotificationObserver对象并放到NotificationCenter中进行管理。
//NotificationCenter::getInstance()->addObserver(this,callfuncO_selector(HotUpdateLayer::getClientVersion),MSG_UI_ANS_GETCLIENTVERSION,NULL);
//NotificationCenter::getInstance()->addObserver(this,callfuncO_selector(HotUpdateLayer::checkUpdate),MSG_UI_ANS_CHECKUPDATE,NULL);
//NotificationCenter::getInstance()->addObserver(this,callfuncO_selector(HotUpdateLayer::updateDownLoad),MSG_UI_ANS_UPDATEDOWNLOAD,NULL);
第二步是发送消息,调用postNotification方法可以发送指定的消息,这个方法有一个重载函数,接受一个Ref*对象。
NotificationCenter::sharedNotificationCenter()->postNotification(MSG_UI_ANS_GAMELINK,Integer::create(1));
第三步是注销,将添加的对象和监听的消息传入,并移除该观察者。
//NotificationCenter::getInstance()->removeObserver(this,MSG_UI_ANS_GETCLIENTVERSION);
//NotificationCenter::getInstance()->removeObserver(this,MSG_UI_ANS_CHECKUPDATE);
//NotificationCenter::getInstance()->removeObserver(this,MSG_UI_ANS_UPDATEDOWNLOAD);
18.1如何监听触摸消息
18.1.1监听触摸消息
使用触摸监听者处理触屏事件,需要有以下两个步骤:
1、创建监听者并实现监听回调。
2、注册监听者等待事件触发。
Cocos2d-x 3.0之后改继承为组合,结合C++ 11的fuction对象,很好地简化了类之间的继承关系。原来希望监听一个消息时,自身必须成为一个监听者,而现在可以很方便地创建一个监听者,由这个监听者专门监听消息。
18.1.2触摸监听者
EventListenerTouchOneByOne/EventListenerTouchAllAtOnce分别对应Cocos2d-x 3.0之前的CCTargetedTouchDelegate/CCStandardTouchDelegate,前者的命名更为直观。
Target监听者的例子:
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);//点击吞噬的选项,独占这个点击事件,其他的Target监听者不会接收到这个点击事件了
listener->onTouchBegan = CC_CALLBACK_2(LotteryKindScrollView::onTouchBegan, this); 
listener->onTouchEnded = CC_CALLBACK_2(LotteryKindScrollView::onTouchEnded, this);
listener->onTouchMoved = CC_CALLBACK_2(LotteryKindScrollView::onTouchMoved, this);
listener->onTouchCancelled = CC_CALLBACK_2(LotteryKindScrollView::onTouchCancelled, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
在多点触摸时,OneByOne会将触摸点一个一个地回调,回调函数的参数为Touch *, Event *。每次回调只传入一个触摸对象。
bool LotteryKindScrollView::onTouchBegan(Touch *pTouch, Event *pEvent)
{
    if(pTouch->getLocation().y > 150 + 604 || pTouch->getLocation().y < 150) return false; 
    start_pos = pTouch->getLocation();
    return true;
}
void LotteryKindScrollView::onTouchMoved(Touch *pTouch, Event *pEvent)
{
  
}
void LotteryKindScrollView::onTouchEnded(Touch *pTouch, Event *pEvent)
{
  
}
20170322问题:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
解决方法:
schedule_selector声明的回调函数要带一个float参数
20170305添加:
7.1.1按钮类ControlButton
示例:测试按钮——ControlButtonTest 
// 背景
CCScale9Sprite *pBackground;
// 确定
CCControlButton *pSubmit;
// 取消
CCControlButton *pCancel;
// 关闭
CCControlButton *pClose;
// 按钮的标题字
Label *titlebutton;
// 按钮的标题字
Scale9Sprite *pBackground=Scale9Sprite::create("button.png");
// 创建按钮对象
ControlButton *pSubmit=ControlButton::create(titlebutton,pBackground);
// 背景九宫格
 void backgroundWithSpriteFrameName(const char *pszSpriteFrameName);
 void backgroundWithFile(const char *file);
 
 // 按钮九宫格
 // 从帧名加载
 void buttonSubmitWithSpriteFrameName(const char *pszSpriteFrameName);
 void buttonCancelWithSpriteFrameName(const char *pszSpriteFrameName);
 void buttonCloseWithSpriteFrameName(const char *pszSpriteFrameName);
 // 从文件加载
 void buttonSubmitWithFile(const char *file,const char *text=0,const char *fontName="微软雅黑",int fontSize=12);
 void buttonCancelWithFile(const char *file,const char *text=0,const char *fontName="微软雅黑",int fontSize=12);
 void buttonCloseWithFile(const char *file,const char *text=0,const char *fontName="微软雅黑",int fontSize=12);
 // 从文件加载并均分,实现四态按钮
 void buttonSubmitWithFileCell(const char *file,int cell,bool Hor=true);
 void buttonCancelWithFileCell(const char *file,int cell,bool Hor=true);
 void buttonCloseWithFileCell(const char *file,int cell,bool Hor=true);

适配功能函数
// 获得设计分辨率大小
 winSize = CCDirector::sharedDirector()->getWinSize();
void DZPKLayer::dzpk_ToPortrait()
{
#if (CC_TARGET_PLATFORM ==CC_PLATFORM_WIN32)
 GLView* eglView = Director::getInstance()->getOpenGLView(); 
 eglView->setViewName("QiXing");
 eglView->setFrameSize(WINDOW_WIDTH,WINDOW_HEIGHT);
 eglView->setDesignResolutionSize(SCREEN_WIDTH, SCREEN_HEIGHT, kResolutionExactFit);
#endif
 //切换竖屏代码
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
 GLView *pEGLView = Director::getInstance()->getOpenGLView();
        // 获得屏幕分辨率大小
 cocos2d::Size frameSize = pEGLView->getFrameSize();
 JniMethodInfo minfo;
 if( JniHelper::getStaticMethodInfo(minfo,"org.cocos2dx.cpp.AppActivity","changedActivityOrientation","(I)V") )
 {
  minfo.env->CallStaticVoidMethod(minfo.classID,minfo.methodID,2);
 }
 pEGLView->setFrameSize(frameSize.height,frameSize.width);
        // 设置设计分辨率和适配方式
 pEGLView->setDesignResolutionSize(SCREEN_WIDTH, SCREEN_HEIGHT,kResolutionExactFit);
#endif
}
void DZPKLayer::dzpk_ToLandscape()
{
#if (CC_TARGET_PLATFORM ==CC_PLATFORM_WIN32)
 MyConfig::Instance().LoadData("xml/MyConfig.xml");
 GLView* eglView = Director::getInstance()->getOpenGLView();
 eglView->setViewName("dzpk");
 eglView->setFrameSize(SCREEN_HEIGHT*0.8,SCREEN_WIDTH*0.8);
 eglView->setDesignResolutionSize(SCREEN_HEIGHT,SCREEN_WIDTH,kResolutionExactFit);
#endif
 //切换横屏代码
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
 GLView *pEGLView = Director::getInstance()->getOpenGLView();
        // 获得屏幕分辨率大小
 cocos2d::Size frameSize = pEGLView->getFrameSize();
 JniMethodInfo minfo;
 if( JniHelper::getStaticMethodInfo(minfo,"org.cocos2dx.cpp.AppActivity","changedActivityOrientation","(I)V") )
 {
  minfo.env->CallStaticVoidMethod(minfo.classID,minfo.methodID,1);
 }
 pEGLView->setFrameSize(frameSize.height,frameSize.width);
        // 设置设计分辨率和适配方式
 pEGLView->setDesignResolutionSize(SCREEN_HEIGHT,SCREEN_WIDTH,kResolutionExactFit);
#endif
}

chap11数据结构和常用类
deprecated文件夹
CCDeprecated.h对这些废弃类重新做了类型定义
整数类型封装类、整型数的封装
__Integer/Integer/CCInteger
继承自Ref,Clonable
使用create创建对象,使用getValue获取值
例如:
NotificationCenter::sharedNotificationCenter()->postNotification(MSG_UI_ANS_GAMELINK,Integer::create(1));

typedef __Array Array;
typedef __Array CCArray;
__Array多继承自Ref,Clonable
removeObjectAtIndex函数删除元素
getRandomObject函数获得一个随机元素对象
containsObject函数判断是否包含某个对象
void DZPKLayer::updateActionName(Object* obj)
{
 __Array *arr=(__Array *)obj;
 // count函数获得数组中的元素个数
 if(arr->count()>=2)
 {
  // getObjectAtIndex函数根据索引获得某个元素对象
  int iViewID=((Integer *)arr->getObjectAtIndex(0))->getValue();
  const char* szName=((__String *)arr->getObjectAtIndex(1))->getCString();
  m_pPlayerInfoManager->updateActionName(iViewID,szName);
 }
}
string str=String::createWithFormat("胜利:手牌数=%d,公共牌数=%d,牌型=%d",bTempCount1,bTempCount2,ct)->getCString();
MyNSString::GBKToUTF8(str);
// 静态函数create创建一个数组对象  
__Array *arr=__Array::create();
// addObject添加元素 
arr->addObject(Integer::create(wWinnerID));
arr->addObject(String::create(str));
NotificationCenter::getInstance()->postNotification("updateActionName",arr);


字典CCDictionary\__Dictionary\Dictionary是一个键值对容器,键不可以重复,值可以重复
//创建
  CCDictionary *dictionary = CCDictionary::create();
//添加
  dictionary->setObject(CCInteger::create(dwUserID), "dwUserID");
  dictionary->setObject(CCInteger::create(wFaceID), "wFaceID");
  dictionary->setObject(CCInteger::create(cbGender), "cbGender");
  dictionary->setObject(CCInteger::create(cbMemberOrder), "cbMemberOrder");
  dictionary->setObject(CCInteger::create(lScore), "lScore");
  dictionary->setObject(CCInteger::create(lWinCount), "lWinCount");
  dictionary->setObject(CCInteger::create(lLostCount), "lLostCount");
  dictionary->setObject(CCInteger::create(lDrawCount), "lDrawCount");
  dictionary->setObject(CCInteger::create(lFleeCount), "lFleeCount");
  dictionary->setObject(CCInteger::create(lWinCount+lLostCount+lDrawCount+lFleeCount), "lTotalCount");
  dictionary->setObject(CCInteger::create(lExperience), "lExperience");
  dictionary->setObject(CCString::create(szNickName), "szNickName");
 
CCDictionary *dic = (CCDictionary *)friendData->objectAtIndex(i);
//根据键获得值 
DWORD userID = ((CCInteger *)dic->objectForKey("dwUserID"))->getValue();

Cocos2d-x 2.0中常用的isTouchEnabled()、setTouchEnabled(bool value)、isAccelerometerEnabled()及setAccelerometerEnabled(bool value)4个启用或禁用触摸事件和加速度计事件的函数已经不建议使用了,从Cocos2d-x 3.0开始建议使用监听器来监听回调触摸事件和加速度计事件。

3.5.6 SpriteBatchNode精灵表单类
如果能尽量减少OpenGL ES的调用,游戏的运行就会变得非常顺畅。
SpriteBatchNode的前身是旧版本中的SpriteSheet,也就是俗称的精灵表单。
使用SpriteBatchNode类时需要注意两个问题:
SpriteBatchNode类只能接受精灵对象成为其子节点。粒子、标签以及图层都不能成为SpriteBatchNode类的子节点。
所有的精灵对象必须使用同一张纹理图片,并且最好不要对这些精灵对象使用一些混合效果。
3.0版本之后推荐直接使用Sprite,不需要再将Sprite作为子节点添加到SpriteBatchNode中。

示例:测试SpriteFrameCacheTest精灵帧缓存类
SpriteFrameCacheTest
cocos2d-x-3.2/test/cpp-tests/Resources/animations
本例我们选择使用grossini-aliases.plist和grossini-aliases.png
cocos2d-x-3.2/test/cpp-tests/Resources/Images
grossini_dance_01.png到grossini_dance_14.png
如果开发者没有先使用addSpriteFramesWithFile函数添加精灵帧缓存,之后的操作都会提示找不到对应的.png文件。
//3.x
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("dzpk.plist","dzpk.png");
//2.x
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("dzpk.plist");
CCString *pBatchName=CCString::createWithFormat("dzpk.png");
cocos2d::CCSpriteBatchNode * s_dzpk= CCSpriteBatchNode::create(pBatchName->getCString());

3.6.1 cocos2d::Vector<T>
设计者们将cocos2d::Vector<T>设计为cocos2d::CCArray的替代品。存入容器的对象必须是cocos2d::Ref或其派生类。当容器被释放时,它所保存的所有元素都会被释放一次引用。
使用现代的C++,本地存储对象比堆存储对象要好。所以不要使用new操作来申请cocos2d::Vector<T>的堆对象,要使用栈对象。cocos2d::Vector<T>并不是cocos2d::Ref的子类,所以不要像使用其他Cocos2d类一样使用retain/release和引用计数内存管理。Vector<Vector<>>也是非法的。

4.8示例:测试函数回调动作——CallFuncActionTest 
函数回调动作包括如下几种:
CallFunc:不包含参数
CallFuncN:参数表示要调用动作的节点对象
__CCCallFuncND和__CCCallFuncO在3.0当中已经弃用了,使用CallFuncN代替。
由于从Cocos2d-x 3.0开始支持最新的C++ 11语法,因而,CallFuncActionTest的init函数中的回调方法可以使用更加简单的方式实现。
有关C++ 11新特性的知识请参考《C++ Prime中文版(第5版)》或官网文档。

3.0后新的回调接口,由四个CC_CALLBACK取代。
CC_CALLBACK的差别就在于后面的数字,0就代表回调是没有参数的函数,1就是有1个参数,2就是有2个参数,3就是有3个参数。
示例:测试菜单——MenuTest
③精灵菜单项的使用
//3.x
 Sprite *CloseNormal=Sprite::createWithSpriteFrame(spriteFrame("CloseNormal.png"));//正常状态
 Sprite *CloseSelected=Sprite::createWithSpriteFrame(spriteFrame("CloseSelected.png"));//选择状态
 [=]以传值的方式传入所有变量,值不可以被修改
//重置
MenuItemSprite *pCloseItemSprite1 = MenuItemSprite::create(pCloseNormalButton1,pCloseSelectButton1,[=](Ref* ){
 reset(NULL);
});
MenuItemSprite* CloseItem = MenuItemSprite::create(CloseNormal,CloseSelected,CC_CALLBACK_1(DZPKLayer::menuCloseCallback, this));
 CloseItem->setAnchorPoint(ccp(0.5,0.5));
 CloseItem->setTag(ExitTag);
 CloseItem->setPosition(ccp(m_WinSize.width*0.5,m_WinSize.height*0.35));
 Menu* menu = Menu::create(CloseItem,NULL);
 menu->setAnchorPoint(ccp(0,0));
 menu->setPosition(Point::ZERO);
 menu->setZOrder(-1801);
 //menu->setTouchPriority(-1801);
 addChild(menu,100);
void DZPKLayer::menuCloseCallback( Object* obj )
{
 int tag = dynamic_cast<CCNode*>(obj)->getTag();
 switch (tag)
 {
 case ExitTag:
  {
   CCLOG("exit================================");
   DZPKLayer::ExitDZPK();
  }
  break;
 default:
  break;
 }
}
//2.x
CCSprite *sendItemNormalImage = CCSprite::createWithSpriteFrame(spriteFrame("Button_FriendSend1.png"));
CCSprite *sendItemSelectedImage = CCSprite::createWithSpriteFrame(spriteFrame("Button_FriendSend2.png"));
CCSprite *deleteItemNormalImage = CCSprite::createWithSpriteFrame(spriteFrame("Button_FriendDelete1.png"));
CCSprite *deleteItemSelectedImage = CCSprite::createWithSpriteFrame(spriteFrame("Button_FriendDelete2.png"));
CCSprite *chatItemNormalImage = CCSprite::createWithSpriteFrame(spriteFrame("Button_FriendChat1.png"));
CCSprite *chatItemSelectedImage = CCSprite::createWithSpriteFrame(spriteFrame("Button_FriendChat2.png"));
CCMenuItemSprite *sendItem = CCMenuItemSprite::create(sendItemNormalImage,sendItemSelectedImage,this,menu_selector(BankerListLayer::sendButton));
CCMenuItemSprite *deleteItem = CCMenuItemSprite::create(deleteItemNormalImage,deleteItemSelectedImage,this,menu_selector(BankerListLayer::deleteButton));
CCMenuItemSprite *chatItem = CCMenuItemSprite::create(chatItemNormalImage,chatItemSelectedImage,this,menu_selector(BankerListLayer::chatButton));
myFriendOperaMenu = CCMenu::create(sendItem,deleteItem,chatItem,NULL); 
myFriendOperaMenu->setPosition(ccp(555, 42)); 
myFriendOperaMenu->alignItemsHorizontallyWithPadding(4);
this->addChild(myFriendOperaMenu,2);
void BankerListLayer::chatButton(cocos2d::CCObject *obj)
{ 
}

P109
Sprite * Start1 = Sprite::createWithSpriteFrame(spriteFrame(texture_name::s_start_button1));
Sprite * Start2 = Sprite::createWithSpriteFrame(spriteFrame(texture_name::s_start_button2));
MenuItemSprite *StartItem = MenuItemSprite::create(Start1,Start2,CC_CALLBACK_1(DZPKLayer::menuResumeCallback, this));
StartItem->setTag(StartTag);
// 菜单中关闭按钮
auto *LeaveItem = MenuItemImage::create("CloseNormal.png","CloseSelected.png",CC_CALLBACK_1(DZPKLayer::menuCloseCallback, this));
LeaveItem->setTag(CloseTag);
// 菜单
auto m_StartClose= Menu::create(StartItem,LeaveItem,NULL);
m_StartClose->setPosition(ccp(0,0));//Vec2::ZERO 
addChild(m_StartClose,0);
  
// 使用png图片创建一个精灵
auto exit_1 = Sprite::create("CloseNormal.png");

附录 Cocos2d-x中常用的宏
Cocos2d-x中提供了很多宏来完成一些特定的功能,它们在很大程度上方便了开发者。
1、与节点创建相关的宏
2、与平台相关的宏
3、与命名空间相关的宏
4、与节点属性相关的宏
5、与内存管理相关的宏
使用delete操作符删除一个C++对象p,如果p为NULL,则不进行操作
CC_SAFE_DELETE(tabLayer);
6、与日志相关的宏
7、与调试相关的宏
8、与转换相关的宏

命名空间宏
宏|作用|同等作用的C++语句
USING_NS_CC|定义cocos2d命名空间
USING_NS_CC_EXT|定义cocos2d::extension命名空间

2.3.2断言宏CCAssert的使用
cond是断言表达式,msg是错误提示信息。
if (NULL == s_AllBullet)
  CCAssert(0, "请先调用 CBulletManage::Init(...) 函数!");
2.3.3数组遍历宏CCARRAY_FOREACH、CCARRAY_FOREACH_REVERSE
声明在CCArray.h中
__array__为需要遍历的数组,__object__为Object对象
 CCSprite *pChild = NULL;
 CCObject* pObj = NULL;
 CCARRAY_FOREACH(getChildren(), pObj)
 {
  //在程序里要对该Object进行强制类型转换
                pChild = (CCSprite*)pObj;
  pChild->setVisible( true );
 }
2.3.5对象创建方法宏CREATE_FUNC的使用
CREATE_FUNC自动生成一个默认的静态create方法。
CREATE_FUNC(CLogin);
即生成一个方法:static CLogin* create();

4.5使用编辑框制作用户登录界面
Cocos2d-x使用EditBox添加编辑框,EditBox继承自ControlButton。
(1)创建一个编辑框对象m_peditAccount,用来输入姓名
cocos2d::extension::CCEditBox * m_peditAccount;
cocos2d::extension::CCEditBox * m_peditPW;
(10)给输入框添加事件代理,事件代理函数在EditBoxDelegate中定义,所以自己定义的类要继承EditBoxDelegate。其中包括4个处理函数。
class CLogin : public cocos2d::CCLayer, cocos2d::extension::CCEditBoxDelegate
editBoxReturn:当按键盘的完成键时触发
virtual void editBoxReturn(cocos2d::extension::CCEditBox* editBox);

附录A 实例代码清单说明
代码清单|实例说明
2-2|Cocos2d-x基本数据类型的使用方式,比如String、Array、Point、Size、Rect、Dictionary、Bool
2-3|Cocos2d-x常用宏定义的使用方法,比如随机数宏,角度转换宏,两值交换宏,数组遍历宏,字典遍历宏,属性定义宏
2-4|锚点的使用方式,节点坐标和世界坐标的相互转换
3-1-2|从场景中移除Node节点
3-2-2|使用Camera缩放、旋转节点
3-4-2|使用Scene创建一个战斗场景
3-4-3|多个场景相互切换的方式
3-5-2|Layer、layerColor的使用方式
4-1|1、使用LabelBMFont显示文本,获取单个字并设置样式;2、使用LabelTTF显示文本并对文本设置样式;3、使用LabelAtlas在场景中显示自定义字体。
4-2|介绍6种菜单项的区别和使用方式,在游戏中添加菜单并设置单击菜单后的回调函数
4-2-2|使用菜单制作游戏菜单功能
4-3-1|在游戏中使用ScrollView显示多页内容,监听ScrollView的滚动和缩放事件
4-3-3|通过制作一个简单背包讲解如何使用TableView,设置TableView大小、方向、渲染顺序、数据源。自定义单元格TableViewCell
4-3-4|当TableView里添加菜单时,如何区分处理是点击菜单还是滑动TableView
4-5|通过制作一个用户登录界面讲解编辑框的使用方式,包括设置编辑框的显示形式、输入内容,注册4种事件的代理函数
5-2|瞬时动作举例
5-3|延时动作举例,如移动、跳跃、旋转、缩放、倾斜变形、曲线运动等。把简单动作联合起来,实现按顺序播放动作、同时播放动作、逆向播放动作、重复播放动作等
6-2|介绍Cocos2d-x对背景音乐和音效的处理方法,主要内容包括播放、停止、暂停、恢复等操作
8-2|通过三个例子讲解Cocos2d-x中的屏幕触摸事件
8-3|使用多点触摸实现缩放图片
8-4-1|把键盘输入事件显示在屏幕中,讲解了如何使用Cocos2d-x的键盘事件
9-1|使用UserDefault存储修改数据
20170219添加:
http://www.docin.com/p-1489599279.html
Cocos2d-x学习之路(个人总结)
一、精灵篇
1、创建精灵的三种方法
1.1使用指定图片创建一个Sprite:
auto sprite=Sprite::create("2.png");
1.2使用矩形创建一个Sprite:
auto sprite=Sprite::create("2.png",Rect(0,0,40,40));
1.3使用精灵表单(Sprite Sheet)创建一个Sprite:
加载一个精灵表单
auto framecache=SpriteFrameCache::getInstance();
framecache->addSpriteFramesWithFile("sprite.plist");
auto sprite=Sprite::createWithSpriteFrameName("2.png");
this->addChild(sprite);
2、锚点和位置(颜色和透明度不受锚点影响)
2.1锚点
sprite->setAnchorPoint(Vec2(0.5,0.5));
2.2受锚点影响的精灵属性
位置
缩放
倾斜
角度:角度增加,顺时针旋转;角度减少,逆时针旋转
2.3不受锚点影响的精灵属性
颜色:Color3B对象代表RGB颜色值,即0~255之间的值,预定义颜色,如Color3B::White,Color3B:Red
透明度:取值范围(0~255),默认值为255(不透明)
二、动作篇
1、动作概念
随时间改变Node的属性
By和To的区别:
By相对于节点是相对的
To相对于节点是绝对的
2、基本动作及其如何执行动作
移动
旋转
缩放
淡入淡出
色调
跳跃
减速
贝塞尔曲线
3、序列动作及其如何执行动作
Sequence:序列对象可以是:动作对象、函数(CallFunc对象)、甚至另一序列
4、三种回调函数
1、callback()
2、callback(Node* sender)
3、callback(Node* sender,long date)
注意:两个对象同时调用一个动作的时候会失败,此时另外一个对象应该调用动作的clone();使用回调函数的时候,传入回调方法的时候记得没用括号,每个回调函数必须传入一个this参数。
三、计时器篇
1、原理介绍:
为游戏提供定时事件和定时调用服务
所有Node对象都知道如何调度和取消调度事件
2、三种计时器
2.1默认调度器:scheduleUpdate()
取消方法:
unscheduleUpdate()停止调度器
2.2单次调度器:scheduleOnce(SEL_SCHEDULE selector,float delay)
取消方法:
unschedule(SEL_SCHEDULE selector,float delay)
2.3自定义调度器:schedule(SEL_SCHEDULE selector,float interval,unsigned int repeat,float delay)
取消方法:
unschedule(SEL_SCHEDULE selector,float delay)
四、触摸篇
1、传统的单点触摸(针对scene的触屏事件)
1.1单点触摸的声明
1.2单点监听器的创建
1.3具体方法的实现
2、针对node的单点触摸(兰布达表达式)
2.1这种触摸方式并不需声明
2.2单点监听器的创建和方法实现
auto listener=EventListenerTouchOneByOne::create();
listener->onTouchBegan=[=](Touch *touch,Event *event)
{

};
listener->onTouchMoved=[](Touch *touch,Event *event)
{

};
listener->onTouchEnded=[=](Touch *touch,Event *event)
{

};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,hello);//node类型
注意:兰布达表达式[](){}
其中[&]任何被使用的外部变量皆隐式地以参考方式加以引用。全局对象消失之后不能使用。
[=]任何被使用的外部变量皆隐式地以传值方式加以引用。全局变量一直可以使用。
接着()中是传入参数,{}里面是方法体。
2.3兰布达表达式
3、触摸穿透(吞没)
4、多指触摸

20161217添加:
Xcode8.2+Cocos2d-x 3.10精灵创建不了的bug:


 

// add "HelloWorld" splash screen"

    auto sprite =Sprite::create("HelloWorld.png");
 
 {

gl.supports_vertex_array_object: true

cocos2d.x.version: cocos2d-x-3.10

gl.vendor: Apple Inc.

gl.supports_PVRTC: true

gl.renderer: Apple Software Renderer

cocos2d.x.compiled_with_profiler: false

gl.max_texture_size: 4096

gl.supports_ETC1: false

gl.supports_BGRA8888: false

cocos2d.x.build_type: DEBUG

gl.supports_discard_framebuffer: true

gl.supports_NPOT: true

gl.supports_ATITC: false

gl.max_samples_allowed: 4

gl.max_texture_units: 8

cocos2d.x.compiled_with_gl_state_cache: true

gl.supports_S3TC: false

gl.version: OpenGL ES 2.0 APPLE-13.0.7

}



libpng error: CgBI: unhandled critical chunk

libpng error: CgBI: unhandled critical chunk

libpng error: CgBI: unhandled critical chunk

(lldb) 

解决方法:

加载图片资源出现libpng error: CgBI: unhandled critical chunk 

设置Remove Text Metadata From PNG Files = NO.就可以正常显示了 


20170104问题:DELL 14英寸笔记本+Win8.1+OS X虚拟机+Xcode7.0.1+Cocos2d-x 3.10下iPhone 6s Plus的模拟器太大了,在显示器上看不全
解决方法:command+1,2,3,4,5调大小,虚拟机下command+4比较合适

20161008添加:
2.x——>3.x
1、 CCControlEvent改为cocos2d::extension::Control::EventType、CCControlEventTouchUpInside改为Control::EventType::TOUCH_UP_INSIDE、CCControlEventTouchDown改为Control::EventType::TOUCH_DOWN
2、 CCPointZero改为Vec2::ZERO或Point::ZERO
3、去掉CC:
CCControlButton、CCScale9Sprite
4、CCArray改为Vector<SpriteFrame*>,addObject改为pushBack
5、ccBLACK改为Color3B::BLACK
6、CCControlStateNormal改为Control::State::NORMAL
7、kCCRepeatForever改为kRepeatForever
8、menu_selector改为 CC_CALLBACK_1、callfunc_selector改为CC_CALLBACK_0
9、kCCAttributeNamePosition改为GLProgram::ATTRIBUTE_NAME_POSITION
10、去掉CCTargetedTouchDelegate
11、注释掉visit、keyBackClicked、registerWithTouchDispatcher、ccTouchBegan改为onTouchBegan
12、CCCallFunc::create(this,callfunc_selector(DZPKLayer::selfTimeOut))改为使用lambda表达式或者其他函数对象。这里,DZPKLayer::selfTimeOut的函数体没有使用DZPKLayer的成员变量和其它成员函数。注:lambda表达式内部也可以使用DZPKLayer的其他成员。
13、#include "AssetsManager/AssetsManager.h"改为#include "assets-manager/AssetsManager.h"、AssetsManager::kNoNewVersion改为AssetsManager::ErrorCode::NO_NEW_VERSION、AssetsManager::kNetwork改为AssetsManager::ErrorCode::NETWORK。
14、CCScrollViewDirection改为cocos2d::extension::ScrollView::Direction、kCCScrollViewDirectionVertical改为ScrollView::Direction::VERTICAL。

火烈鸟网络科技编著的2.x开发教程、Cocos2d-x游戏开发技术精解这两本书,都是基于2.0.4版本讲解且于2013年6月份出版的。
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.5.2节点的组织
前面我们已经接触了组织节点的基本方式:addChild方法。在介绍addChild方法时,我们是以向场景中添加层作为例子讲解的。而事实上,addChild是CCNode提供的方法,我们可以把任何的CCNode添加到另一个节点之中。
除了添加节点之外,CCNode还提供了一系列管理节点的方法,表3-3列出了这些方法。
表3-3 组织节点相关的方法
addChild|把child添加到当前节点之中
removeFromParentAndCleanup|把当前节点从其父节点中移除,如果cleanup为true,则执行clean方法
node->removeFromParentAndCleanup(true);
removeChild|从当前节点中移除child节点,如果cleanup为true,则调用child的clean方法
removeChild(node,true);
removeChildByTag|从当前节点中移除标号为tag的节点
removeChildByTag(tag_card_index);
removeAllChildrenWithCleanup|移除当前节点的所有子节点
this->removeAllChildrenWithCleanup(true);
getChildByTag|返回当前节点中标号为tag的节点
cleanup|停止此节点的全部动作与计时器
例子:RoomChip也是一个层,是主场景层的子节点
#include "RoomChip.h"
CCScene *scene=CCDirector::sharedDirector()->getRunningScene();
if (!scene->getChildByTag(10))
{   
return;
}
RoomChip *m_roomChip = dynamic_cast<RoomChip*>(scene->getChildByTag(10)->getChildByTag(3));
3.1.1CCNode类的成员数据
CCNode类的主要保护成员数据(子类可见,Protected关键字)如表3-2所示。
3.12CCNode类的函数
CCNode类的主要函数如表3-3所示。
函数名,返回类型,描述
getScale,浮点型,获得缩放系数
setScale,空,设置缩放系数
m_pCKPX_BTN->setOpacity(0);//255表示完全不透明,0表示完全透明
m_pCKPX_PIC = Sprite::createWithSpriteFrame(spriteFrame(texture_name::s_ol_bg_ckpx));
m_pCKPX_PIC->getTexture()->setAliasTexParameters();//图片放大时,不模糊但有锯齿
m_pCKPX_PIC->setScale(0);//整体缩放,s为比例,s=1表示原尺寸
m_pCKPX_PIC->setAnchorPoint(ccp(0,0));//(0,0)点代表左下点,(1,1)代表右上点
m_pCKPX_PIC->setPosition(ccp(myConfig.m_DZPKOperaLayerPos[1][0],myConfig.m_DZPKOperaLayerPos[1][1]));//xPos和yPos为相对于父节点锚点的位置
addChild(m_pCKPX_PIC);
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和它的子类可以作为精灵批处理类的子类。

//所有的音效API都被定义在SimpleAudioEngine类中,该类是一个单例类
SoundControl::sharedSoundControl()->playSoundEffect(sound_name::s_dzpk_win);
//使用精灵帧创建一个精灵
Sprite* GaneSuccentSprite = Sprite::createWithSpriteFrame(spriteFrame(texture_name::s_win));
//锚点就像用图钉把一张图纸钉在墙上一样。通过锚点可以把游戏元素定位在屏幕上。
//锚点是一个相对比例值,而不是一个坐标值。当前精灵的锚点是(0.5,0.5)表示当前锚点位于精灵的中心位置。
GaneSuccentSprite->setAnchorPoint(ccp(0.5,0.5));
//设置位置
//GaneSuccentSprite->setPosition(ccp(WINSIZE_W/3,WINSIZE_H/2));
GaneSuccentSprite->setPosition(ccp(myConfig.m_WinLosePos[0],myConfig.m_WinLosePos[1]));
//添加子节点,并指定z坐标和tag标签
addChild(GaneSuccentSprite,10,ApTage_03);

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连接。
直接在主线程中执行网络传输任务称作阻塞式传输,而在新线程中一部地进行网络传输任务则称为非阻塞式传输。【书中此处阻塞式传输的含义不恰当】
网络游戏需要保持用户终端数据与服务器的数据一致,这个过程称为同步。
20160804添加:
第10章 网络编程
HttpRequest是一种数据类型,它提供了一些方法用来定义或获取HTTP请求的参数。
/**
* The HttpRequest type enum used in the HttpRequest::setRequestType.
*/
enum class Type 
{   
GET,
POST, 
PUT,    
DELETE,
UNKNOWN,
};
HttpClient使用单例模式,用来处理异步HTTP请求。
如果在请求里设置了回调函数,当请求完成后,就会在主线程中调用该回调函数。它使用静态方法getInstance获取:
network::HttpClient::getInstance();
void RoomLayer::sendHttpRequest()

 //宏定义手机平台
 string url = ConfigMgr::instance()->text("display_text.xml", "t958");
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
 url = ConfigMgr::instance()->text("display_text.xml", "t957");
#endif
 CCLOG("%s completed", url.c_str());
 network::HttpRequest* request = new network::HttpRequest();
 request->setUrl(url.c_str());// 设置请求连接
 request->setRequestType(network::HttpRequest::Type::GET);// 设置请求类型
 request->setResponseCallback(this, callfuncND_selector(RoomLayer::onHttpRequestCompleted));// 设置请求完成后的回调函数
 request->setTag("GET test1");// 为请求设置一个标记
 network::HttpClient::getInstance()->send(request);// 发送请求
 network::HttpClient::getInstance()->setTimeoutForConnect(10);// 设置请求超时的时间
 network::HttpClient::getInstance()->setTimeoutForRead(10);// 设置下载超时的时间
 request->release();
}
 //获得网络数据
 void onHttpRequestCompleted(Node *sender, void *data);
HttpResponse也是一种数据类型,包含请求返回的数据等信息。
// getHttpRequest获取引发该请求的HttpRequest对象
 if (0 != strlen(response->getHttpRequest()->getTag()))  
 { 
  CCLOG("%s completed", response->getHttpRequest()->getTag()); 
 }
// 获取请求状态码。如果返回200,说明请求成功。
 int statusCode = response->getResponseCode();
// 判断请求是否成功
 if (!response->isSucceed())  
 { 
  CCLOG("response failed"); 
  CCLOG("error buffer: %s", response->getErrorBuffer());
  return; 
 } 
// 获取请求返回的数据 
 std::vector<char> *buffer = response->getResponseData();
调试信息:
https://www.110kino.com:1000/Android/update.htm completed
In the constructor of HttpClient!
GET test1 completed
response code: 200
{"version":"1.2.3","packageUrl":"/Client/Download.html"}
buffer = 0x0896b298 { size=61 }
vercode = "1.2.3"
updateUrl = "/Client/Download.html"
url = "https://www.110kino.com:1000/Client/Download.html"
D:\Project3.x\9yiLottery_3.x\cocos2d\cocos\network\HttpClient.h
#include "network/HttpClient.h"
<t957><a href="" www.110kino.com:1000="" ios="" update.htm<="" t957"="">" target="_blank">https://www.110kino.com:1000/IOS/update.htm</t957>;
<t958><a href="" www.110kino.com:1000="" update.htm<="" android="" t958"="">" target="_blank">https://www.110kino.com:1000/Android/update.htm</t958>;
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程序包。    

20160619、20160628添加:
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
英文版http://pan.baidu.com/share/link?shareid=1994603050&uk=1614005835
Pro Android C++ with the NDK.pdf
全部14章中文版http://pan.baidu.com/share/link?shareid=2785412732&uk=305441427
链接: http://pan.baidu.com/s/1o6FXq6u 密码: wszz
前3章中文版http://vdisk.weibo.com/s/u7lkQIf33pnBa
Android C++高级编程 使用NDK完整版nw.pdf
Android C++高级编程——使用NDK
2014年1月第1版
作者:(美国)辛纳(Onur Cinar) 译者:于红 佘建伟 冯艳红
目录
第1章Android平台上的C++入门
第2章深入了解Android NDK
第3章用JNI实现与原生代码通信
我们将会掌握以下主要概念:
Java代码如何调用原生方法
声明原生方法
在共享库中载入原生模块
在C/C++中实现原生方法
3.2.1原生方法的声明
Cocos2dxRenderer.java
nativeInit方法中含有关键字native以通知Java编译器,它用另一种语言提供该方法的具体实现。因为原生方法没有方法体,方法声明以语句终结符——分号结尾。
 @Override
 public void onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig) {
  Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);
  this.mLastTickInNanoSeconds = System.nanoTime();
 }
 private static native void nativeTouchesBegin(final int pID, final float pX, final float pY);
 private static native void nativeTouchesEnd(final int pID, final float pX, final float pY);
 private static native void nativeTouchesMove(final int[] pIDs, final float[] pXs, final float[] pYs);
 private static native void nativeTouchesCancel(final int[] pIDs, final float[] pXs, final float[] pYs);
 private static native boolean nativeKeyDown(final int pKeyCode);
 private static native void nativeRender();
        // 原生方法由原生库实现。该原生库与应用程序一起打包
 private static native void nativeInit(final int pWidth, final int pHeight);
 private static native void nativeOnPause();
 private static native void nativeOnResume();
尽管现在虚拟机知道该方法被原生实现,但是它仍然不知道到哪儿去找方法的实现。
3.2.2加载共享库
原生方法被编译成一个共享库。需要先加载该共享库以便虚拟机能够找到原生方法实现。java.lang.System类提供了两个静态方法,load和loadLibrary,用于在运行时加载共享库。
3.2.3实现原生方法
proj.android\jni\hellocpp\main.cpp
原生方法nativeInit也用一个名为Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit的完全限定的函数来声明,这种显式的函数命名让虚拟机在加载的共享库中自动查找原生函数。
原生方法多带了两个参数,第一个参数JNIEnv是指向可用JNI函数表的接口指针;第二个参数jobject是Cocos2dxRenderer类实例的Java对象引用。
(1)JNIEnv接口指针
原生代码通过JNIEnv接口指针提供的各种函数来使用虚拟机的功能。
(2)实例方法与静态方法
Java程序设计语言有两类方法:实例方法和静态方法。实例方法和静态方法均可以声明为原生的。
原生实例方法通过第二个参数获取实例引用,该参数是jobject类型的。
原生静态方法通过第二个参数获取类引用而不是实例引用,该参数是jclass值类型的。
#include "AppDelegate.h"
#include "platform/android/jni/JniHelper.h"
#include <jni.h>//这个头文件中包含JNI数据类型和函数的定义
#include <android/log.h>
#include "HelloWorldScene.h"
#define  LOG_TAG    "main"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
using namespace cocos2d;
extern "C"
{
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    JniHelper::setJavaVM(vm);
    return JNI_VERSION_1_4;
}
//nativeInit方法的原生实现
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)
{
    if (!CCDirector::sharedDirector()->getOpenGLView())
    {
        CCEGLView *view = CCEGLView::sharedOpenGLView();
        view->setFrameSize(w, h);
        AppDelegate *pAppDelegate = new AppDelegate();
        CCApplication::sharedApplication()->run();
    }
    else
    {
        ccDrawInit();
        ccGLInvalidateStateCache();
       
        CCShaderCache::sharedShaderCache()->reloadDefaultShaders();
        CCTextureCache::reloadAllTextures();
        CCNotificationCenter::sharedNotificationCenter()->postNotification(EVNET_COME_TO_FOREGROUND, NULL);
        CCDirector::sharedDirector()->setGLDefaultValues();
    }
}
}
3.7线程
作为多线程环境的一部分,虚拟机支持运行的原生代码。在开发原生构件时要记住JNI技术的一些约束:
1、只在原生方法执行期间及正在执行原生方法的线程环境下局部引用是有效的,局部引用不能在多线程间共享,只有全局引用可以被多个线程共享。
2、被传递给每个原生方法的JNIEnv接口指针在与方法调用相关的线程中也是有效的,它不能被其他线程缓存或使用。
3.7.2原生线程
JNI通过JavaVM接口指针提供了AttachCurrentThread函数以便于让原生线程附着到虚拟机上。JavaVM接口指针应该尽早被缓存,否则的
话它不能被获取。
JniHelper.cpp
#define JAVAVM    cocos2d::JniHelper::getJavaVM()
    static bool getEnv(JNIEnv **env)
    {
        bool bRet = false;
        do
        {
            if (JAVAVM->GetEnv((void**)env, JNI_VERSION_1_4) != JNI_OK)
            {
                LOGD("Failed to get the environment using GetEnv()");
                break;
            }
            // AttachCurrentThread将当前线程附着到虚拟机
            // 可以用JNIEnv接口实现线程与Java应用程序的通信
            // DetachCurrentThread将当前线程与虚拟机分离
            if (JAVAVM->AttachCurrentThread(env, 0) < 0)
            {
                LOGD("Failed to get the environment using AttachCurrentThread()");
                break;
            }
            bRet = true;
        } while (0);       
        return bRet;
    }

第4章使用SWIG自动生成JNI代码
第5章日志、调试及故障处理
第6章BionicAPI入门
第7章原生线程
7.3 POSIX线程
7.3.1在原生代码中使用POSIX线程
POSIX Thread的Android实现是Bionic标准C标准库的一部分。与其他平台不同,在编译时不需要链接任何其他的库。
第8章POSIXSocketAPI:面向连接的通信
第9章POSIXSocketAPI:无连接的通信
第10章POSIXSocketAPI:本地通信
第11章支持C++
第12章原生图形AP
第13章原生音频API
第14章程序概要分析和NEON优化

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。【VS2005也支持,VS2003不支持】
注意:VS2010只支持Win7以后的操作系统。【XP也支持】

20160908:搭建Cocos2d-x 2.0.3+VS2005开发环境
libBox2D
libchipmunk
libcocos2d - 3 个错误,106 个警告
1>d:\vc8project\2.0-x-2.03\cocos2dx\platform\win32\ccapplication.cpp(189) : error C2065: 'LSTATUS' : undeclared identifier
1>d:\vc8project\2.0-x-2.03\cocos2dx\platform\win32\ccapplication.cpp(189) : error C2146: syntax error : missing ';' before identifier 'status'
1>d:\vc8project\2.0-x-2.03\cocos2dx\platform\win32\ccapplication.cpp(189) : error C2065: 'status' : undeclared identifier
1>libcocos2d - 1 个错误,2 个警告
1>LINK : fatal error LNK1181: 无法打开输入文件“libzlib.lib”
1>libcocos2d - 1 个错误,0 个警告
1>LINK : fatal error LNK1181: 无法打开输入文件“libiconv.lib”
1>libcocos2d - 0 个错误,60 个警告
========== 生成: 1 已成功, 0 已失败, 0 最新, 0 已跳过 ==========
libCocosDenshion
libExtensions
liblua
TestCpp
1>ExtensionsTest.obj : error LNK2019: 无法解析的外部符号 "void __cdecl runEditBoxTest(void)" (?runEditBoxTest@@YAXXZ),该符号在函数 "public: void __thiscall ExtensionsMainLayer::menuCallback(class cocos2d::CCObject *)" (?menuCallback@ExtensionsMainLayer@@QAEXPAVCCObject@cocos2d@@@Z) 中被引用
1>D:\VC8Project\2.0-x-2.03\Debug.win32\TestCpp.exe : fatal error LNK1120: 1 个无法解析的外部命令
1>生成日志保存在“file://d:\VC8Project\2.0-x-2.03\samples\TestCpp\proj.win32\Debug.win32\BuildLog.htm”
1>TestCpp - 2 个错误,151 个警告
//runEditBoxTest();
TestJavascript
TestLua
1>d:\vc8project\2.0-x-2.03\scripting\lua\cocos2dx_support\luacocos2d.h(16) : fatal error C1083: Cannot open include file: 'cocos-ext.h': No such file or directory
1>d:\vc8project\2.0-x-2.03\scripting\lua\cocos2dx_support\luacocos2d.h(16) : fatal error C1083: Cannot open include file: 'cocos-ext.h': No such file or directory
1>TestLua - 2 个错误,8 个警告
附加包含目录
$(SolutionDir)\extensions
HelloLua
1>d:\vc8project\2.0-x-2.03\scripting\lua\cocos2dx_support\luacocos2d.h(16) : fatal error C1083: Cannot open include file: 'cocos-ext.h': No such file or directory
1>d:\vc8project\2.0-x-2.03\scripting\lua\cocos2dx_support\luacocos2d.h(16) : fatal error C1083: Cannot open include file: 'cocos-ext.h': No such file or directory
1>HelloLua - 2 个错误,7 个警告
附加包含目录
$(SolutionDir)\extensions
工作目录由$(OutDir)改为D:\VC8Project\2.0-x-2.03\samples\HelloLua\Resources

1>HelloCpp - 5 个错误,14 个警告
1>d:\vc8project\2.0-x-2.03\samples\hellocpp\classes\register.h(5) : fatal error C1083: Cannot open include file: 'cocos-ext.h': No such file or directory
1>d:\vc8project\2.0-x-2.03\samples\hellocpp\classes\login.h(5) : fatal error C1083: Cannot open include file: 'SimpleAudioEngine.h': No such file or directory
1>d:\vc8project\2.0-x-2.03\samples\hellocpp\classes\hall.h(5) : fatal error C1083: Cannot open include file: 'cocos-ext.h': No such file or directory
1>d:\vc8project\2.0-x-2.03\samples\hellocpp\classes\hall.h(5) : fatal error C1083: Cannot open include file: 'cocos-ext.h': No such file or directory
1>d:\vc8project\2.0-x-2.03\samples\hellocpp\classes\login.h(5) : fatal error C1083: Cannot open include file: 'SimpleAudioEngine.h': No such file or directory
附加包含目录
$(SolutionDir)\extensions
$(SolutionDir)\CocosDenshion\include
1>D:\VC8Project\2.0-x-2.03\Debug.win32\HelloCpp.exe : fatal error LNK1120: 11 个无法解析的外部命令
1>生成日志保存在“file://d:\VC8Project\2.0-x-2.03\samples\HelloCpp\proj.win32\Debug.win32\BuildLog.htm”
1>HelloCpp - 23 个错误,16 个警告
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下路径文件名大小写敏感
20160710添加:
VS2010+2.0.3工程移植到VS2012+2.2.5的步骤:
调试器无法继续运行该进程。项目文件""已被重命名或已不在解决方案中。
【确定】
python create_project.py -project ApplicationDemo -package org.cocos2dx.application -language cpp
VS2012打开ApplicationDemo工程
cygwin64编译so文件libcocos2dcpp.so:
cd /cygdrive/d/cocos2d-x-2.2.5/projects/ApplicationDemo/proj.android
export NDK_ROOT=/cygdrive/d/Hanxiaohua/android-ndk-r9
./build_native.sh
ADT打包apk文件ApplicationDemo.apk:
导入时根目录填D:\cocos2d-x-2.2.5\projects\ApplicationDemo\proj.android
工程属性文件target=android-8改为target=android-18
lib目录拷贝至src\org\cocos2dx\lib目录,与application目录平行
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
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.2 Android开发环境
2.2.3 iOS开发环境

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
20161215:MacBook Pro下Cocos2d-x 3.x iOS开发环境搭建
安装Cocos2d-x 3.10 mac版
/Applications/Cocos/Cocos2d-x
在终端中输入以下命令:
cd /Applications/Cocos/Cocos2d-x/cocos2d-x-3.10/tools/cocos2d-console/bin
ls
cocos new HelloApp -p com.hpcy.mahjong -l cpp -d ~/Desktop
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" 
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友盟 

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。

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。
20160728添加:
根目录填:
F:\Project3.x\QiXing\proj.android
target=android-15改为target=android-18
Description Resource Path Location Type
The project cannot be built until build path errors are resolved QiXing  Unknown Java Problem
安装3.10之后,配置ANT_ROOT环境变量
ANT_ROOT,C:\Cocos\tools\ant\bin
ANT_HOME,C:\Cocos\tools\ant
path,%ANT_HOME%\bin
classpath,C:\Cocos\tools\ant\lib
验证ant
如果出现如下内容,说明安装成功:
C:\Users\DELL->ant
Buildfile: build.xml does not exist!
Build failed
C:\Users\DELL->ant
Buildfile: build.xml does not exist!
Build failed
3.10中用cocos命令打包apk,可行
C:\Users\DELL->f:
F:\>cd F:\Project3.x\QiXing\proj.android
F:\Project3.x\QiXing\proj.android>cocos run -p android

最终生成F:\Project3.x\QiXing\bin\debug\android\QiXing-debug.apk
F:\Project3.x\QiXing\proj.android>cocos run -p android -m release
目前需要使用Eclipse或android studio来完成keystore设置和release发布
导入libcocos2dx工程
最终生成QiXing.apk
 
3.0一书中用Cygwin编译生成.so文件,在3.10中似乎不可行
DELL-@DELL ~
$ cd /cygdrive/f/Project3.x/QiXing/proj.android
DELL-@DELL /cygdrive/f/Project3.x/QiXing/proj.android
$ python build_native.py
Please use cocos console instead.

target=android-19改为target=android-18
uffers/Android.mk: Cannot find module with tag 'cocos/platform/third_party/andro
id/prebuilt/libcurl' in import path
Android NDK: Are you sure your NDK_MODULE_PATH variable is properly defined ?
make: *** [obj/local/armeabi/objs-debug/cocos2dcpp_shared/__/__/Classes/lottery/
LotteryKindScrollView.o] Error 1
make: *** Waiting for unfinished jobs....
make: Leaving directory `F:/Project3.x/9yiLottery_3.x/proj.android'
执行命令出错,返回值:2。
TCHAR改为TCHART就可以了
${NDK_ROOT}/ndk-build.cmd NDK_DEBUG=0
${ProjDirPath}
NDK_MODULE_PATH
C:\Cocos\Cocos2d-x\cocos2d-x-3.10\;C:\Cocos\Cocos2d-x\cocos2d-x-3.10\external\;F:\cocos2d-x-2.2.5\;F:\cocos2d-x-2.2.5\cocos2dx\platform\third_party\android\prebuilt\
注意不要漏掉\

20160721添加:
3.6
ApplicationDemo
libbox2d
libcocos2d
libSpine
3.10多了两个工程:
libbullet
librecast
C:\Users\DELL->cocos new -p com.QiXing.hapigame -l cpp -d F:\Project3.x QiXing
> 拷贝模板到 F:\Project3.x\QiXing
> 拷贝 cocos2d-x ...
> 替换文件名中的工程名称,'HelloCpp' 替换为 'QiXing'。
> 替换文件中的工程名称,'HelloCpp' 替换为 'QiXing'。
> 替换工程的包名,'org.cocos2dx.hellocpp' 替换为 'com.QiXing.hapigame'。
> 替换 Mac 工程的 Bundle ID,'org.cocos2dx.hellocpp' 替换为 'com.QiXing.hapigame
'。
> 替换 iOS 工程的 Bundle ID,'org.cocos2dx.hellocpp' 替换为 'com.QiXing.hapigame
'。
C:\Users\DELL->

DELL-的用户变量
安装CocosForWin-v3.10前:
COCOS_CONSOLE_ROOT
F:\hxhwin7\cocos2d-x-3.6\tools\cocos2d-console\bin
COCOS_TEMPLATES_ROOT
F:\hxhwin7\cocos2d-x-3.6\templates
安装CocosForWin-v3.10后:
COCOS_CONSOLE_ROOT
C:\Cocos\Cocos2d-x\Cocos2d-x-3.10\tools\cocos2d-console\bin
COCOS_TEMPLATES_ROOT
C:\Cocos\Cocos2d-x\Cocos2d-x-3.10\templates
COCOS_X_ROOT
C:\Cocos\Cocos2d-x
PATH
C:\Cocos\Cocos2d-x\Cocos2d-x-3.10\templates;C:\Cocos\Cocos2d-x\Cocos2d-x-3.10\tools\cocos2d-console\bin;

F:\hxhwin7\cocos2d-x-3.6\setup.py
NDK_ROOT输入
F:\android-ndk-r9
ANDROID_SDK_ROOT输入
F:\adt-bundle-windows-x86_64-20130729\sdk
ANT_ROOT忽略
打开DOS命令行
C:\Users\DELL->echo %COCOS_CONSOLE_ROOT%
F:\hxhwin7\cocos2d-x-3.6\tools\cocos2d-console\bin
C:\Users\DELL->echo %ANDROID_SDK_ROOT%
F:\adt-bundle-windows-x86_64-20130729\sdk
C:\Users\DELL->echo %NDK_ROOT%
F:\android-ndk-r9
输入cocos命令,该命令不仅可以创建项目,还可以编译、运行、编译js版本和部署到不同的平台。
创建工程:
C:\Users\DELL->cocos new -p org.cocos2dx.simplegame -l cpp -d F:\Project3.x Simp
leGame
Running command: new
> Copy template into F:\Project3.x\SimpleGame
> Copying cocos2d-x files...
> Rename project name from 'HelloCpp' to 'SimpleGame'
> Replace the project name from 'HelloCpp' to 'SimpleGame'
> Replace the project package name from 'org.cocos2dx.hellocpp' to 'org.cocos2dx
.simplegame'
> Replace the mac bundle id from 'org.cocos2dx.hellocpp' to 'org.cocos2dx.simple
game'
> Replace the ios bundle id from 'org.cocos2dx.hellocpp' to 'org.cocos2dx.simple
game'
C:\Users\DELL->cocos new -p org.cocos2dx.application -l cpp -d F:\Project3.x App
licationDemo
Running command: new
> Copy template into F:\Project3.x\ApplicationDemo
> Copying cocos2d-x files...
> Rename project name from 'HelloCpp' to 'ApplicationDemo'
> Replace the project name from 'HelloCpp' to 'ApplicationDemo'
> Replace the project package name from 'org.cocos2dx.hellocpp' to 'org.cocos2dx
.application'
> Replace the mac bundle id from 'org.cocos2dx.hellocpp' to 'org.cocos2dx.applic
ation'
> Replace the ios bundle id from 'org.cocos2dx.hellocpp' to 'org.cocos2dx.applic
ation'
C:\Users\DELL->
问题1:
无法启动程序,因为计算机中丢失MSVCR120.dll。尝试重新安装该程序以解决此问题。
【确定】
解决方法:
64位MSVCR120.DLL放在C:\Windows\SysWOW64
问题2:
错误 1 error C1083: 无法打开包括文件:“extensions/ExtensionExport.h”: No such file or directory f:\project3.x\applicationdemo\cocos2d\extensions\gui\cccontrolextension\cccontrolutils.h 39 1 ApplicationDemo
解决方法:
1、在你自己的头文件中加入#include ”cocos-ext.h"
2、使用命名空间USING_NS_CC_EXT;
3、选中工程右键“属性”->"配置属性“->"c/c++"->"常规”->"附加包含目录"中添加“”$(EngineRoot)
名称,值
$(EngineRoot),F:\Project3.x\ApplicationDemo\cocos2d\cocos\2d\..\..\
问题3:
Cocos2d-x 3.10+VS2012 UIScale9Sprite.cpp编译报错    
1>..\ui\UIScale9Sprite.cpp(1172): error C2059: 语法错误:“{”
1>..\ui\UIScale9Sprite.cpp(1172): error C2143: 语法错误 : 缺少“;”(在“{”的前面)
1>..\ui\UIScale9Sprite.cpp(1172): error C2143: 语法错误 : 缺少“;”(在“}”的前面)
1>..\ui\UIScale9Sprite.cpp(1176): error C2059: 语法错误:“{”
1>..\ui\UIScale9Sprite.cpp(1176): error C2143: 语法错误 : 缺少“;”(在“{”的前面)
1>..\ui\UIScale9Sprite.cpp(1176): error C2143: 语法错误 : 缺少“;”(在“}”的前面)
1>..\ui\UIScale9Sprite.cpp(1210): error C2059: 语法错误:“{”
解决方法:
VS2012对C++11语法支持不全,那个语法刚好就是它不支持的,改掉就好。
如下:
            uvCoordinates = {Vec2(u0,v3), Vec2(u3,v0)};
改成
            uvCoordinates.push_back(Vec2(u0,v3));
            uvCoordinates.push_back(Vec2(u3,v0));

20160712添加: 
2.3文字类
引擎提供了3种方式来实现文字的处理,
第一种方式有3个类,分别是LabelTTF、LabelAtlas和LabelBMFont;
第二种方式全部由Label类完成;
第三种方式则是使用Widget的子类Text、TextAtlas和TextBMFont完成。
这3种方式实现的结果一样,只是处理方式不同。
每种方式又包括3种文字的创建,分别是使用系统字体或TTF字体来创建;使用一张图片来创建,图片中的每个字符都有固定的宽和高;
使用图片和对应的配置文件来创建,图片中每个字符的宽和高可以变化,配置文件中存储着各个字符的信息。
2.5列表类
对于列表,引擎提供了几种实现方式,既有2.x版本中extension命名空间的ScrollView类和TableView类,又有3.x版本中ui命名空间的ScrollView类、PageView类和ListView类。
对于ui命名空间下对应的类,效果是一样的,只是实现方式不一样而已。
2.5.2 TableView类
当使用滚动视图时,对于显示的每一项没有什么规律时,一般使用ScrollView类实现,如游戏中使用文字的方式介绍游戏或聊天系统等。
但当其中每一项的格式都类似时,则使用TableView的方式来实现,如游戏中的充值列表、好友榜等,该类继承自ScrollView。
CCTableViewDelegate类的函数
// 当TableViewCell被单击时,响应函数,它是一个纯虚函数,当继承该类时,必须重写该方法
tableCellTouched
CCTableViewDataSource类的函数
// 设置TableView中每一项的大小
cellSizeForTable
// 列表中每一项的数据,都在这里创建和设置,是一个纯虚函数,子类必须重写
tableCellAtIndex
// 设置列表一共有多少项
numberOfCellsInTableView
第10章 图形用户界面
F:\hxhwin7\cocos2d-x-3.6\cocos\ui
在Cocos2d-x根目录下的ui目录下,是本章要讲到的图形用户界面类,这些类包括:布局文本Text、按钮Button、复选框CheckBox、视图列表ListView、图片视图ImageView、分页视图PageView和布局Layout等。
这些UI组件可以通过两种方式使用,
一、通过CocosBuilder构建好,并产生json配置文件,程序加载json文件,实现UI组件。
二、直接使用UI代码来实现。
F:\hxhwin7\cocos2d-x-3.6\extensions\GUI
另外的一部分UI组件位于Cocos2d-x根目录下的extensions/GUI目录下,这里面包括:编辑框EditBox、滚动视图ScrollView、表格视图TableView和控制视图Control及其子类。
10.1文本
文本(Text)就像我们前面学习的Label标签,可以显示一些文字,也可以设置文字的字体、字号、颜色和对齐方式等属性。
10.2按钮
按钮(Button)类似于我们前面讲到的精灵菜单项,或者图片菜单项。按钮可以响应回调事件,实现一些事件处理逻辑。
10.3复选框
复选框(CheckBox)有选中和未选中两个状态,可以为其添加事件监听器来响应事件处理。
10.4滑块
滑块(Slider)一般用来控制一些音量、屏幕明暗等。滑块组件由滑块和进度组成,可以添加监听器事件,事件处理函数中可以获得当前进度大小。
10.5加载条
加载条(LoadingBar)也叫进度条,一般应用在游戏启动中,在加载资源时显示加载进度,或者从网络获取资源时显示进度等。
10.6布局
所谓布局就是界面上的组件如何摆放,是水平、垂直,还是相对布局等。布局的实现由布局类Layout、布局参数类LayoutParameter和边距类Margin来实现。
10.7滚动视图
滚动视图(ScrollView)继承自Layout,也是一个布局类,可以使放置在其内部的视图组件滚动显示。
ScrollView的创建比较简单,使用create方法来创建。
可以使用setDirection方法来设置滚动方向。
Direction是一个枚举常量类。
10.8列表视图
列表视图(ListView)继承自ScrollView,具有滚动视图的特性。ListView里面维护着一个数组列表项,我们可以通过ListView中的添加、删除列表项方法来维护这些列表项。可以为ListView添加事件监听器来检测哪个列表项被选中。
10.9表格视图
Cocos2d-x中的表格视图(TableView),完全借鉴了iOS中TableView的设计。
首先,表格视图TableView继承自ScrollView,是一个滚动视图,这里的ScrollView是cocos2d::extension命名空间下面的ScrollView。另外,创建一个TableView,有两个辅助类,一个是数据源类TableViewDataSource,封装了表格的数据源,另外一个是代理类TableViewDelegate,提供了一些额外操作方法。
表格里面的每一行数据都由TableViewCell对象封装。
10.10编辑框
编辑框(EditBox)常用来收集一些用户信息。
create静态函数:
编辑框的创建。第一个参数是编辑框的大小;第二个参数是默认情况下的图片(这里是一个可以缩放的图片,被封装成精灵);第三个参数是按下的图片,默认为空;第四个参数是禁用的图片,默认为空。
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+。

4.4扩展控件
4.4.1滑动条控件ControlSlider
滑动条控件常用来设置一个连续值的调整,比如音量调整等。ControlSlider继承自Control类。
1、ControlSlider::create(滑动条背景,滑动条进度,滑动条拖曳图标)
2、setMaximumValue、setMinimumValue设置滑动条的最大值和最小值
3、setMaximumAllowedValue、setMinimumAllowedValue设置滑动条可使用的最大值和最小值
4、setAnchorPoint、setPosition设置slider的位置
5、addTargetWithActionForControlEvents为滑动条添加值变化事件监听器,当值发生变化时就会触发该函数
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设置的请求连接。

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服务器,至此,这个问题就彻底解决了。

附录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();
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.3标签菜单项(MenuItemLabel)
另外,我们还可以使用MenuItemLabel的子类MenuItemFont和MenuItemAtlasFont来创建字体菜单和图集菜单。
// 菜单
CCMenu* menu = CCMenu::create();
menu->setPosition(Vec2::ZERO);
bk1->addChild(menu);
  
CCMenuItemFont* itemReset = CCMenuItemFont::create("reset",this,menu_selector(UpdateLayer::reset));
itemReset->setPosition(ccp(visibleSize.width/2, 50));
menu->addChild(itemReset);
// 创建一个字体标签菜单项,第一个参数是显示的内容,第二个参数是函数回调。
CCMenuItemFont* itemGetClientVersion = CCMenuItemFont::create("getClientVersion",this,menu_selector(UpdateLayer::getClientVersion));
itemGetClientVersion->setPosition(ccp(visibleSize.width/2, 100));
menu->addChild(itemGetClientVersion);
//
CCMenuItemFont* itemGetServerVersion = CCMenuItemFont::create("checkUpdate",this,menu_selector(UpdateLayer::checkUpdate));
itemGetServerVersion->setPosition(ccp(visibleSize.width/2, 150));
menu->addChild(ite·etServerVersion);
//
CCMenuItemFont* itemUpdateVersion = CCMenuItemFont::create("updateVersion",this,menu_selector(UpdateLayer::update));
itemUpdateVersion->setPosition(ccp(visibleSize.width/2, 200));
menu->addChild(itemUpdateVersion);
//
CCMenuItemFont* itemEnterScene = CCMenuItemFont::create("enterScene",this,menu_selector(UpdateLayer::enterScene));
itemEnterScene->setPosition(ccp(visibleSize.width/2, 250));
menu->addChild(itemEnterScene);
5.4精灵菜单项(MenuItemSprite)
可以通过精灵来创建一个菜单项,使用精灵创建菜单可以指定三个状态:默认状态、选中状态和实效状态,另外,还可以让精灵执行一些动作,使得游戏画面更加生动。
create静态函数:
第一个参数是默认精灵,第二个是选中精灵,第四个参数是回调函数。
// 3.x使用精灵菜单项创建【开始】、【离开】菜单
Sprite * Start1 = Sprite::createWithSpriteFrame(spriteFrame(texture_name::s_start_button1));
Sprite * Start2 = Sprite::createWithSpriteFrame(spriteFrame(texture_name::s_start_button2));
Sprite * exit_1 = Sprite::createWithSpriteFrame(spriteFrame(texture_name::s_exit_button1));
Sprite * exit_2 = Sprite::createWithSpriteFrame(spriteFrame(texture_name::s_exit_button2));
MenuItemSprite *StartItem = MenuItemSprite::create(Start1,Start2,CC_CALLBACK_1(DZPKLayer::LeaveGameResume,this));
StartItem->setTag(StartTag);
StartItem->setPosition(ccp(WINSIZE_W*3/4,WINSIZE_H/3));
MenuItemSprite *LeaveItem = MenuItemSprite::create(exit_1,exit_2,CC_CALLBACK_1(DZPKLayer::LeaveGameResume,this));
LeaveItem->setTag(LeaveTag);
LeaveItem->setPosition(ccp(WINSIZE_W*3/4,WINSIZE_H/5));  
StartLeave= Menu::create(StartItem,LeaveItem,NULL);
StartLeave->setPosition(ccp(0,0)); 
addChild(StartLeave,0);
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");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pic_dating.plist");
////SpriteFrameCache::getInstance()->addSpriteFramesWithFile("cardtable1.plist","cardtable1.png");
////SpriteFrameCache::getInstance()->addSpriteFramesWithFile("cardtable2.plist","cardtable2.png");
////SpriteFrameCache::getInstance()->addSpriteFramesWithFile("cardtable3.plist","cardtable3.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("normal_button.plist","normal_button.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("plaza.plist","plaza.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("sprite1.plist","sprite1.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("sprite2.plist","sprite2.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("tab_button.plist","tab_button.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("shop.plist","shop.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("exchange.plist","exchange.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("luckyDraw1.plist","luckyDraw1.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("luckyDraw2.plist","luckyDraw2.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("player_info.plist","player_info.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("medal.plist","medal.png");
//SpriteFrameCache::getInstance()->addSpriteFramesWithFile("DZPKImageAdd.plist","DZPKImageAdd.png");        //dzpk
根据精灵帧名称获得精灵帧
//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
14.2 XML数据解析
TinyXML是一个开源的解析XML的解析库,Cocos2d-x集成了该库,在Cocos2d-x项目的根目录的external/tinyxml2目录下面有该类的实现。
在TinyXML中,根据XML的各种元素定义了一些类。
XMLDocument:文档
XMLElement:元素
XMLAttribute:属性
XMLComment:注释
XMLNode:节点
XMLText:文本
XMLDeclaration:声明
XMLUnknown:未知部分
Cocos2d-x游戏编程——C++篇
徐飞 著
2015年9月第1版
20160709添加:
1.2.4回调函数的变化
在2.x中,回调函数使用函数指针的方式来实现
//类函数指针定义
//update函数,带一个float参数
//回调不带参数
//回调带一个节点指针参数
//回调带一个节点指针和一个void指针参数
//回调带一个对象指针参数
例子:O代表对象指针参数
//游戏记录新增
void AddGameRecord(Object *obj);
void CardTableLayer::AddGameRecord(Object *obj)
{
 
int ZXP = ((Integer *)obj)->getValue();
 
AddWinLostResult(ZXP);
}
NotificationCenter::getInstance()->addObserver(this, callfuncO_selector(CardTableLayer::AddGameRecord), "AddGameRecord", NULL);
NotificationCenter::getInstance()->removeObserver(this, "AddGameRecord");
NotificationCenter::getInstance()->postNotification("AddGameRecord", Integer::create(ZXP));
//菜单对应函数,带一个对象指针参数
//回调带一个事件指针参数
//回调带一个对象指针参数和一个int返回值
//宏定义
1、用在update等函数的定义中
schedule_selector宏、参数为float的例子:
//点击菜单中的【开始】按钮,开始下一局 
schedule(schedule_selector(DZPKLayer::restartGame),0.1f);
//玩家超时没有准备,30秒没执行则返回大厅
schedule(schedule_selector(DZPKLayer::CloseRoundOpera),30.0f);
2、用在动画的执行中,用来定义瞬时动画
3、用在菜单响应事件上
而在3.x中,引入C++ 11标准中的bind函数,只有4个宏定义来实现。
//不带参数宏定义
//带一个参数宏定义
//带二个参数宏定义
//带三个参数宏定义
在3.x中,使用bind函数的功能,通过回调函数的参数个数来决定使用哪个宏,而不用区分哪个是对应菜单回调,哪个是update回调等。
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关键字表明,该函数不能被继承,已经是最终版本了,如果子类有重写该函数,则编译器就会报错。

第13章 自动更新
13.2 so文件更新
Cocos2d-x引擎中,如果编程语言是C++,那么跨平台编译到Android平台后,所有的代码都编译到一个so文件中。所以,如果代码中有一个小的改动,则需要更新这个so文件。
根据MD5算法的特性,如果某文件有一个小的改动,那么它的MD5值就会变化,所以可以根据计算MD5值判断so文件是否更新。

第15章 iOS
以引擎的2.2.3版本来介绍,对于3.5版本,是类似的。
Copy items if needed指是否把加入的文件复制到当前目录下,如果选择它,资源会复制到proj.ios目录下。
我们的Classes与Resources目录和proj.ios是同级的,所以这一项最好不要选择;下面两个单选是group和folder的区别,前者以组的方式组织文件,它是逻辑上的,在硬盘上资源可以是凌乱的。如果是代码文件,以group的方式加入项目中。Xcode编译器会对代码进行编译;后者以文件夹的方式组织文件。以这种方式加入到项目中的文件,如果是代码文件,编译器不会对其进行编译,文件夹里面的资源只会直接copy到bundle包中。
所以,Classes文件夹以group的方式加入到项目中,而Resources中的资源文件以folder的方式加入。
15.2.1 info.plist文件
项目中有一个info.plist文件,它用于存储游戏的元数据,是一个xml格式的文件,以key和value的方式组织数据,用于存储和读取我们游戏中用到的数据。
表15-1 info.plist部分属性
属性|描述
Bundle display name|游戏名字,用于在iOS系统界面显示
Bundle name|包的简称,应该小于16个字符,可以和Bundle display name不同
Bundle Identifier|包的ID标识
Supported interface orientations|设备支持的方向,与General设置Device Orientation的方向对应
Bundle version|和General中的Build号对应
Bundle version string|和General中的Version号对应
15.2.2 Icon和Launchimage设置
iOS应用,必须为其指定App Icons和Launch Images。在Xcode5后,它们通过Asset Catalog来管理。
Lauch Screen File是Xcode6.0和iOS 8.0之后引入的,它用一个xib文件作为启动画面。
iPhone的启动页面只支持竖屏的,对于横屏游戏,也应该做成竖屏图片。
15.3真机调试
开发者账号有4种类型:个人\公司\企业\教育
15.3.1证书
证书有两种:开发证书(Development)和发布证书(Production)。
本书讲解开发证书申请的流程,发布证书类似。
在苹果系统的应用程序中,找到keychain access,在这里申请CSR。
CSR文件在申请证书时要用到。在申请CSR文件过程时,生成一对公钥和私钥,保存在计算机的keychain中,代码签名基于这种非对称秘钥的加密方式,用私钥进行签名,用公钥进行验证。私钥保存在计算机中,可以把私钥导出,提供给别的开发者使用,它是一个后缀为p12的文件。
而公钥保存在下面生成的Certificate中,当你用自己的私钥对代码签名后,苹果就可以用Certificate中的公钥进行验证了,保证了代码的安全性。

20160807添加:
chap13 使用Cocos2d-x制作2048休闲游戏
13.2使用CocoStudio制作UI界面
13.3编写逻辑代码
13.3.1把UI界面添加到游戏界面中
游戏开始后加载该场景
runWithScene
在init方法中加入UI界面
widgetFromJsonFile
13.3.2添加获取分数控件并设置分数
Helper::seekWidgetByName
13.3.3添加数字方块类
13.3.4初始化游戏数据
13.3.5添加按钮功能
要从UI界面中获取两个按钮
Helper::seekWidgetByName
为两个按钮注册回调函数
addTouchEventListener
toucheventselector
13.3.6添加事件监听

19.4 CocoStudio
CocoStudio是Cocos2d-x官方推出的一款游戏编辑器,它集成了UI编辑器、动画编辑器、场景编辑器和游戏数据编辑器。
启动界面下有4个编辑器选项,分别是动画编辑器、UI编辑器、场景编辑器和数据编辑器。可以选择某一个编辑器来运行它们。

CocoStudio中的UI Editor是非常实用并且操作简单的UI编辑工具。
步骤1:打开UI Editor
打开CocoStudio,选择下方第二个选项UI Editor。
步骤2:新建项目
步骤3:导入资源
步骤4:添加按钮
步骤5:添加背景、滑动条、数字标签、文本标签控件
步骤6:修改对象结构关系
步骤11:初始化UI界面
#include "cocostudio/CocoStudio.h"

#include "cocos/editor-support/cocostudio/CocoStudio.h"
#include "cocos/ui/CocosGUI.h"
using namespace cocostudio;
using namespace ui;
cocos2d::ui::Widget*       m_uiWidget;
 m_uiWidget = GUIReader::getInstance()->widgetFromJsonFile("ExchangeLayer/ExchangeLayer.ExportJson");
 this->addChild(m_uiWidget);

setScaleX
const int kResolutionWidth   = 1360;
const int kResolutionHeight   = 768;
 this->setContentSize(Size(NS_lrbyFish::kResolutionWidth,NS_lrbyFish::kResolutionHeight));
 // 按照屏幕尺寸缩放
 this->setScaleX(UI_SCREEN_W/(float)kResolutionWidth);
 this->setScaleY(UI_SCREEN_H/(float)kResolutionHeight); 

 Widget* UI = GUIReader::getInstance()->widgetFromJsonFile("ComLayer/BankerList_1/BankerList_1.json");
 this->addChild(UI,10);
 //按比例缩放 长宽
 UI->setScaleX((float)1136/1920);
 UI->setScaleY((float)640/1080);
getVisibleSize
getContentSize
步骤12:UI对象的使用
1、获取UI中的对象。
2、添加事件。
3、设置属性。
getChildByName
cocos2d::ui::Button*       closeBtn;
closeBtn = dynamic_cast<Button*>(panel->getChildByName("close"));
void RechargeLayer::SetBtnCallBack(cocos2d::Ref* target,cocos2d::ui::SEL_TouchEvent selector)
{
 if (closeBtn != nullptr)
 {
  closeBtn->addTouchEventListener(target,selector);
 }
}
((RechargeLayer*)m_gameWidget)->SetBtnCallBack(this,SEL_TouchEvent(&LobbyScene::OnBtnCallBack));
Text* content= (Text*) m_list_Daili->getItems().at(0)->getChildByName("content");
content->setString(CGameLobby::GetInstance()->readLanguageString("Daili002")->getCString());
Label* text = dynamic_cast<Label*>(subBg->getChildByName("score_text"));
if (text != nullptr)
{
   text->setString(StringUtils::format("%lli", score));
}

20161111添加:
Cocos2d-x 3.x游戏开发实战
肖文吉 编著
2015年1月第1版
chap1 Cocos2d-x游戏引擎介绍
1.3.4 Cocos2d-x 3.0的新特性
1、使用C++(C++ 11)的特性取代了Objective-C的特性
2、新的渲染器
3、优化了Labels
4、新的事件分发机制
所有事件都由EventDispatcher分发。
5、物理引擎集成
chap3 Cocos2d-x的核心类
3.1节点类(Node)
继承自Ref类,同时也是所有节点类的父类。
3.1.1 Node类的成员变量
Node类常用的受保护的成员变量如下。
_scaleX、_scaleY、_scaleZ:表示节点X、Y、Z轴的缩放比例,节点以锚点为中心缩放该比例。变量是float,默认为1.0。
例如:
playerInfo[i].head->setScale(0.8f);
playerInfo[i].level->setScale(0.75f);
playerInfo[i].chipValue->setScale(0.8);
_position:表示节点在屏幕中的位置。注意:Position设置的是节点在父节点中的坐标值。
例如:
int positionX = playerInfo[i].head->getPositionX();
int positionY = playerInfo[i].head->getPositionY()+2;
m_pCountDown[i]->setPosition(ccp(bkWidth/2,bkHeight - yDelta-yDelta-10));
StartSpriteTag[i]->setPosition(ccp(bkWidth/2,bkHeight - yDelta-yDelta-70));
playerCard[7].cards[0]->setPosition(ccp(bkWidth/2+15*cardDelta,bkHeight-yDelta*3/2));
playerCard[7].cards[1]->setPosition(ccp(bkWidth/2+17*cardDelta,bkHeight-yDelta*3/2));
playerInfo[i].level->setPosition(ccp(positionX-40,positionY+30));
playerInfo[i].infoBG->setPosition(ccp(positionX+100,positionY));
playerInfo[i].chipValue->setPosition(ccp(positionX+100,positionY - 15));
_anchorPoint:表示节点的锚点。锚点的变量类型是Vec2。锚点的x和y取值通常是0~1之间的实数,表示锚点相对于节点长宽的位置。另外,还有_anchorPointInPoints成员变量,区别在于其采用绝对像素值为单位。
例如:
playerInfo[i].playerName->setAnchorPoint(Point::ZERO);
_visible:用于判断节点是否可见。变量类型是bool,默认值为true。
例如:
playerInfo[i].nullHead->setVisible(false);
playerInfo[chairID].nullHead->setVisible(true);
chap6 Cocos2d-x的事件处理机制
6.1事件处理机制
6.1.1接收数据Touch
6.1.2分发事件EventDispatcher
6.1.3处理响应EventListener
6.2触摸事件
6.3加速度计事件
6.4按键事件
6.5鼠标事件
6.6自定义事件
6.7本章小结
chap14 Cocos2d-x的内存管理
Cocos2d-x的内存管理采用了Objective-C当中的“引用计数”和“自动释放池”的方式。
14.1内存管理概述
在内存管理中经常会遇到两个问题。
1、内存溢出
2、内存泄露
有效的内存管理通常包括两个方面的内容。
1、内存分配
2、内存回收
典型的内存回收策略有两种。
自动回收
混合回收
Cocos2d-x的内存管理结合了手动管理内存和自动管理内存两种方式。
手动的内存回收:
retain
release
autorelease
自动释放池是Cocos2d-x推荐的内存管理方式。
14.2手动内存管理
14.2.1对象的引用计数
Cocos2d-x采用了一种称之为引用计数的机制来跟踪对象的状态。
Ref中提供了有关引用计数的如下函数。
retain:将该对象的引用计数加1。
release:将该对象的引用计数减1。
autorelease:不改变对象的引用计数器的值,只是将对象添加到自动释放池中。该函数将会返回该方法的对象本身。
getReferenceCount:返回该对象的引用计数器的值。
14.2.2对象所属权
14.2.3函数中的保留和释放
14.2.4使用自动释放池
14.3自动释放池
chap7 Cocos2d-x的常用控件
4.3.3使用TableView展示多页内容
TableView继承自ScrollView。
TableViewDelegate继承自ScrollViewDelegate。
TableView的使用方式类似cocoa框架的UITableView,用到TableView的类需要继承TableViewDataSource,然后声明几个函数。
class LotteryKindScrollView : public Layer,TableViewDataSource,TableViewDelegate
{
public:
    LotteryKindScrollView();
    ~LotteryKindScrollView();
    virtual bool init();
    static Scene* scene();
    void pressKindButton(int tag);
    void connectGameRoomServer(int tag);
    CREATE_FUNC(LotteryKindScrollView);
        //视图滚动时调用
 virtual void scrollViewDidScroll(ScrollView* view);
        //视图缩放时调用
 virtual void scrollViewDidZoom(ScrollView* view);
 //tableCellTouched:触摸单元格时,会调用该函数
 //触摸事件 计算的是点击的是那个子页
 virtual void tableCellTouched(TableView* table, TableViewCell* cell);
 //3.0 tableCellSizeForIndex:根据index设定每一个单元格的大小
 //3.5 cellSizeForTable:设置TableView中每一项的大小
 //每一项的高度和宽度
 virtual cocos2d::Size cellSizeForTable(TableView *table);
 //tableCellAtIndex:根据index为单元格设置内容
 //生成列表的每一项内容
 virtual TableViewCell* tableCellAtIndex(TableView *table, ssize_t idx);
 //numberOfCellsInTableView:返回单元格的个数
 //一共多少项
 virtual ssize_t numberOfCellsInTableView(TableView *table);
 //刷新
 void refreshLayer();
public:
    void onEnter();
    void onExit();
    bool onTouchBegan(Touch *pTouch, Event *pEvent);
    void onTouchMoved(Touch *pTouch, Event *pEvent);
    void onTouchEnded(Touch *pTouch, Event *pEvent);
    void onTouchCancelled(Touch *pTouch, Event *pEvent);
 //itype 0为游戏 1为彩票 2为体育
 void resetTable(const char* preName,const int count,const int iType);
private:
 int selectedSpriteTag;
 std::vector<int> m_Data;
 int m_Count;
 string m_name;
 TableView* m_table;
 TableViewCell* pCell;
 Vec2 start_pos;
};
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发布


Cocos2d-x v3.1开始支持3D模型。
Cocos2d-x v3.2支持3D骨骼动画。加入对游戏手柄的支持以及一些性能上的优化。
http://www.docin.com/p-888314762.html
比较著名的帧动画格式是Quake2所采用的MD2。
帧动画原理
将每帧所需要的所有顶点的:顶点位置、法线或顶点颜色、纹理坐标等信息全部存储起来,在渲染的时候逐帧播放或插值播放,这就是帧动画的原理。
骨骼动画技术后于帧动画技术的出现。
最开始,骨骼动画仅用于非实时渲染的建模领域,如3DMax这类建模软件之中,以方便美工的建模。
后来,CPU从渲染中解放后,骨骼动画才用于实时渲染的游戏中。
骨骼动画的想法来源于人体骨骼。
两个概念:
骨骼SKELETON:用以控制蒙皮的一种抽象的概念。在最终的渲染结果中,它不可见。
蒙皮SKINMESH:被骨骼控制、并显示在外的因素。实际上就是顶点、法线、纹理坐标等将被渲染的元素。
MDL是比较经典的骨骼动画格式,由于CS的成功而被追捧。
为了播放骨骼动画,需要有骨骼的数据,模型的数据,关联骨骼和模型上每个顶点的关联数据,以及关键帧的坐标变换数据。
20160914:
3.x手柄,PC下链接不过
http://www.cocos.com/doc/tutorial/show?id=1166
2>HelloWorldScene.obj : error LNK2019: 无法解析的外部符号 "public: static class cocos2d::EventListenerController * __cdecl cocos2d::EventListenerController::create(void)" (?create@EventListenerController@cocos2d@@SAPAV12@XZ),该符号在函数 "public: virtual bool __thiscall HelloWorld::init(void)" (?init@HelloWorld@@UAE_NXZ) 中被引用
2>HelloWorldScene.obj : error LNK2019: 无法解析的外部符号 "public: static void __cdecl cocos2d::Controller::startDiscoveryController(void)" (?startDiscoveryController@Controller@cocos2d@@SAXXZ),该符号在函数 "public: virtual bool __thiscall HelloWorld::init(void)" (?init@HelloWorld@@UAE_NXZ) 中被引用

3.x虚拟手柄
https://github.com/cheyiliu/joystick


20161121-20161207资源热更新
http://blog.csdn.net/linchaolong/article/details/42321767
https://coding.net/u/linchaolong/p/Cocos2d-x_HotUpdate/git
http://www.cocos.com/docs/creator/advanced-topics/hot-update.html
http://blog.csdn.net/renzhe20092584/article/details/9184163
http://www.cocos2d-x.org/wiki/Assets_manager
cocos2d-x 3.10 热更新 使用AssetsManagerEx
http://blog.csdn.net/strivero/article/details/51130784
AssetsManagerEx组件使用说明
http://www.cnblogs.com/anxin1225/p/5318793.html
cocos2dx-3.x 用脚本生成 AssetsManagerEx自动更新所需的manifest文件
http://blog.csdn.net/qlt445_ndsc/article/details/51325296
http://zengrong.net/post/2131.htm
这里说的热更新(Hot update),指的是客户端的更新。
大致的流程是,客户端在启动后访问更新api,根据更新api的反馈,下载更新资源,然后使用新的资源启动客户端,或者直接使用新资源不重启客户端。
这种方式可以跳过AppStore的审核,避免了用户频繁下载、安装、覆盖产品包。
我们一般使用这种方式快速修复产品BUG和增加新功能。
我以前的习惯,是在主版本变化的时候需要整包更新,而次版本变化代表逻辑更新,编译版本代表资源更新等等。这些需要自己来定义升级规则。
我们只需要记住这个Updater是使用AssetsManager修改的即可。
在上面SunLightJuly和Henry同学的方法中,使用的是CCHTTPRequest来获取网络资源的。CCHTTPRequest封装了cURL操作。而在Updater中,是直接封装的cURL操作。
在我的设计中,逻辑应该尽量放在lua中,C++部分只提供功能供lua调用。因为lua可以进行热更新,而C++部分则只能整包更新。
从2.1.2版本开始,2dx在libExtensions下添加了一个AssetsManager类用于资源的在线更新和简单的版本管理,同时添加了AssetsManagerTest项目示范了AssetsManager类的用法。


















0 0
原创粉丝点击