基於cocos2dx的橫版動做遊戲製做(二)

若是你看過第一部分介紹,你應該大致知道一個橫版遊戲該怎麼樣去作,須要什麼東西了....本部分介紹一些細節設計...字體

第一個:單例對象咱們應該怎麼設計才比較方便用呢?裏面須要放置哪些對象的引用和指針呢?動畫

在一個戰鬥場景裏,就當前這個遊戲來講,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版本的應該是均可以運行的

相關文章
相關標籤/搜索