这篇文章的代码与原书的代码会有一些不同的地方,因为我按照原书的方法进行编写后,运行会有内存访问冲突之类的错误。所以我进行了一些修改,在修改的地方我会进行指明。
首先我们看一下修改后的HelloWorldScene.h文件。我们定义了一些变量和方法。
#include "cocos2d.h"
#include "SimpleAudioEngine.h"
using namespace cocos2d;
typedef enum {
kDown = 0,
kLeft = 1,
kRight= 2,
kUp = 3,
} HeroDirection;
class HelloWorld : public cocos2d::CCLayer
{
public:
HelloWorld();
~HelloWorld();
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// there's no 'id' in cpp, so we recommand to return the exactly class pointer
static cocos2d::CCScene* scene();
// a selector callback
void menuCloseCallback(CCObject* pSender);
// implement the "static node()" method manually
CREATE_FUNC(HelloWorld);
//地图
CCTMXTiledMap *map;
//主角
CCSprite* heroSprite;
//主角的方向
HeroDirection heroDirection;
//数组保存勇士向四个方向行走的动画模板(这是一个双重指针,指向一维数组的首元素的地址)
CCAnimation** walkAnimation;
//用来保存精灵帧的数组
CCArray* animFrames;
//根据按钮Tag创建不同方向的动画
CCAnimation *animation;
//创建动画的方法
CCAnimation* createAnimationByDirection(HeroDirection direction);
//点击按钮的回调方法
void menuCallBackMove(CCObject* pSender);
//在动画结束后设置主角方向
void setFaceDirection(HeroDirection direction);
//播放动画结束后的回调方法
void onWalkDone(CCNode* pTarget, void* data);
};
然后我们看一下HelloWorldScene.cpp文件修改后的内容。我们分离出了一些方法,用于实现不同的功能。
#include "HelloWorldScene.h"
using namespace cocos2d;
HelloWorld::HelloWorld()
{
}
//析构函数,用于释放new出来的CCAnimation*数组
HelloWorld::~HelloWorld(void)
{
for (int i = 0; i < 4; i++)
{
//释放数组中元素
CC_SAFE_RELEASE(walkAnimation[i]);
}
//释放数组本身
CC_SAFE_DELETE_ARRAY(walkAnimation);
}
CCScene* HelloWorld::scene()
{
CCScene * scene = NULL;
do
{
// 'scene' is an autorelease object
scene = CCScene::create();
CC_BREAK_IF(! scene);
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
CC_BREAK_IF(! layer);
// add layer as a child to scene
scene->addChild(layer);
} while (0);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
bool bRet = false;
do
{
CC_BREAK_IF(! CCLayer::init());
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback));
CC_BREAK_IF(! pCloseItem);
// Place the menu item bottom-right conner.
pCloseItem->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20));
// Create a menu with the "close" menu item, it's an auto release object.
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
CC_BREAK_IF(! pMenu);
// Add the menu to HelloWorld layer as a child layer.
this->addChild(pMenu, 1);
//解析tmx地图
map=CCTMXTiledMap::create("0.tmx");
addChild(map);
//创建四个方向的行走动画
walkAnimation =new CCAnimation*[4];
walkAnimation[kLeft] = this->createAnimationByDirection(kLeft);
walkAnimation[kRight] = this->createAnimationByDirection(kRight);
walkAnimation[kUp] = this->createAnimationByDirection(kUp);
walkAnimation[kDown] = this->createAnimationByDirection(kDown);
//用frame0作为勇士的静态图(这里与原文有不同之处)
heroSprite = CCSprite::createWithSpriteFrame((CCSpriteFrame*)animFrames->objectAtIndex(0));
heroSprite->setPosition(ccp(48,48));
addChild(heroSprite);
//添加四个按钮
CCMenuItem *down = CCMenuItemFont::create("down", this, menu_selector(HelloWorld::menuCallBackMove));
CCMenuItem *left = CCMenuItemFont::create("left", this, menu_selector(HelloWorld::menuCallBackMove) );
CCMenuItem *right = CCMenuItemFont::create("right", this, menu_selector(HelloWorld::menuCallBackMove) );
CCMenuItem *up = CCMenuItemFont::create("up", this, menu_selector(HelloWorld::menuCallBackMove) );
CCMenu* menu = CCMenu::create(down, left, right, up, NULL);
//为了方便查找,给每个menuItem设置tag
down->setTag(kDown);
left->setTag(kLeft);
right->setTag(kRight);
up->setTag(kUp);
//菜单项按间距50水平排列
menu->alignItemsHorizontallyWithPadding(50);
addChild(menu);
bRet = true;
} while (0);
return bRet;
}
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
// "close" menu item clicked
CCDirector::sharedDirector()->end();
}
CCAnimation* HelloWorld::createAnimationByDirection(HeroDirection direction)
{
//将图片生成纹理,保存到全局的纹理缓冲区
CCTexture2D *heroTexture=CCTextureCache::sharedTextureCache()->addImage("hero.png");
//第二个参数表示显示区域的x, y, width, height
CCSpriteFrame* frame0=CCSpriteFrame::createWithTexture(heroTexture,CCRectMake(32*0,32*direction,32,32));
CCSpriteFrame* frame1=CCSpriteFrame::createWithTexture(heroTexture,CCRectMake(32*1,32*direction,32,32));
CCSpriteFrame* frame2=CCSpriteFrame::createWithTexture(heroTexture,CCRectMake(32*2,32*direction,32,32));
CCSpriteFrame* frame3=CCSpriteFrame::createWithTexture(heroTexture,CCRectMake(32*3,32*direction,32,32));
//在2.0版本以后,CCMutableArray取消了
animFrames=CCArray::createWithCapacity(4);
//将创建的四个纹理保存到数组中
animFrames->addObject(frame0);
animFrames->addObject(frame1);
animFrames->addObject(frame2);
animFrames->addObject(frame3);
//创建一个动画,0.2f表示间隔时间
animation = CCAnimation::createWithSpriteFrames(animFrames, 0.2f);
//若不retain()则会出现错误
animation->retain();
return animation;
}
void HelloWorld::menuCallBackMove(CCObject* pSender)
{
CCNode *node = (CCNode *) pSender;
//按钮的tag就是需要行走的方向
int targetDirection = node->getTag();
CCAction *action = CCSequence::create(
CCAnimate::create(walkAnimation[targetDirection]),
//把方向信息传递给onWalkDone方法
CCCallFuncND::create(this, callfuncND_selector(HelloWorld::onWalkDone), (void*)targetDirection),
NULL);
//主角执行动作
heroSprite->runAction(action);
}
void HelloWorld::setFaceDirection(HeroDirection direction)
{
//设置主角的静态画面
heroSprite->setTextureRect(CCRectMake(0,32*direction,32,32));
}
void HelloWorld::onWalkDone(CCNode* pTarget, void* data)
{
//将void*先转换为int,再从int转换到枚举类型
int direction = (int) data;
setFaceDirection((HeroDirection)direction);
}
注意,我们添加了构造函数和析构函数,在析构函数里销毁我们new出来的CCAnimation*数组。这里用到了两个宏(CC_SAFE_RELEASE和CC_SAFE_DELETE_ARRAY),可以方便的释放CCObject型对象和数组。
运行,我们点击屏幕中央的四个按钮,勇士会向对应的方向行走,但只能原地打转,如图所示: