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

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

首先我们看一下修改后的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型对象和数组。

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

                  

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值