基於cocos2dx的橫版動作游戲制作(一)


本人最近幾個月在工作之余,都有斷斷續續地去學習cocos2dx的一些東西,在一些論壇上參考有關資料,源碼,比如www.9miao.com,泰然網等等,畢竟開源,而且較為有趣。

7月份離職后,希望換個方向做手游(我之前一直做的是JAVA,web,數據庫),發現沒有工作經驗真的是不好找....,筆試過了,面試總會問:“你有沒有什么作品”,一想想,平時都是做一些demo,或者是參閱別人的項目源碼,好像真的沒有完整的弄一樣東西出來。

為此,我准備做一個橫版的動作游戲(因為是第一次做,前后總共花了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版本的應該是都可以運行的

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM