学习: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(); }