原帖地址:http://bbs.9ria.com/thread-276187-1-1.html

 http://bbs.9ria.com/thread-279133-1-1.html

 

 

本贴是达叔从as3转到2dx的心路历程
对于没有任何C艹基础的人来说,也许会有帮助。建议从头到尾看一遍。里面的问题相信你也能遇到。
会陆续更新。
写不对的欢迎指正。





Ctrl + , (逗号) 是打开某个类 就是FB里的 Ctrl + Shift + R
Ctrl + K ,+ D 是代码格式化 (先按K,再按D)
注释是 Ctrl + K ,+ C
反注释是 Ctrl + K ,+ U
删除整行:Control + L ( FB是Ctrl + D )
格式化整个块:Ctrl+K+F
重命名 shift + alt + R
查看上次阅读处\反上次查看处:Control + "-" \ Control + Shift + "-"   (很长用的快捷键,fb 里的 alt + 左右)
还有以前按住Ctrl 再鼠标点击的东西 现在都是F12
代码提示 Ctrl+J


int billy [5];
int billy [5] = { 16, 2, 77, 40, 12071 };
int billy [] = { 16, 2, 77, 40, 12071 };  // 不写个数也可以
如果我们声明一个全局数组(在所有函数之外),则它的内容将被初始化为所有元素均为0。
char * terry = "hello";

删除
delete pRet;
pRet = NULL;   

if ( pRet && pRet->init() )
{
    这个和as3一样
}

遍历nodeCCArray * pChildrenArray = this->getChildren();  
CCLayer* child = NULL;  
CCObject* pObject = NULL;  

CCARRAY_FOREACH( pChildrenArray, pObject  )
{
    child = (CCLayer*)pObject;  
    if(!child)
    break;  
    //child->dosomething();  
}

for (int i = 0; i < int( arr->count() ); i++)
{
CCLabelTTF* test = (CCLabelTTF*)( arr->objectAtIndex(i) );
test->setPosition( ccp(400,300 + 60 * i) );
CCLog("length::%d" , i );
}

输出int型

CCLog("length::%d" , i );


http://www.ityran.com/archives/2105

在项目上右键添加 -> 类,一次生成cpp 和 h 文件,这是我一个初学者想到的,也是最基本的需求。
但是这样文件的位置无法改变。所以必须用添加项,h 和 cpp 分开添加,然后指定目录。还能更麻烦点吗?

想做socket,看教程,教程里之字没提导包的事,试了半天没有想要的包。后来知道需要的配置下。

加载plist文件

CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("1.plist");
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("2.plist");

CCSprite *sp = CCSprite::createWithSpriteFrameName("test.jpg");

this->addChild(sp);

就这么简单,他会自动管理缓存里的文件。
只要知道名字就行,可恶的是需要知道后缀。
不过他的管理方式已经比as3还简单了。

http://www.cnblogs.com/sambird/archive/2013/07/18/3197562.html

cocos2d-x在使用CCScale9Sprite的时候需要注意,因为使用到了扩展库所以要
在项目属性中的C/C++的附加包含目录中,添加$(SolutionDir)extensions,设置include路径
在连接器的输入中,添加libExtensions.lib,这个库文件位于cocos2d-x编译结果目录中(Debug.win32)
接下来需要在源码中加入相应的代码,首先是添加头文件及名字空间

#include "cocos-ext.h"
USING_NS_CC_EXT;  
交叉编译的时候要注意在Android.mk中要加
$(call import-module,extensions) \
方可编译成功


CCTexture2D *tt2d = CCTextureCache::sharedTextureCache()->addImage("1.png");

CCSpriteBatchNode *qb = CCSpriteBatchNode::createWithTexture(tt2d);
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("1.plist",tt2d);
关于这个管理混乱的问题,可以参看这个文章
http://blog.csdn.net/sdhjob/article/details/8227181 讲的特别详细

想实现这个的话。。。
"ying" + ( int(i / 2) + 1) + ".jpg"  就得这样
char nameStr[100] = {0};
memset( nameStr, 0, sizeof(nameStr) );
sprintf( nameStr,  "fish%d_%d%d.png" ,  13   ,   i / 10  ,  i%10  );

移动的时候会用到的
但是快速移动的时候会有很大延迟,没找到更好的办法。
CCSetIterator iter1 = pTouches->begin();
CCTouch *t1 = (CCTouch*)(*iter1);
iter1++;

ccpSub( getLocation(), getPreviousLocation() );  计算两点距离的宏

移动的话 这么写就行 直接相加 操作符已经重载了
node->setPosition( t1->getDelta() + node->getPosition() );

关于大小的问题。
as3里直接width height
2dx要麻烦些。

http://blog.csdn.net/bill_ming/article/details/9078781  

CCNode类的setPosition,getPosition函数如果是一个Node的Child则获取的坐标就是该Node的本地坐标
另一个关键问题就是在cocos2d-x里就是各种对象的大小问题。
因为在cocos2d-x里CCNode对象有缩放的方法setScaleX和setScaleY。
所以在获取对象大小的时候必须根据情况明确指定获取对象原始大小,还是缩放后的大小。
当然cocos2d-x里提供了对应函数来完成这些操作:

getContentSize 函数来获得节点原始的大小。只是逻辑尺寸,不是像素
boundingBox 函数来获得经过缩放和旋转之后的外框盒大小。
getContentSizeInPixels 获得的是像素点大小

无论是搞2d还是3d开发,最需要搞清楚的就是坐标系,这部分混乱的话就没啥奔头了。
所以玩cocos2d,一上来就先把各种与坐标有关的东西搞清楚。

基本的两个坐标系:屏幕坐标系和GL坐标系。
屏幕坐标系x轴朝右,y轴朝下。默认原点在左上角。这个和as一样。
GL坐标系x轴朝右,y轴朝上。默认原点在左下角。

在调用任何需要设置位置的函数,或从函数获取位置信息前,必须要明确这个函数使用哪个坐标系。

比如调用CCNode类的setPosition函数, 它使用的就是GL坐标系。
比如在处理触摸事件时CCTouch对象中的坐标就是  屏幕坐标系。(左上角的)


另一个重要的坐标系就是和Node相关的本地坐标系。

这个结构和一般做3D用的场景树的概念是一样的。

所以从Node拿到的位置是该节点的本地坐标,需要通过特定的函数才能把本地坐标转换为世界坐标。
而且这里的坐标都用的是GL坐标系。在CCNode对象中有几个方便的函数可以做坐标转换。

convertToWorldSpace方法可以把基于当前node的本地坐标系下的坐标转换到世界坐标系中。
convertToNodeSpace方法可以把世界坐标转换到当前node的本地坐标系中。

另一个关键的问题就是在cocos2d里面就是各种对象的大小问题。
因为在cocos2d里CCNode对象有缩放的方法setScaleX和setScaleY。
所以在获取对象大小的时候就必须根据情况明确指定获取对象原始大小,还是缩放后的大小。
当然cocos2d里提供了对应的函数来完成这些操作。

getContentSize 函数用来获得节点原始的大小。
boundingBox 函数用来获得经过缩放和旋转之后的外框盒大小。

举个简单的例子:
bool ret = CCRect::CCRectContainsPoint(
this->boundingBox() , this->getParent()->convertTouchToNodeSpace( pTouch ));
这个例子的功能是来判定当前的触摸操作是否发生在自己的node对象上。其中pTouch是CCTouch对象的指针,包含了当前触摸事件发生点的坐标。

CCRectContainsPoint这个函数用来判断一个点是否在一个矩形范围内。我们就想用这个函数来判断当前触摸操作的这个点是否在当前node的范围内。
this->boundingBox() 方法获得了当前节点对象在父节点对象下的缩放之后的本地坐标大小,并且是用GL坐标系表示的。

pTouch对象中的坐标是屏幕坐标系,所以必须转换到GL坐标系,再转换到父节点的本地坐标下。
好在convertTouchToNodeSpace这个函数一次完成了这两个转换,可以参考该库的源码,其中有具体的计算过程。

所有数据都转换到同一个坐标系下了以后,就可以通过CCRectContainsPoint函数完成最终的判定操作。

最后想说的一点是,尽可能用相对坐标。换句话说,程序中所有对象在设置大小和位置时,都应该以父对象的大小和位置为依据。
这样程序发布在以各种不同的分辨率发布时,只需要调整根对象的大小就可以了。




比如你的node scale是2
那么点击你的node 坐标是多少?
坐标是未放大的。。。
比如你点的x 200
但给你的是100 明白?

双手缩放

CCSetIterator iter1 = pTouches->begin();//第一个点
CCPoint p1  = ((CCTouch*)(*iter1))->getPreviousLocation(); //getPreviousLocationInView();
CCPoint p11 = ((CCTouch*)(*iter1))->getLocation(); //getLocationInView();
别用注释的那个 y是反的 坐标系很重要
iter1++;
//第二个点
CCPoint p2  = ((CCTouch*)(*iter1))->getPreviousLocation();
CCPoint p22 = ((CCTouch*)(*iter1))->getLocation();

float dis1 = p1.getDistance(p2);  //旧的距离
float dis2 = p11.getDistance(p22);//新的距离

float olds = node->getScale();

//旧的中点
float oldx = ( p1.x + p2.x ) / 2;
float oldy = ( p1.y + p2.y ) / 2;

CCPoint oldp = node->convertToNodeSpace( ccp(oldx,oldy) );

float news = dis2/dis1 * olds;
node->setScale( news );

//新的中点
float newx = ( p11.x + p22.x ) / 2;
float newy = ( p11.y + p22.y ) / 2;

//偏移了多少
//我需要知道 缩放的是 地图里的哪个点
//想让变大后的图的 oldp点 显示在 newWorldP位置上

float ax = -( oldp.x * news - newx );
float ay = -( oldp.y * news - newy );

node->setPosition(ax,ay);

拼接45度角地图时,会出现缝隙 或者拼接小图时也会有缝,咋办?

sb = CCSpriteBatchNode::create("1.png");
1.sb->getTexture()->setAliasTexParameters();
node->addChild(sb);
char *abc = "ca*.png";
CCSprite *t2d = CCSprite::createWithSpriteFrameName(abc);

2.t2d->getTexture()->setAliasTexParameters();

在 1 和 2 任意一个地方设置都可以。 这句话的意思是 设置贴图无锯齿的属性。
不过这个方法设置的图在拖动的时候会有缝隙,比之前的更恶劣。
然后用了这个

修改 ccConfig.h  将
    #define CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 0
    改为
    #define CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 1
这样就完美解决了(至少我们游戏是搞定了)


还有其他方法 请看这  http://blog.csdn.net/yuanhong2910/article/details/7163539


2dx四大缓存区

CCTextureCache; 图片纹理

CCSpriteFrameCache; 精灵
CCAnimationCache; 动画
CCShaderCache; 着色器

Cocos2D-x中的单例如下:
CCDirector, CCTextureCache, CCSpriteFrameCache, CCAnimationCache, CCUserDefault,CCNotificationCenter,CCShaderCache,CCScriptEngineManager,CCFileUtils,SimleAudioEngie。

cocos2d-x中的事件机制
这个和puremvc那个一样。相当好用。

//发送事件
CCNotificationCenter::sharedNotificationCenter()->postNotification(CLICK_TEST_MSG, (CCObject*)data);

//监听事件
void GameManager::initListener()
{
    CCNotificationCenter::sharedNotificationCenter()->
    addObserver( this, callfuncO_selector(GameManager:
nClickTest), CLICK_TEST_MSG, NULL);
}

//处理事件
void GameManager:nClickTest(CCObject* obj)
{
   CCMessageBox("onClickTest", "Title");
  //移除监听事件
   CCNotificationCenter::sharedNotificationCenter()->removeObserver(this, CLICK_TEST_MSG);
}

http://blog.csdn.net/crayondeng/article/details/11677457

为什么用 do while
http://www.cnblogs.com/flying_bat/archive/2008/01/18/1044693.html

如果要用gettimer()
那就在update里 累计加delta

关于定时器:也就是timer
单位都是秒
this->scheduleOnce(schedule_selector(HelloWorld::MutUpdate), 5.0f); 只执行一次  
this->unscheduleAllSelectors(); 停止所有的计时器
this->unscheduleUpdate(); 取消默认的update调用
this->unschedule(schedule_selector(HelloWorld::MutUpdate));  取消自定义的


this->schedule(schedule_selector(HelloWorld::MutUpdate), 1.0f); 1秒执行一次
this->schedule(schedule_selector(HelloWorld::MutUpdate));

this->scheduleUpdate();

void HelloWorld::update( float fDelta )

我不需要知道你有多少帧之动画创建辅助类
http://www.benmutou.com/blog/archives/59

今天遇到的问题 11.25日

声明了一个  CCDictionary *di;  属性




在menu点击事件里死活得不到。。
经过义青老师指导,发现原来是忘记 retain();

以后记住。。数据类型的要retain呀
别忘了释放啊~

最恶心的数据转换
在做数据转换时,最好包含以下头文件

#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
USING_NS_CC;
using namespace std;

在2d-x中,也有一个格式刷:CCString ( 数据转换常常找她做中间人 )
那么我们要转换类型,
可先将起始数据类型刷成CCString然后再转成目的数据类型,
这个方法比较方便且实用。

int 转 CCstring
int num = 5;
CCString* ns = CCString::createWithFormat("%d",num);

CCstring 转 int
int px = ns->intValue();//将CCString 转换为int的方法,转成float类型有 floatValue()

CCString 转  char
const char *string= ns->getCString();

char 转  CCString
CString.Format(”%s”,char *)//char 转cstring
CCString* ns=CCString::createWithFormat("%s",char *);

string 转  char
const char *string = std::string("STRING").c_str();

char 转 string

string s(char *);

string  转 int
std::string s("1234");
int n = std::atoi(s.c_str());//函数原型int atoi(const char *);

int 转 string
int a = 3;
CCString* ns = CCString::createWithFormat("%d",a);
string s = ns->m_sString;

string 转 CCString
std::string str = "123";
CCString* ns = CCString::createWithFormat("%s",str.c_str());

CCString 转 string
std::string s = ns->m_sString;//ns是一个CCString*类型

char 转  int
char *buf = "1122";
int n = std::atoi(buf);

int 转 char
int a = 3;
CCString* ns = CCString::createWithFormat("%d",a);
const char* s = ns->getCString();

看了这么多 我只想说 转你妹夫啊。。。

action的用法
CCScaleTo *scale1 = CCScaleTo::create( 0.1f , 1.2f );
CCScaleTo *scale2 = CCScaleTo::create( 0.1f , 0.8f);
CCScaleTo *scale3 = CCScaleTo::create( 0.1f , 1.1f );
CCScaleTo *scale4 = CCScaleTo::create( 0.1f , 0.9f );
CCScaleTo *scale5 = CCScaleTo::create( 0.1f , 1.0f );
CCFiniteTimeAction* action = CCSequence::create(scale1,scale2,scale3,scale4,scale5,NULL);
bu->runAction(action);

CCScaleTo *scale0 = CCScaleTo::create( 0.2f , 1.2f );CCScaleTo *scale1 = CCScaleTo::create( 0.2f , 1.0f );
CCActionInterval *a1 = CCEaseElasticOut::create(scale0);
CCActionInterval *a2 = CCEaseElasticOut::create(scale1);
CCFiniteTimeAction* action1 = CCSequence::create(a1,a2,NULL);
bu->runAction(action1);

cocos2dx中一个action结束后想正确使用回调函数
CCFiniteTimeAction *actionOne = CCSequence::create(  
    CCScaleTo::create(1.0f,0.5f,1.5f),  
    CCFadeIn::create(1.0f),  
    CCCallFunc::create(this,callfunc_selector(xx::menuSetVisableFalse)),  
    NULL  
);  

11.26日的bug
CCDictionary的setObject 传入的是  const std::string& key
然后我传进去的是char *
用 allKeysForObject 方法往外倒这些key 用std::string 和 char 都接不对。妈蛋的 是我语法不对?来回试了好几次。
进源码一看,返回的数组里存的是CCString.....
妈蛋的 api 你倒是说一声啊 每个方法都让我看源码啊?

关于menu
menu->alignItemsHorizontally();
这个一开始就设置

然后每插入一个对象都要设置这句
menu->alignItemsHorizontallyWithPadding(tabWid);





CCPointZero 这是0,0点 不用你ccp(0,0)了

关于CCTexture2D的问题
starling里的texture 都是独立的 无论你是从纹理集里拿出来的 还是单独的
但,你永远不要高估2dx的作者的设计能力。
他们把CCSpriteFrame和CCSprite里的纹理概念不一样。
CCSpriteFrame里得到的是整个plist里加载的纹理。

所以,你要这样设置

CCSpriteFrame *spriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("ying1.jpg");

CCSprite *s = (CCSprite *)cell->getChildByTag(9001);
s->setDisplayFrame( spriteFrame )
2dx 你也有脸叫自己引擎
好好跟人家starling学学吧

CCControlButton

CCControlButton *btn1 = CCControlButton::create();

CCSpriteFrame *a10 = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("ying2.jpg");


btn1->setBackgroundSpriteFrameForState( CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("ying1.jpg") , CCControlStateNormal );


btn1->setBackgroundSpriteFrameForState( CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("ying2.jpg") , CCControlStateHighlighted );


this->addChild(btn1);
btn1->setPosition(ccp(300,300));
btn1->setPreferredSize( a10->getOriginalSizeInPixels() );
btn1->addTargetWithActionForControlEvents(this,cccontrol_selector(MoneyPanel::click1),CCControlEventTouchUpInside);

void MoneyPanel::click1(CCObject* pSender, CCControlEvent event)
{
    CCLog("aaaaaaaaaaaa");
}


触摸的封装
cocos2dx的封装和as3完全不是一个级别的。
所以最好自己封装一下。
http://mayingchen003.blog.163.com/blog/static/1626818420138442507/
这个没测试过


有时你想用组件,必须导入类库。
方法就在这
http://blog.csdn.net/pomme_qixiaohu/article/details/8838162
初学者容易绊在这里

addChild 方法的坑
里面介绍的明白。
Adds a child to the container with z-order as 0.
不像as3一样加到最后面,而是加到最前面。。。
而且 你把他加到一个现实列表里 再加到另一个里会报错 因为他不会自动移除 一点不智能

遇到这个报错时。。
一定是类名 或者 命名空间名
就是没导入.h文件顺便说一句,头文件只需要在.h里include一遍就可以了

单例的写法


h里
static MoneyPanel* getInstance();

cpp里

static MoneyPanel* instance;
MoneyPanel* MoneyPanel::getInstance()
{
    if( instance == NULL )
    {
        instance = MoneyPanel::create();
    }
    return instance;
}
static是用::访问的 包括静态变量

关于全局静态变量的区别
在h里写静态变量是不行的
static bool aaa;
这样会报错 得用其他方法 暂时没看见 乖乖用方法吧

今天遇到一个问题

d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.h(7): error C2011: “MoneyPanel”:“class”类型重定义
1>          d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.h(7) : 参见“MoneyPanel”的声明
1>d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.cpp(24): error C2027: 使用了未定义类型“MoneyPanel”
1>          d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.h(7) : 参见“MoneyPanel”的声明
1>d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.cpp(24): error C2062: 意外的类型“void”
1>d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.cpp(25): error C2143: 语法错误 : 缺少“;”(在“{”的前面)
1>d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.cpp(25): error C2447: “{”: 缺少函数标题(是否是老式的形式表?)
1>d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.cpp(237): error C2027: 使用了未定义类型“MoneyPanel”
1>          d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.h(7) : 参见“MoneyPanel”的声明
1>d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.cpp(241): error C2027: 使用了未定义类型“MoneyPanel”
1>          d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.h(7) : 参见“MoneyPanel”的声明

1>d:\cocos2d-x-2.2\projects\farmgame\classes\moneypanel.cpp(241): error C3861: “create”: 找不到标识符

百思不得其解
后来查出来是因为没加   #pragma once
我戳~~

局部变量如果是new出来的 需要delete吗?他占用的内存会在方法结束时释放吗?
答案是必须delete ,内存不会自动释放
具体看这个
http://bbs.csdn.net/topics/10426927

返回局部new的对象怎么样呢?答案是最好不要~请看
不要返回局部变量的引用,也不要返回new生成的对象的引用
http://blog.sina.com.cn/s/blog_40965d3a0101eaiq.html

所以2dx的create方法得到的数据能够返回还是很不错的

char*  和 char[ ] 有什么区别?
http://blog.csdn.net/yahohi/article/details/7427724

char *c1 = "abc";  实际上先是在文字常量区分配了一块内存放"abc",然后在栈上分配一地址给c1并指向

这块地址,然后改变常量"abc"自然会崩溃
然而char c2[] = "abc",实际上abc分配内存的地方和上者并不一样

一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于

数据结构中的栈。
2、堆区(heap)— 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据

结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态

变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统
释放。
4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放。
5、程序代码区

printf,sprintf,vsprintf 区别?
http://blog.csdn.net/anye3000/article/details/6593551

函数指针

void (*p[10])(void(*)());//我了个去,谁能告诉我这句话什么意思?

正解:*p[10]是一个指针数组,数组中的指针指向的是一些函数,这些函数参数为void(*)(),返回值为空。参数部分的void(*)()是一个指向无参数,返回值为空的函数的函数指针。

上面的声明可以分步完成:
首先,声明一个无参数,返回值为空的函数指针
typedef void (*pfv)();

接着,声明一个函数指针,该函数指针指向一个参数为pfv,返回值为空的函数指针
typedef void (*pFunc_taking_pfv)(pfv);

最后,声明一个含有10个这样的函数指针的数组
pFunc_taking_pfv arrayFunc[10];

C/C++之回调函数
http://www.cnblogs.com/chenyuming507950417/archive/2012/01/02/2310114.html

指针函数与函数指针的区别
http://www.cnblogs.com/gmh915/archive/2010/06/11/1756067.html


typedef 的 define 区别
http://www.cnblogs.com/kerwinshaw/archive/2009/02/02/1382428.html

说下define的特殊用法,他还可以这么用,里面可以传参数
#define max(x,y) (x)>(y)?(x)y);
具体看这个
http://blog.163.com/wk_technology/blog/static/13078835920091158041771/
http://blog.csdn.net/sanmaofly/article/details/4164308

typedef void (CCObject::*SEL_CallFunc)(); //声明一个函数指针 SEL_CallFunc就是指向函数的指针 他两边的圆括号是必须的
这个东西就相当于int a 里的int 一旦需要你就要写一遍那么长的玩意儿 太麻烦 所以用typedef给他简化下
所以以后直接用SEL_CallFunc来表示这个指针


#define callfunc_selector(_SELECTOR) (SEL_CallFunc)(&_SELECTOR)

SEL_CallFunc action;
CCObject *target;
void Tabnavigator::setTabChangeFun( CCObject *_target , SEL_CallFunc action_ )
{
    target = _target;//这个是监听方法
    action = action_;
}

(target->*action)(); //这个是调用

tab->setTabChangeFun( this  ,  callfunc_selector( MoneyPanel::tabChangeFun )  ); //这个就是监听了



所以 2dx里的函数回调展开其实是这样的
当你传入的时候 其实是
tab->setTabChangeFun(this, callfunc_selector(MoneyPanel::tabChangeFun) );
( SEL_CallFunc ) ( &MoneyPanel::tabChangeFun )

函数指针怎么用呢?
一般来说是这样
char (*pFun)(int);



char glFun(int a){ return;}
void main()
{
    pFun = glFun;
    (*pFun)(2);
}


先声明一个 空着扔那儿就行了,然后给他赋值调用。搞定!


如果你重写了父类的方法 那么必须调用一下

今天就发生了一个超级诡异的玩意儿

void Tabnavigator:
nEnter()
{
    CCNode:nEnter();
}

一开始没写CCNode的onEnter ,结果鼠标事件消失了。。  

今天的bug 12.12
新建了一个类,vs提示 构造函数不能有返回类型
找了半天才发现,头文件的最后没加分号。。
class Cangku : public cocos2d::CCNode
{
};  

装插件的话,写起来比较简单,开头class 后面的都帮你搞定

筛选器和文件夹的区别
筛选器只是看起来放到里面了,其实他还在原来的位置。
所以include的时候不要看错(include需要包含文件夹),或者自己手动创建文件夹。
创建筛选器之后,要注意工程目录下的“*.filters”文件一定不能删掉,因为这个文件就是用来记录筛选器的。
这个和fb不一样。


关于筛选器看这个
http://www.zhuyanfeng.com/archives/1692

 #include到底该写在哪
http://blog.csdn.net/cppyin/article/details/6121010


=============================================================

as关键字在哪里?
比如你想强转一个类型 那么用这个方法 ItemModel是目标类型

static_cast<ItemModel*>(abc);

全局变量 与  静态全局变量

全局变量的作用域不仅在本文件中可以使用,在其他文件中也可以使用. 但静态全局变量只能在本文件中使用.
float minScale = 0.5; //  在头文件的public里写 就是数据成员 ,其他地方(.h .cpp都算)就是全局变量,不过放到cpp里好像其他类看不到。
数据成员那儿 是不允许直接初始化的。(一般aser的话都写public里好了)

一般定义static 全局变量时,都把它放在.cpp文件中而不是.h文件中,这样就不会给其他编译单元造成不必要的信息污染。


static int s_val=2; // 这个就是静态全局变量
具体看这儿吧
http://blog.csdn.net/windhaunting/article/details/5364309

hhttp://blog.csdn.net/candyliuxj/article/details/7853938
http://baike.baidu.com/link?url=2KlV7z9OhsNPofulO3kF3h-wzApZ4vahAc0JoS2MLYM87MQjrsDUsvnRARW0BZBx
http://wrchen.blog.sohu.com/71617539.html



声明了一个指针数据成员,没有初始化。默认竟然不是NULL
所以如果你想用 == NULL 来段判断最好自己初始化一下!这点和as不一样!

析构函数会自动把你的数据成员释放吗?
看了眼cccontrolbutton的析构
CCControlButton::~CCControlButton()
{
    CC_SAFE_RELEASE(m_currentTitle);
    CC_SAFE_RELEASE(m_titleLabel);
    CC_SAFE_RELEASE(m_backgroundSpriteDispatchTable);
    CC_SAFE_RELEASE(m_titleLabelDispatchTable);
    CC_SAFE_RELEASE(m_titleColorDispatchTable);
    CC_SAFE_RELEASE(m_titleDispatchTable);
    CC_SAFE_RELEASE(m_backgroundSprite);
}
你明白了吧 得自己释放。

一些陌生的关键字
http://www.cnblogs.com/fanzhidongyzby/archive/2012/11/07/2759326.html


如何判断一个类的类型?对应AS的 is
typeid(int).name();  //获取int类型名,结果为“int”。
typeid(1)!= typeid(1.0);  //比较表达式类型,结果为true。

堆栈的一些解释
http://www.cnblogs.com/chuncn/archive/2011/04/12/2014273.html
;

两个头文件不能互相引用。不然会报错,不过可以把.h写入到cpp里,这样就不会报了。(也许还有其他解决办法,我没想到)

A B在一个容器里 如果容器调用了 removeAllChildren
那么 A B 再 removeAllChildren 就报错。

注册触摸不是什么时候都可以的,具体请看这个。在触摸事件回调里是注册不上的。这个要注意!
http://blog.csdn.net/xiadasong007/article/details/8057741


现在有个需求,上面是CCTableView ,下面是一个CCScrollView , 现在要求滑动table 而下面的scroll不滑动。
那么就要求table的触摸可以吞噬。可他注册的时候是flase,所以我们要改一下。
下面是更改的顺序,记住写的地方不能错,因为注册监听和得到touchhandler有顺序问题。
void ItemList:nEnter()
{
    CCLayer:nEnter();
    //cclayer注册监听是在enter里 所以要写这 不然得不到hander
    CCTouchHandler *ct = CCDirector::sharedDirector()->getTouchDispatcher()->findHandler(tableView);
    CCTargetedTouchHandler *ctt =  dynamic_cast<CCTargetedTouchHandler*>(ct);
    ctt->setSwallowsTouches(true);
}


关于触摸的详细说明在这里
http://hi.baidu.com/mefeng47/item/ab7409d530912f3ee3108fd3

因为失误,行尾点了其他选项造成报错。
记得要选windows的呀


具体看这个
http://blog.csdn.net/njnu_mjn/article/details/7853337

新的初始化方式
CCLayer::CCLayer()
: m_bTouchEnabled(false)
, m_bAccelerometerEnabled(false)
, m_bKeypadEnabled(false)
, m_pScriptTouchHandlerEntry(NULL)
, m_pScriptKeypadHandlerEntry(NULL)
, m_pScriptAccelerateHandlerEntry(NULL)
, m_nTouchPriority(0)
, m_eTouchMode(kCCTouchesAllAtOnce)
{
    m_bIgnoreAnchorPointForPosition = true;
    setAnchorPoint(ccp(0.5f, 0.5f));
}

两句话拼字符串
CCString* str = CCString::createWithFormat("aaa %d / %d aaa",now,max);
allnum->setString( str->getCString() );

cocos2d-x游戏iphone移植到android需要注意事项
1.在android.mk中添加源文件(cpp文件)的时候 中间不能有空格
2.如果游戏使用到了物理引擎box2d的话 那么源文件对的引用应为:#include "Box2D/Box2D.h"  而不是  #include "Box2D.h"
3.在使用cocos2d-x引擎开发的时候 对头文件的包含尽可能地使用全路径包含 因为android有可能会找不到默认的包含路径
4.创建一个指针变量的时候 不要初始化为NULL;CCLayer layer;可以  CCLayer layer=NULL;不可以
5.使用c++库文件的时候要使用标准的头引用 如:#include <vector.h> 应写为#include <vector>

1.使用char * 去接收一个char[]数组   当读到'\0'的时候 会自动结束,所以 不要使用char* 去获取一个char数组
2.不要拿char* str与 ""比较  一个是指针 一个是常量    std::string(str)可以与""比较

关于“using namespace std”
http://www.cnblogs.com/uniqueliu/archive/2011/07/10/2102238.html

以前如果要写一个面板,大概要写好几个类,有的类里内容很少。这样下来,类显的特别多。
不过c++有一个好处,一个h文件里可以有许多的类。这样我们可以把一个系统的类写在一起。
不过。今天遇到了问题。一个类死活报错。
最后发现,编译一个文件里的class文件是有顺序问题的。
上面的类看不到下面的类。以后注意点吧

关于CCLabelAtlas
CCTexture2D* tt = CCTextureCache::sharedTextureCache()->textureForKey("111.png");
CCLabelAtlas* jinbila =  new CCLabelAtlas();
jinbila->autorelease();
jinbila->initWithString( "000000000", tt, 12, 32, '.' );
return jinbila;
000000000的意思是限制你的长度。。。写几个就是几个。
万万没想到啊

CCSprite 里 也能添加东西。。之前一直把他当bitmap使用,二了。忘记他是继承自ccnode了
所以ccspritebatchnode可以用他,不过如果继承他的话,不能在构造方法里写init的东西,所以重写init吧~~

然后看看这么几个东西

char*,const char*和string的相互转换

1. string 转 const char*
   char * ch = const_cast<char*>(str.c_str())   

   或
   string s = "abc";

   const char* c_s = s.c_str();


2. const char* 转 string

   直接赋值即可

   const char* c_s = "abc";

   string s(c_s);

3. string 转 char*

   string s = "abc";

   char* c;

   const int len = s.length();

   c = new char[len+1];

   strcpy(c,s.c_str());


4. char* 转 string

   char* c = "abc";

   string s(c);


5. const char* 转 char*

   const char* cpc = "abc";

   char* pc = new char[100];//足够长 用size的话就+1 比如这样

   strcpy(pc,cpc);

   const char* p_w_picpathname = Json_getItemAt(c1,1)->valuestring;

   cell1->p_w_picpathName = new char[ strlen( p_w_picpathname ) + 1 ];

   strcpy( cell1->p_w_picpathName , p_w_picpathname );

6. char* 转 const char*

   直接赋值即可

   char* pc = "abc";

 const char* cpc = pc;

const char*, char const*, char*const的区别问题几乎是C++面试中每次都会有的题目。

http://blog.csdn.net/yingxunren/article/details/3968800

http://goodidea.blog.51cto.com/639065/126526


char *const p;  与  const char * p;  的区别

前者定义P为常量,即只能单向赋值一次,P++展开为p=p+1,重复赋值给常量,出错,后者P为地址变量,地址变量是指向该变量的存储地址值如:4B3F6A,不能赋给一个字符值(字符相当于ascii表中对应的整数)如强制赋值,会把原地址变量P变为一个两位数的整数,造成地址指针溢出。而p++,则表示把该地址变量向下一个存储单元移动一位,如4B3F6A到4B3F6B.所以合法。

char* 和char[]的区别
http://blog.csdn.net/yahohi/article/details/7427724

strcpy和memcpy的区别
http://www.cnblogs.com/stoneJin/archive/2011/09/16/2179248.html

C语言中memset函数详解
http://blog.sina.com.cn/s/blog_715d0ae30100yj2d.html

new char[10] 和 char[10] 的区别char * charSequence = new char[10];
char szChar[10];
的区别??
http://blog.163.com/tongfangyuan0000@126/blog/static/430418552009123101445131/注意前者默认的是字符串,后者是字符数组,二者有本质的区别,不过这对于字符串之间的比较等不影响的。

char的拼接 strcat  原型:extern char *strcat(char *dest,char *src);
  用法:#include <string.h>
  功能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。
  说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
  返回指向dest的指针。
  举例:
  // strcat.c
  #include <syslib.h>
  #include <string.h>
  main()
  {
      char d[20]="Golden Global";
      char *s=" View";
      clrscr();
      strcat(d,s);
      printf("%s",d);
      getchar();
      return 0;
  }
  程序执行结果为:
  Golden Global View

const char *p = "123";

p[1] = '3'; // 会报错
p = "456"; // 不会报错

const char * 只是说指针指向的内容不可变,但指针本身可以再赋值

假设你的程序是
char * findArg(char *s)
{
    return s;
}

这个时候,你如果传const char *进去,那么好一些的编译器,会知道,你传回的函数返回值,也是const char *,也就是指针指向的内容不可写。

所以如果你传进去的是const char *,最好还是把 char *name写成const char *name,因为char *name可以对指针指向的内容进行修改。

如何给char* 的类属性赋值
之前总以为char*不初始化 然后用一个赋值就可以
这个思路在c++里不对
应该在构造方法里把char* 初始化为 new char[20]; 个数自己定
然后再写入进去
比如可以用
memset( cell1->p_w_picpathName,0,sizeof(cell1->p_w_picpathName) );
sprintf( cell1->p_w_picpathName , "%s%s" , p_w_picpathname , ".png" );


map 经验谈
map 里不能放 char* (也可以放,不过要改一些东西)
最好用string (不过有说这个效率差)
之前是用一个单例存储map,当时没用指针,是用的对象。
结果出了一个大问题。在一个方法体里把这个对象引用出来,然后设置key value,结果他只给临时变量里存了key value
单例里的没存,貌似他在方法内拷贝了一个临时的。
然后把单例的那个变量设置为指针。
vs通过
xcode报错。。妈蛋
xcode不希望指针 解指针 再赋值 比如这样 (*map)[a] = 1; insert也不行!!!!妈蛋!!
所以还得改回对象。。。各位看明白了么?


map



C++map的基本操作和使用  
1、map简介

map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key。

2、map的功能
自动建立Key - value的对应。key 和 value可以是任意你需要的类型。
根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记录,最多查找20次。
快速插入Key - Value 记录。
快速删除记录
根据Key 修改value记录。
遍历所有记录。

3、使用map
使用map得包含map类所在的头文件
#include <map> //注意,STL头文件没有扩展名.h
map对象是模板类,需要关键字和存储对象两个模板参数:
std:map<int, string> personnel;
这样就定义了一个用int作为索引,并拥有相关联的指向string的指针.
为了使用方便,可以对模板类进行一下类型定义,
typedef map<int, CString> UDT_MAP_INT_CSTRING;
UDT_MAP_INT_CSTRING enumMap;

4、在map中插入元素
改变map中的条目非常简单,因为map类已经对[]操作符进行了重载
enumMap[1] = "One";
enumMap[2] = "Two";
.....

这样非常直观,但存在一个性能的问题。插入2时,先在enumMap中查找主键为2的项,没发现,然后将一个新的对象插入enumMap,键是2,值是一个空字符串,插入完成后,将字符串赋为"Two";

该方法会将每个值都赋为缺省值,然后再赋为显示的值,
如果元素是类对象,则开销比较大。
我们可以用以下方法来避免开销:

enumMap.insert( map<int, CString> :: value_type(2, "Two")  );

5、查找并获取map中的元素
下标操作符给出了获得一个值的最简单方法:

CString tmp = enumMap[2];

但是,只有当map中有这个键的实例时才对, 否则会自动插入一个实例,值为初始化值。
我们可以使用Find()和Count()方法来发现一个键是否存在。

查找map中是否包含某个关键字条目用find()方法,传入的参数是要查找的key,在这里需要提到的是begin()和end()两个成员,
分别代表map对象中第一个条目和最后一个条目,这两个数据的类型是iterator.

int nFindKey = 2; //要查找的Key

//定义一个条目变量(实际是指针)

UDT_MAP_INT_CSTRING::iterator it = enumMap.find(nFindKey);

if( it == enumMap.end() )
{
    //没找到
}
else
{
    //找到
}

通过map对象的方法获取的iterator数据类型是一个std::pair对象,包括两个数据 iterator->first 和 iterator->second 分别代表关键字和存储的数据

6、从map中删除元素

移除某个map中某个条目用erase()
该成员方法的定义如下

iterator erase(iterator it); //通过一个条目对象删除
iterator erase(iterator first, iterator last); //删除一个范围
size_type erase(const Key& key); //通过关键字删除
clear()就相当于 enumMap.erase(enumMap.begin(), enumMap.end());

C++ STLmap的使用

以下是对C++中STLmap的插入,查找,遍历及删除的例子:
http://blog.csdn.net/mjshldcsd/article/details/7206901