本人最近幾個月在工做之餘,都有斷斷續續地去學習cocos2dx的一些東西,在一些論壇上參考有關資料,源碼,好比www.9miao.com,泰然網等等,畢竟開源,並且較爲有趣。html
7月份離職後,但願換個方向作手遊(我以前一直作的是JAVA,web,數據庫),發現沒有工做經驗真的是很差找....,筆試過了,面試總會問:「你有沒有什麼做品」,一想一想,平時都是作一些demo,或者是參閱別人的項目源碼,好像真的沒有完整的弄同樣東西出來。web
爲此,我準備作一個橫版的動做遊戲(由於是第一次作,先後總共花了6天時間才基本完成)面試
在看官您閱讀如下內容時,我認爲您是對cocos2x是有一些基礎瞭解的。數據庫
在作這個遊戲以前,咱們先來設想一下,咱們遊戲須要哪些對象,內容等等到這些東西呢?設計模式
1.在一個戰鬥場景中,咱們須要一副地圖做爲基礎,因此你可能須要用到Tiled 這個工具,來製做咱們的地圖(在此我會認爲您對瓦片地圖是有了解的);緩存
2.咱們須要控制操做英雄(hero),怪物(AI)要來攻擊英雄,hero和AI的閒置,行走,戰鬥都是須要不停地播放動畫的,因此你可能須要本身去找一些人物素材(這玩意還真是很差找),而後爲了方便加載使用,你可能還須要將幀動畫序列打包,因此你極可能須要用到TexturePacker工具編輯器
3.英雄須要釋放各類技能,還須要能使用血瓶加血,魔瓶加藍,同時咱們還須要左上角可以顯示當前英雄的血量,藍量和等級等等信息,咱們還須要一個搖桿來操控英雄,等等......麻雀雖小,東西也不能少啊.....,這些素材都須要本身去找,準備好了佈局又是一個問題了,這裏你可能須要用到CocosStudio的UI編輯器了工具
4.素材的處理:你找的素材不必定都能直接用,你極可能還得本身去用PotoShop進行加工....佈局
好了,以上這些介紹東西,已經大概能支撐咱們作一款橫版遊戲最基礎的「磚石」了,固然還有cocos2dx了,無論你在XCode下仍是在VS下,這是你各人的喜愛了,這裏就不介紹cocos2d的配置了,網上有不少這方面的帖子。學習
在此咱們來整理一下,咱們上面說到要用到的一些工具:
1.Tiled :用來作瓦片地圖的
2.TexturePacker :幀動畫打包的
3.CocosStudio:UI製做的
4.PotoShop:素材加工
在此,我先放張圖出來,看看開發完成以後的效果
這張圖就是最基本的效果了。
接下來,咱們開動以前還須要作些預備工做,那就是設計啦.....,咱們不能直接拿上素材就開搞。
//------------------------設計部分----------------------------
整個戰鬥場景咱們能夠將他當作兩層:
一個是遊戲層(GameLayer):這裏包括英雄,怪物,地圖,已經地圖上的掉落,道具等等.....
一個是操做層(OptionLayer):這裏包括操做搖桿,技能UI,物品UI,人物頭像屬性UI
而後咱們須要考慮一下一些面向對象的東西,在這裏,英雄跟怪物是有不少共性的.咱們能夠將他們當作是一類角色(Role).....(包括你可能須要加一些非敵對類的NPC等均可歸爲這一類),怪物和英雄均可繼承自它,這樣咱們能省不少事.....
咱們最後還得考慮如下,各個對象直接的交互訪問問題....由於一個場景裏的各個對象有時候須要相互訪問,那這個對象的實例怎麼獲取比較方便呢,這裏咱們用一個單例來保存這些對象的指針或者引用(若是您對單例設計模式不瞭解的話,能夠先去稍微瞭解一十幾分鍾)
好了,設計部分好像說的差很少了(再往下說就沒個模塊的細節設計了,這點咱們後面結合代碼將),看起來是否是很簡單呢?(是的,一目瞭然,可是咱們作的最多的工做永遠都是細節上的處理)
//---------------------地圖的處理-------------
咱們將地圖圖片的可達區域和不可區域理解爲地面(floor)和牆壁(wall)兩個Layer
這在後續控制英雄和怪物移動位置是能較好把握好範圍,畢竟,地圖的每一個區域不該該都是可達的(具體的編輯細節可本身摸索和參考網上的資料,這裏再也不贅述);
總之你作好以後,在後續開發時確定會用到它,如下是地圖的加載......
//初始化地圖 void GameDisplayLayer::initMapWithFile(const char * path){ CCTMXTiledMap *tileMap = CCTMXTiledMap::create(path); CCObject *pObject = NULL; //遍歷tmx地圖中的Layer CCARRAY_FOREACH(tileMap->getChildren(), pObject) { CCTMXLayer *child = (CCTMXLayer*)pObject; child->getTexture()->setAliasTexParameters(); } tileMap->setAnchorPoint(ccp(0,0)); tileMap->setPosition(ccp(0,0)); this->addChild(tileMap, 0); global->tmxTileMap = tileMap; }
加載完後,若咱們想要知道對象要移動的點到底在不在floor這一區域內呢?如下是轉換和判斷位置代碼(這裏我提早貼出代碼.....省的後面忘記)
//判斷位置是否在地圖可移動範圍內 bool Global::tileAllowMove(CCPoint MovePoint){ CCTMXLayer *floor = global->tmxTileMap->layerNamed("floor"); //計算當前touchpoint在地圖中的Gid CCPoint tileGid = Global::tilePosFromLocation(MovePoint); if(0 == floor->tileGIDAt(tileGid)){ //CCLog("current touchPoint tileGIDAt(?) is Empty "); return false; } return true; } //將CCPoint轉換成Gid位置 CCPoint Global::tilePosFromLocation(CCPoint MovePoint, CCTMXTiledMap *map) { if(NULL == map){ map = global->tmxTileMap; } // 移動點的屏幕座標必須減去瓷磚地圖的座標 - 由於地圖可能比屏幕大,不少時候地圖會隨着操做移動,地圖位置不必定在(0,0)點上了 CCPoint point = ccpSub(MovePoint, map->getPosition()); // 將獲得座標值轉換成整數 CCPoint pointGID = ccp(0,0); pointGID.x = (int) (point.x / map->getTileSize().width); pointGID.y = (int) ((map->getMapSize().height * map->getTileSize().height - point.y) / map->getTileSize().height); //CCLog("pointGID.x,%f,%f",pointGID.x,pointGID.y); return pointGID; }
//----------------------Role類設計--------------------------------------
Role類是怪物和英雄的基類,它定義了二者所共有的屬性,方法等.......如下是代碼示例,Role.h的頭文件
注意:每一個序列幀動畫Animation 須要在怪物和英雄的init()中給其初始化
//基礎角色類,主角和NPC都須要繼承它 class Role :public CCSprite { public: Role(void); ~Role(void); CC_SYNTHESIZE(std::string,Name,Name); //角色名稱 CC_SYNTHESIZE(CCAnimation*,idleAnimation,IdleAnimation); //角色空閒時序列 CC_SYNTHESIZE(CCAnimation*,movingAnimation,MovingAnimation); //角色移動時動畫幀序列 CC_SYNTHESIZE(CCAnimation*,attackAnimation,AttackAnimation); //角色普通攻擊時動畫幀序列 CC_SYNTHESIZE(CCAnimation*,attackAnimation_1,AttackAnimation_1); //角色特殊攻擊1動畫幀序列 CC_SYNTHESIZE(CCAnimation*,attackAnimation_2,AttackAnimation_2); //角色特殊攻擊2動畫幀序列 CC_SYNTHESIZE(CCAnimation*,attackAnimation_3,AttackAnimation_3); //角色特殊攻擊3動畫幀序列 CC_SYNTHESIZE(CCAnimation*,attackAnimation_4,AttackAnimation_4); //角色特殊攻擊4動畫幀序列 CC_SYNTHESIZE(CCAnimation*,hurtAnimation,HurtAnimation); //角色受傷時動畫幀序列 CC_SYNTHESIZE(CCAnimation*,deadAnimation,DeadAnimation); //角色死亡時動畫幀序列 CC_SYNTHESIZE(float,curtLifeValue,CurtLifeValue); //角色當前生命值 CC_SYNTHESIZE(float,sumLifeValue,SumLifeValue); //角色整體生命值 CC_SYNTHESIZE(float,attackStrenth,AttackStrenth); //角色當前攻擊力 CC_SYNTHESIZE(ActionState,actionState,ActionState); //當前Action狀態(據此狀態處理各個動畫之間的銜接問題) CC_SYNTHESIZE(Direction, roleDirection, RoleDirection); //角色朝向(分向左仍是向右) CC_SYNTHESIZE(bool, allowMove, AllowMove); //角色是否容許移動,例如:攻擊,受傷等動畫執行期間不可移動 CC_SYNTHESIZE(CCPoint, _vector, Vector); //偏移量,AI自動移動時下一幀的偏移向量 void Role::callBackAction(CCNode* pSender); //動畫執行完畢的通用回調處理 //action methods virtual void RunIdleAction(); //執行閒置動畫 virtual void RunMovingAction(); //執行移動行走動畫 virtual void RunAttackAction(); //執行普通攻擊動畫 virtual void RunAttackAction_1(); //執行特殊攻擊1動畫 virtual void RunHurtAction(); //執行被攻擊後受傷動畫 //......死亡動畫等 };
//-------------下面我再給出動畫執行部分的代碼和回調----------------------- void Role::RunAttackAction() { if(this->getActionState() == ActionStateNone || this->getActionState() == ActionStateIdle || this->getActionState() == ActionStateMove){ this->setAllowMove(false); this->stopAllActions(); this->setActionState(ActionStateAttack); CCFiniteTimeAction *sequence = NULL; CCAnimate * AttackAnimate = CCAnimate::create(this->getAttackAnimation()); CCFiniteTimeAction * callFuncN = CCCallFuncN::create(this, callfuncN_selector(Role::callBackAction)); sequence = CCSequence::create(AttackAnimate, callFuncN,NULL); //最後加上NULL,不然報錯 this->runAction(sequence); } } //動畫執行結束後的通用回調,可在子類本身定義回調 void Role::callBackAction(CCNode* pSender){ if(pSender != 0) { this->setActionState(ActionStateNone); this->setAllowMove(true); //非行走類動畫結束角色能夠移動 this->RunIdleAction(); //繼續執行空閒動畫 } }
//這裏我再給出英雄(hero)類的初始化init()方法中幀動畫的初始動做,怪物類可依葫蘆畫瓢.......
bool Hero::init(){ //預加載精靈圖片 CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("MyImages/role_ac_monkey.plist"); //獲取紋理緩存 CCSpriteFrameCache *spriteFrameCache = CCSpriteFrameCache::sharedSpriteFrameCache(); Hero::initWithSpriteFrameName("39597-1.png"); int frameNum = 0; //取幾幀 int frameStart = 0;//起始number CCArray *actionArry = CCArray::createWithCapacity(20); CCSpriteFrame *spriteFrame = NULL; //------------------------------idle action 空閒---------------------- frameNum = 4; //取幾幀 frameStart = 1;//起始number for(int i=frameStart;i<frameNum;i++){ spriteFrame = spriteFrameCache->spriteFrameByName(CCString::createWithFormat("39597-%d.png",i)->getCString()); actionArry->addObject(spriteFrame); } CCAnimation* idleAnimation = CCAnimation::createWithSpriteFrames(actionArry,0.2f); actionArry->removeAllObjects(); idleAnimation->retain(); this->setIdleAnimation(idleAnimation);
//......還有行走,攻擊動畫等等初始化 //---------------------釋放array-------------------------------------- actionArry->release(); return true; }
//-----------------------搖桿控制英雄行走的設計---------------------
怪物和英雄都有一樣的屬性,血量,攻擊,狀態,是否容許移動等等,貌似作的事情還很多,爲了能看到某種效果,咱們先來看看如何經過觸摸搖桿來控制hero行走
爲此咱們設計一個專門的腰桿類來處理英雄的移動控制,搖桿的控制爲此我作單章說明,請參考:http://www.cnblogs.com/zouly/p/3841830.html
//---------------------技能UI,及技能遮罩冷卻效果-------------------------
爲了使本篇幅看起來不是太長,我還但願在介紹本功能點時能開單章說明技能UI的製做過程,冷卻遮罩處理,請參考:http://www.cnblogs.com/zouly/p/3842333.html
好了,爲了使本文篇幅看起來不至於太長,咱們第一部分就介紹到這裏
另外,實現這個遊戲參考了不少文章,記不住了,也不一一列舉了
http://pan.baidu.com/s/1jGh0wJk 這是源代碼,在vs2012 cocos2dx 2.2.2上運行,3.0~2.0版本的應該是均可以運行的