基于cocos2dx的横版动作游戏制作(二)
如果你看過第一部分介紹,你應該大體知道一個橫版游戲該怎么樣去做,需要什么東西了....本部分介紹一些細節設計...
第一個:單例對象我們應該怎么設計才比較方便用呢?里面需要放置哪些對象的引用和指針呢?
在一個戰斗場景里,就當前這個游戲來說,GameLayer(游戲層),OptionLayer(操作層) 是他最基礎的構成部分,自然在每個層中的child你都是可以訪問的,對于英雄和NPC也是一樣,如果將這些對象的引用當成一個全局的指針放置在一個單例對象里,那在接下來的開發訪問中將會有很大的便利,因為這些對象基本上是不可缺的....
這里我先介紹一個很好用的單例模版類,所有你需要創建的單例類只要繼承它就可以了,非常方便
#ifndef _SINGLETON_H #define _SINGLETON_Husing 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);
//需引入以下類,否則在這些類中訪問單例對象會報錯 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智能....說起來很廣了)
第五,英雄跟怪物之間釋放攻擊技能的碰撞問題,這個貌似比較簡單,但是有一點需要注意的是,png圖片的大小往往要比精靈實際的大小要大,如果計算有效的攻擊范圍,可被攻擊的范圍等到?rect = CCRectMake(originX,originY,width,height);這個需要根據實際情況來定,通過attackReck.intersectsRect(hurtReck)方法判斷碰撞是否有效
代碼里之前寫的地方有錯,CCRect理解出錯,應該是左下角原點+寬和高(汗.....)
//計算有效攻擊區域 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版本的應該是都可以運行的
posted on 2014-07-15 12:58 慵懶的貓 閱讀(...) 評論(...) 編輯 收藏轉載于:https://www.cnblogs.com/zouly/p/3844531.html
總結
以上是生活随笔為你收集整理的基于cocos2dx的横版动作游戏制作(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【游戏作品】SUNSET——动漫风横版动
- 下一篇: 用Unity开发一款2D横版游戏demo