http://blog.csdn.net/somestill/article/details/9745141
1、VisibleSize和VisibleOrigin
getVisibleSize:表示获得视口(可视区域)的大小,如果DesignResolutionSize跟屏幕尺寸一样大,则getVisibleSize等于getWinSize。
getVisibleOrigin:表示可视区域的起点坐标,这在处理相对位置的时候非常有用,确保节点在不同分辨率下的位置一致。
2、因为在cocos2d里CCNode对象有缩放的方法setScaleX和setScaleY。所以在获取对象大小的时候就必须根据情况明确指定获取对象原始大小,还是缩放后的大小。当然cocos2d里提供了对应的函数来完成这些操作。
getContentSize函数来获得节点原始的大小。只是逻辑尺寸,不是像素
boundingBox函数来获得经过缩放和旋转之后的外框盒大小。
getContentSizeInPixels获得的是像素点大小
3、在精灵初始化时不指定图片,后期在设置
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
CCSprite *grossini = CCSprite::create();
CCSpriteFrame *frame = frameCache->spriteFrameByName("grossini_dance_01.png");
grossini->setDisplayFrame(frame); //给精灵设置一个新的显示帧
类似的添加图片按钮:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
/* 加入关闭按钮-使用图片菜单来实现*/
CCMenuItemImage* closeItemImg = CCMenuItemImage::create();
/* 初始化,先不设置图片*/
closeItemImg->initWithTarget(this, menu_selector(BatchNodeSceneWithCloseBtn::menuCloseCallback));
/* 设置正常图片-使用SpriteFrame对象*/
closeItemImg->setNormalSpriteFrame(cache->spriteFrameByName("CloseNormal.png"));
/* 设置点击状态图片-使用SpriteFrame对象*/
closeItemImg->setSelectedSpriteFrame(cache->spriteFrameByName("CloseSelected.png"));
CCMenu* menu = CCMenu::create(closeItemImg,NULL);
menu->setPosition(ccp(size.width – 50, 50));
this->addChild(menu);
//区别就是,initWithTarget、setNormalSpriteFrame、setSelectedSpriteFrame这几个函数,主要是setNormalSpriteFrame和setSelectedSpriteFrame,SpriteFrame已经存在SpriteFrameCache里了,所以我们可以成功地设置按钮的图片。
当然,如果开始制定了精灵的显示图片,后期也是可以更改显示的图片的,
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
CCTexture2D * tex = CCSprite::create("btn_room_hover.png")->getTexture();
bg->setTexture(tex);
4、场景切换
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
void GameSetting::callbackreturn(CCSprite *sprite)
{
CCScene *returnback=HelloWorld::scene(); //要切换到的场景
CCDirector::sharedDirector()->setDepthTest(true); //开启深度检测
CCTransitionScene *tmpaction=CCTransitionMoveInR::create(1.2,returnback); //切换方法
CCDirector::sharedDirector()->replaceScene(tmpaction);
}
同样,如果在多个layer中间切换,可以把多个layer放到一个CCLayerMultiplex中,同时通过switchTo来进行layer的切换。
5、更改文本标签值
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
CCLabelTTF *ttf=CCLabelTTF::create("%0", "Arial", 12); //创建文本
this->addChild(ttf,1);
而后期,可以通过一下方法改变文本的值
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
char tmp[10];
sprintf(tmp, "%%%d",totalNum*100));
ttf->setString(tmp); //主要是此函数
6、如果是通过CCTableView建立列表的话,数据如果不是固定的话,在创建后如果存在多个CCTableView的切换,这时需要通过
View->reloadData(); //View =CCTableView::create(this,CCSizeMake(960,422));,即创建时的名字,而reloadData为系统函数
来重新加载数据,否则,将导致数据不能时时改变。
另外,可以通过View->setContentOffset(ccp(0, -80 * (idx - 5)));来设置显示的区域(不包括当前已显示窗口的大小,5为当前窗口最多显示的cell个数)。
7、游戏中经常遇到几个层之间互相通信的问题,这就用到了观察者模式,
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
void addObserver(CCObject *target,
SEL_CallFuncO selector,
const char *name,
CCObject *obj);
具体代码如下:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
void A::onEnter() {
CCLayer::onEnter();
CCNotificationCenter::sharedNotificationCenter()->addObserver(
this,
callfuncO_selector(A::func), // 处理的消息的回调函数
kXxxxName, // 感兴趣的消息名称
NULL); // 保存消息中传递的数据
}
可以参考文字cocos2d-x 观察者模式。这样的话如果有消息来得话,就会调用回调函数来处理了。其次,也很重要,要重写onExit()方法,释放掉消息观察者,如果不释放,会发生内存泄露的。
另外,如果值为int型,可以通过以下方式传值:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
CCNotificationCenter::sharedNotificationCenter()->postNotification(GOT_ARENA_CONVT_CHARM,CCInteger::create(0));
接收值:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
CCInteger* ret = (CCInteger*)obj;
CCLog("ret = %d",ret->getValue());
8、设置加载资源的路径,如果有多套ccb文件,针对不同的情况,在文件名完全一样的情况下,就可以通过设置上级目录,从而实现加载不同资源的问题,这样,就需要知道资源的路径。
把资源以目录的形式加入xcode时, 选择”Create folder references for any added folders “, 而不是默认的”Create groups for any added folders “, 加入后,xcode左侧树状结构内显示的图标是蓝色而非黄色。这样,就建立了不同的资源。
获取资源时,在AppDelegate.cpp中可以设置全局资源路径:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
std::vector<std::string> paths;
paths.push_back("zh_CN"); //上层文件夹名称
paths.push_back("en_US"); //上层文件夹名称,根据需要,选择不同的设置
paths.push_back("");
CCFileUtils::sharedFileUtils()->setSearchPaths(paths);
当然,系统自动处理到Resources目录的,所以,只用设置之后的目录即可,需要详细了解,可以看这里。
9、闪屏问题,参见这里。
10、程序中判断是安卓还是IOS
导入文件相关:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "AndroidUtiles.h"
#endif
程序中判断相关:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#else
JNIExitApp();
#endif
11、触摸事件的空间方面
空间方面就是每个触摸点(Touch)对象包含了当前位置信息,以及之前的位置信息(如果有的话),下面的函数是可以获得触摸点之前的位置信息:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
Point getPreviousLocationInView() //UI坐标
Point getPreviousLocation() //OpenGL坐标
下面的函数是可以获得触摸点当前的位置信息。
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
Point getLocationInView() //UI坐标
Point getLocation() //OpenGL坐标
返回触摸事件当前作用的目标节点。
把touch对象中保存的屏幕坐标转换到GL坐标,再转换到目标节点的本地坐标下。
在Node对象中有几个函数可以做坐标转换。convertToNodeSpace方法可以把世界坐标转换到当前node的本地坐标系中;convertToWorldSpace方法可以把基于当前node的本地坐标系下的坐标转换到世界坐标系中;convertTouchToNodeSpace这个函数可以把屏幕坐标系转换到GL坐标系,再转换到父节点的本地坐标下。
计算目标节点的矩形区域。
判断触碰点在不在目标节点的矩形区域内,即判断是否被选中。
根据选择的目标确定炮塔的类型。
判定玩家是否触摸到某炮塔选项的过程可用如下所示的原理图来解释:2
如图:在一个240*360的屏幕内,当玩家触摸屏幕时,触摸对象中会保存下此时的屏幕坐标值(150, 210)。但由于Cocos2d-x中处理坐标一般都使用的是OpenGL坐标,所以这就需要把它转换为(150, 150)的Cocos2d-x坐标值。当我们判定触摸点在不在蓝色的Node内时,可以先计算出这个Node的矩形区域(0, 0, Node宽, Node高),再把触摸点(150, 150)转换到它本地坐标系下。这样就可以直接通过containsPoint方法来判断一个点在不在一个矩形区内了。事例中Node的坐标为(100, 100),所以转换后,触碰点的坐标就变成了(50, 50)。显然地,我们就可以判断点(50,50)在这个大小为(100,100)的矩形中了。PS,相关坐标系详解。
12、较好的按钮显示效果
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
_goMenu4->setScale(0); //_goMenu4 为ccmenuitemImage*类型<span id="transmark"></span>
CCEaseElasticOut* ani_set = CCEaseElasticOut::create(CCScaleTo::create(1.0f, 1.0f), 0.3f);
_goMenu4->runAction(ani_set);
13、CCLabelBMFont字体的使用
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
cocos2d::CCLabelBMFont *_leftTalkInfoBMFont;
char fntName[30] = {0};
sprintf(fntName, "dialog_tw_%d.fnt", (StageModel::sharedStageModel()->getCurStage()->getStageId() + 1)/2);
_leftTalkInfoBMFont->setFntFile(fntName);
_leftTalkInfoBMFont->setString(talkData->getTalkContent()->getCString(), true);
_leftTalkInfoBMFont->setScale(0.35);
_leftTalkInfoBMFont->setWidth(160);
_leftTalkInfoBMFont->setAnchorPoint(ccp(0, 1));
_leftTalkInfoBMFont->updateLabel();
_leftTalkInfoBMFont->setAlignment(kCCTextAlignmentLeft);
_leftTalkInfoBMFont->setLineBreakWithoutSpace(true);