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