若是你看過第一部分介紹,你應該大致知道一個橫版遊戲該怎麼樣去作,須要什麼東西了....本部分介紹一些細節設計...字體
第一個:單例對象咱們應該怎麼設計才比較方便用呢?裏面須要放置哪些對象的引用和指針呢?動畫
在一個戰鬥場景裏,就當前這個遊戲來講,GameLayer(遊戲層),OptionLayer(操做層) 是他最基礎的構成部分,天然在每一個層中的child你都是能夠訪問的,對於英雄和NPC也是同樣,若是將這些對象的引用當成一個全局的指針放置在一個單例對象裏,那在接下來的開發訪問中將會有很大的便利,由於這些對象基本上是不可缺的....ui
這裏我先介紹一個很好用的單例模版類,全部你須要建立的單例類只要繼承它就能夠了,很是方便lua
#ifndef _SINGLETON_H #define _SINGLETON_H using namespace std; template <class T> class Singleton { public: //獲取類的惟一實例 static inline T* instance(); //釋放類的惟一實例 void release(); protected: Singleton(void){} ~Singleton(void){} static T* _instance; }; template <class T> inline T* Singleton<T>::instance() { if(NULL == _instance){ _instance = new T; } return _instance; } template <class T> void Singleton<T>::release() { if (!_instance) return; delete _instance; _instance = 0; } //cpp文件中須要先聲明靜態變量 #define DECLARE_SINGLETON_MEMBER(_Ty) \ template <> _Ty* Singleton<_Ty>::_instance = NULL; #endif//_SINGLETON_H
那麼單例中你能夠引用這如下對象,方便訪問,可是要注意cpp文件中須要聲明靜態變量,能夠經過模板中的宏 DECLARE_SINGLETON_MEMBER(XXX);spa
//需引入如下類,不然在這些類中訪問單例對象會報錯 class GameDisplayLayer; class OptionLayer; class Hero; class Role; USING_NS_CC; //全局單例 class Global:public Singleton<Global> { public: Global(void); ~Global(void); //GameScene *gameScene; GameDisplayLayer *gameLayer; //遊戲層 OptionLayer *optionLayer; //操做層 Hero *hero; //英雄 CCArray *npcs; //怪物 CCTMXTiledMap *tmxTileMap; //地圖
//還有其餘一些對象的引用和公共方法也能夠放這裏......本身定義
}
第二,咱們得介紹一下人物和地圖的移動的細節問題,好比:地圖通常狀況下是比當前屏幕大的,橫版遊戲人物在各個方向移動時,必須考慮何時該由地圖自己移動位置,而不是英雄移動,不過這個問題應該是比較好獲得答案的,只要人物移動的下一幀地址快要超出屏幕中間,咱們就讓地圖超反方向移動相等距離,這樣能夠形成英雄向前移動的效果,可是若是地圖最邊緣方向快要移動完畢時,爲了保證不把黑色的越界區域顯示出來,你還得在每次移動前判斷是否地圖邊緣位置快要超過屏幕了,這時候,就算任務下一幀到達屏幕中間部分,你也得讓英雄移動;除此以外,若讓地圖移動,那麼你也必須遍歷Npc,道具什麼的,讓他們跟着地圖一塊兒移動....如下貼出部分代碼。設計
if (heroCtrl->getAllowMove()&&(Direction.x != 0||Direction.y != 0)) { CCSize size=CCDirector::sharedDirector()->getWinSize(); //製造一個矩形框,人物只會在當前框裏活動,經過地圖移動來形成更大面積的活動範圍 CCRect rect=CCRectMake(heroCtrl->getContentSize().width/2,heroCtrl->getContentSize().height/2,size.width-(heroCtrl->getContentSize().width/2),size.height-(heroCtrl->getContentSize().height/2)); if(rect.containsPoint(position)){ float mapMaxX = 0; //計算是不是人移動仍是地圖移動,注意:地圖在初始化時錨點已設爲cpp(0,0) if(heroCtrl->getPosition().x <= SCREEN.width/2 && Direction.x>0 && position.x > SCREEN.width/2){ //地圖須要左移動,position表示人物下一幀的位置 //計算地圖最右端x軸下一次位置 mapMaxX = tmxTileMap->getPositionX()+tmxTileMap->getContentSize().width-Direction.x; //保證地圖不會把越界部分移出來 if(mapMaxX > SCREEN.width){ global->tmxTileMap->setPositionX(global->tmxTileMap->getPositionX()-Direction.x); OptionLayer::npcMoveByMap(ccp(-Direction.x,0)); if(Direction.y != 0){ heroCtrl->setPositionY(heroCtrl->getPositionY() + Direction.y);//防止地圖移動時,人物Y軸不能移動 } }else{ heroCtrl->setPosition(position); //地圖快要越界,人物移動便可 } }else if(heroCtrl->getPosition().x >= SCREEN.width/2 && Direction.x<0 && position.x < SCREEN.width/2){//地圖須要像右移動 //計算地圖最左端x軸下一次位置 mapMaxX = tmxTileMap->getPositionX()+Direction.x; //保證地圖不會把越界部分移出來 if(mapMaxX < 0){ global->tmxTileMap->setPositionX(global->tmxTileMap->getPositionX()-Direction.x); OptionLayer::npcMoveByMap(ccp(-Direction.x,0)); if(Direction.y != 0){ heroCtrl->setPositionY(heroCtrl->getPositionY() + Direction.y);//防止地圖移動時,人物Y軸不能移動 } }else{ heroCtrl->setPosition(position); //地圖快要越界,人物移動 } }else{ heroCtrl->setPosition(position); //人物移動便可 } } }
第三,英雄跟怪物的相互遮擋問題,一個比較偷懶但頗有效的解決辦法是,根據Y軸的位置來設置當前對象的zOrder值......指針
第四,AI 自動追殺英雄的問題,方法有不少種,其中之一的方法,能夠參考搖桿控制的辦法來一步步靠近英雄......(這個功能點能夠花點心思考慮考慮,AI智能....提及來很廣了)code
第五,英雄跟怪物之間釋放攻擊技能的碰撞問題,這個貌似比較簡單,可是有一點須要注意的是,png圖片的大小每每要比精靈實際的大小要大,若是計算有效的攻擊範圍,可被攻擊的範圍等到 rect = CCRectMake(originX,originY,width,height);這個須要根據實際狀況來定,經過attackReck.intersectsRect(hurtReck)方法判斷碰撞是否有效對象
代碼裏以前寫的地方有錯,CCRect理解出錯,應該是左下角原點+寬和高(汗.....)blog
//計算有效攻擊區域 CCRect PublicFun::getAttackRect(Role* role){ CCRect rect ; float originX = 0; float originY = 0; float width = 0; float height = 0; //計算正前方攻擊區域 if(role->getRoleDirection() == RolelTurnRight){//朝右 originX = role->getPositionX(); originY = role->getPositionY() - role->getContentSize().height/2; width = role->getContentSize().width/2; height = role->getContentSize().height/2; rect = CCRectMake(originX,originY,width,height); }else{ originX = role->getPositionX() -role->getContentSize().width/2; originY = role->getPositionY() - role->getContentSize().height/2; width = role->getContentSize().width/2; height = role->getContentSize().height/2; rect = CCRectMake(originX,originY,width,height); } return rect; } //計算可被攻擊有效區域(當前精靈大小) CCRect PublicFun::getHurtRect(Role* role){ CCRect rect ; float originX = 0; float originY = 0; float width = 0; float height = 0; //受攻擊範圍 originX = role->getPositionX() - role->getContentSize().width/2; originY = role->getPositionY() - role->getContentSize().height/2; width = role->getContentSize().width; height = role->getContentSize().height; rect = CCRectMake(originX,originY,width,height); return rect; }
以後計算是否被攻擊
CCRect hurtReck = PublicFun::getHurtRect(npc);//怪物受傷區域 if(attackReck.intersectsRect(hurtReck)){ npc->setAllowMove(false); //此處可處理怪物被攻擊後的後續 Hero::damageDisplay("-999", npc); npc->RunHurtAction(); }
第六,技能傷害數字漸隱效果,這個問題也比較好解決,只要在當前角色頭頂上方生成CCLabelBMFont 或者其餘字體都行,經過CCFadeOut產生漸隱效果,以後移除掉該字體便可
void Hero::damageDisplay(const char* str,NPC* npc){//產生數字動畫 CCFadeOut *labelFadeOut = CCFadeOut::create(1.5f); CCLabelBMFont* atLabel = CCLabelBMFont::create(str, "fonts/helvetica-32.fnt"); atLabel->setColor(ccRED); atLabel->setPosition(ccp(npc->getPositionX()-5,npc->getPositionY()+npc->getContentSize().height/2+5)); global->gameLayer->addChild(atLabel, 1); CCFiniteTimeAction * callFuncN = CCCallFuncN::create(atLabel, callfuncN_selector(Hero::FontsCallBackAction)); CCFiniteTimeAction *sequence = CCSequence::create(labelFadeOut, callFuncN,NULL); atLabel->runAction(sequence); }
說到這裏,貌似整個遊戲的介紹都算比較徹底了,麻雀雖小,涵蓋的東西細節上仍是有很多須要處理的,後續考慮用quick-cocos2dx用全lua實現移植它
代碼和資源附件後續會上傳上來....
http://pan.baidu.com/s/1ntFQwrB 這是源代碼,在vs2012 cocos2dx 2.2.2上運行,3.0如下~2.0版本的應該是均可以運行的