学习:cocos2d-x手机游戏开发(四)简单实现人物移动代码,cocos2d-2.1beta3-x-2.1.1 vs2010

HelloWorldScene.h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

#include "SimpleAudioEngine.h"

class HelloWorld : public cocos2d::CCLayer
{
public:
    virtual bool init();  

 
    static cocos2d::CCScene* scene();
    

    void menuCloseCallback(CCObject* pSender);

    // implement the "static node()" method manually
    CREATE_FUNC(HelloWorld);
    virtual ~HelloWorld();  
    cocos2d::CCTMXTiledMap *map;
    cocos2d::CCAnimation *walkAnimations[4];
    cocos2d::CCSprite *heroSprite;
    typedef enum{
        kDown,
        kLeft,
        kRight,
        kUp,
        kTotal
    }HeroDirection;
    cocos2d::CCAnimation *createAnimationByDirection(HeroDirection direction);
       
    void menuCallbackMove(CCObject *pSender);          
     
    void setFaceDirection(HeroDirection direction);          
         
    void onWalkDone(CCNode *pTarget, void *data);              
         
    bool isHeroWalking;          
          
    cocos2d::CCPoint positionForTileCoord(cocos2d::CCPoint tileCoord);          
          
    void setSceneScrollPosition(cocos2d::CCPoint position);          
          
    void update(float dt);          
         
    cocos2d::CCPoint tilecoordForPosition(cocos2d::CCPoint position);          
          
    typedef enum{
        kNone,          
        kWall,          
        kEnemy,
    }CollisionType;          
          
    CollisionType checkCollision(cocos2d::CCPoint heroPosition); 

};

#endif  // __HELLOWORLD_SCENE_H__

HelloWorldScene.cpp

#include "HelloWorldScene.h"

using namespace cocos2d;

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 
    {
        //////////////////////////////////////////////////////////////////////////
        // super init first
        //////////////////////////////////////////////////////////////////////////

        CC_BREAK_IF(! CCLayer::init());

        //////////////////////////////////////////////////////////////////////////
        // add your codes below...
        //////////////////////////////////////////////////////////////////////////

        // 1. Add a menu item with "X" image, which is clicked to quit the program.

        // Create a "close" menu item with close icon, it's an auto release object.
        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");//CCTMXTiledMap::tiledMapWithTMXFile("0.tmx");          
        this->addChild(map);              
        for (int i=0; i<kTotal; i++)
        {
            walkAnimations[i] = createAnimationByDirection((HeroDirection)i);      
        }
        //创建勇士,用第一帧作为勇士的静态图 
        
        
        heroSprite =CCSprite::createWithSpriteFrame(((CCAnimationFrame*)(walkAnimations[kDown]->getFrames()->objectAtIndex(0)))->getSpriteFrame());          
        heroSprite->setAnchorPoint(CCPointZero);          
        heroSprite->setPosition(positionForTileCoord(ccp(7, 0)));          
        this->addChild(heroSprite);              
        //加入4个行走方向的控制菜单          
        CCMenuItem *down = CCMenuItemFont::create("down", this, menu_selector(HelloWorld::menuCallbackMove));
            //CCMenuItemFont::create("down", this, menu_selector(HelloWorld::menuCallbackMove));
            //CCMenuItemFont::itemWithString("down", this, menu_selector(HelloWorld::menuCallbackMove));          
        CCMenuItem *left = CCMenuItemFont::create("left", this, menu_selector(HelloWorld::menuCallbackMove));
            //CCMenuItemFont::itemWithString("left", this, menu_selector(HelloWorld::menuCallbackMove));          
        CCMenuItem *right = CCMenuItemFont::create("right", this, menu_selector(HelloWorld::menuCallbackMove));
            //CCMenuItemFont::itemWithString("right", this, menu_selector(HelloWorld::menuCallbackMove));          
        CCMenuItem *up = CCMenuItemFont::create("up", this, menu_selector(HelloWorld::menuCallbackMove));
            //CCMenuItemFont::itemWithString("up", this, menu_selector(HelloWorld::menuCallbackMove));          
        CCMenu *menu =CCMenu::create(down,left,right,up,NULL);
            //CCMenu::menuWithItems(down, left, right, up, NULL);             
        //为了方便查找给菜单项添加tag          
        down->setTag(kDown);          
        left->setTag(kLeft);          
        right->setTag(kRight);          
        up->setTag(kUp);              
        //菜单项水平排列          
        menu->alignItemsHorizontallyWithPadding(30);          
        this->addChild(menu);             
        //启动定时器          
        this->schedule(schedule_selector(HelloWorld::update));  
        this->isHeroWalking = false;
        bRet = true;
    } while (0);

    return bRet;
}

void HelloWorld::menuCloseCallback(CCObject* pSender)
{
    // "close" menu item clicked
    CCDirector::sharedDirector()->end();
}
/************************************************************************          
设置行走方向  
*********************************************[2013年1月24日 12:04:13]***/
CCAnimation *HelloWorld::createAnimationByDirection(HeroDirection direction)  
{      
    //将图片生成纹理,保存到全局的纹理缓冲区      
    CCTexture2D *heroTexture = CCTextureCache::sharedTextureCache()->addImage("hero.png");              
    //用纹理创建4帧动画      
    CCArray *animFrames = new CCArray[4];      
    for (int i=0; i<4; i++)      
    {          
        CCSpriteFrame *fream = CCSpriteFrame::createWithTexture(heroTexture,CCRectMake(32*i, 32*direction, 32, 32));
            //CCSpriteFrame::frameWithTexture(heroTexture, CCRectMake(32*i, 32*direction, 32, 32));          
        animFrames->addObject(fream);      
    }      
    // 用4个动画帧生成CCAnimation对象(动画模板),其中0.2f是每帧之间的时间间隔      
    CCAnimation *animation = new CCAnimation();      
    animation->initWithSpriteFrames(animFrames, 0.2f);      
    return animation;  
}      
/************************************************************************          
设置行走方向变化的回调函数  
*********************************************[2013年1月24日 12:04:13]***/    
void HelloWorld::menuCallbackMove(CCObject *pSender)  
{      
    //如果勇士正在移动,不接受指令      
    if (this->isHeroWalking)          
        return;              
    CCNode *node = (CCNode*)pSender;      
    //按钮的tag就是需要走的方向      
    HeroDirection tag = (HeroDirection)node->getTag();      
    //根据方向计算移动的距离      
    CCPoint moveByPosition;      
    switch(tag)      
    {      
    case kDown:          
        moveByPosition = ccp(0, -32);          
        break;      
    case kLeft:          
        moveByPosition = ccp(-32, 0);          
        break;      
    case kRight:          
        moveByPosition = ccp(32, 0);          
        break;      
    case kUp:          
        moveByPosition = ccp(0, 32);          
        break;      
    }      
    //计算目标坐标,用勇士当前坐标加上移动距离      
    CCPoint targetPosition = ccpAdd(heroSprite->getPosition(), moveByPosition);     
    CCPoint tilePoint = tilecoordForPosition(targetPosition);      
    //检查碰撞类型,如果是墙壁,则只需要设置勇士的朝向      
    if (checkCollision(targetPosition) == kWall)      
    {          
        setFaceDirection(tag);          
        return;      
    }              
    //利用ccspawn将行走动画和移动同时执行      
    CCAction *action =CCSequence::create( //CCSequence::actions(
        CCSpawn::create(//CCSpawn::actions(
            CCAnimate::create(walkAnimations[tag]),//CCAnimate::actionWithAnimation(walkAnimations[tag]),
            CCMoveBy::create(0.28f,moveByPosition),NULL),//CCMoveBy::actionWithDuration(0.28f, moveByPosition), NULL),
        //把当前的行走方向传递给onwalkdone          
            CCCallFuncND::create(this,callfuncND_selector(HelloWorld::onWalkDone),(void*)(tag)),NULL);
                
        
    heroSprite->runAction(action);          
    //设置移动状态      
    this->isHeroWalking = true;  
}  
/************************************************************************          
设置行走方向  *********************************************[2013年1月24日 13:08:06]***/
void HelloWorld::setFaceDirection(HeroDirection direction)  
{      
    heroSprite->setTextureRect(CCRectMake(0, 32.0f*direction, 32, 32));  
}      
/************************************************************************          
停止行走的回调  
*********************************************[2013年1月24日 13:08:06]***/
void HelloWorld::onWalkDone(CCNode *pTarget, void *data)  
{      
    //设置移动状态     
    this->isHeroWalking = false;      
    HeroDirection direction = (HeroDirection)(int)data;     
    this->setFaceDirection(direction);  
}  
/************************************************************************          
游戏场景的移动  
*********************************************[2013年1月24日 16:05:27]***/
void HelloWorld::setSceneScrollPosition(CCPoint position)  
{      
    CCSize screenSize = CCDirector::sharedDirector()->getWinSize();      
    //计算TMXtilemap的宽高      
    CCSize mapSize = CCSizeMake(map->getMapSize().width*map->getTileSize().width,         
        map->getMapSize().height*map->getTileSize().height);      
    float x = MAX(position.x, screenSize.width/2.0f);      
    float y = MAX(position.y, screenSize.height/2.0f);          
    if (mapSize.width > screenSize.width)         
        x = MIN(x, mapSize.width - screenSize.width/2.0f);      
    if (mapSize.height > screenSize.height)          
        y = MIN(y, mapSize.height - screenSize.height/2.0f);          
    CCPoint heroPosition = ccp(x, y);      
    CCPoint screenCenter = ccp(screenSize.width/2.0f, screenSize.height/2.0f);      
    CCPoint scrollPosition = ccpSub(screenCenter, heroPosition);        
    this->setPosition(scrollPosition); 
}      
/************************************************************************      
定时器回调函数,更新地图  
***********************************************[2013年1月24日 17:12:16]**/
void HelloWorld::update(float dt)  
{      
    if (isHeroWalking)        
        setSceneScrollPosition(heroSprite->getPosition()); 
}      
/************************************************************************      
从cocos2d-x坐标转换成Tilemap坐标  
***********************************************[2013年1月24日 17:13:09]**/
CCPoint HelloWorld::tilecoordForPosition(CCPoint position)  
{      
    int x = int(position.x/map->getTileSize().width);    
    int y = int(position.y/map->getTileSize().height);     
    return ccp(x, y); 
}     
/************************************************************************     
从Tilemap坐标转换成cocos2d-x坐标  
***********************************************[2013年1月24日 17:27:37]**/
CCPoint HelloWorld::positionForTileCoord(CCPoint position) 
{      
    float x = float(position.x*map->getTileSize().width);     
    float y = float(position.y*map->getTileSize().height);     
    return ccp(x, y); 
}    
/************************************************************************      
根据勇士当前位置判断碰撞类型
***********************************************[2013年1月24日 17:15:38]**/
HelloWorld::CollisionType HelloWorld::checkCollision(cocos2d::CCPoint heroPosition)  
{     
    //将cocos2d-x坐标转换成为Tilemap坐标     
    CCPoint tileCoord = tilecoordForPosition(heroPosition);       
    //如果勇士坐标超过地图边框,返回kWall类型,阻止其移动    
    if (heroPosition.x < 0 || tileCoord.x > map->getMapSize().width-1    
        || tileCoord.y < 0 || tileCoord.y > map->getMapSize().height-1)    
        return kWall;    
    //由于TMX文件的坐标与游戏中坐标定义不同转换一下;  
    tileCoord.y = map->getMapSize().height - 1 - tileCoord.y;  
    //获取当前图块的ID,为1表示有墙    
    if(map->layerNamed("wall")->tileGIDAt(tileCoord))    
    {
        return kWall;  
    }
    //其他可以通行  
    if (map->layerNamed("floor")->tileGIDAt(tileCoord))
    {
        return kNone;  
    }
    
           
}      
/************************************************************************     
析构函数  *********************************************[2013年1月24日 13:08:06]***/
HelloWorld::~HelloWorld() 
{     
    //释放内存   
    for (int i=0; i<4; i++)     
    {         
        CC_SAFE_RELEASE(walkAnimations[i]);     
    }      this->unscheduleAllSelectors(); 
}      

 

 tmx、png文件下载

posted @ 2013-02-07 17:13  gwjtssy  阅读(4390)  评论(0编辑  收藏  举报