改写《魔塔》前篇03:点击按钮控制人物行走

来源:互联网 发布:淘宝手机排名怎么靠前 编辑:程序博客网 时间:2024/06/04 17:44

这篇文章的代码与原书的代码会有一些不同的地方,因为我按照原书的方法进行编写后,运行会有内存访问冲突之类的错误。所以我进行了一些修改,在修改的地方我会进行指明。

首先我们看一下修改后的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 instancebool 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设置tagdown->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, heightCCSpriteFrame* 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型对象和数组。

运行,我们点击屏幕中央的四个按钮,勇士会向对应的方向行走,但只能原地打转,如图所示:

                  

原创粉丝点击