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

本人最近幾個月在工做之餘,都有斷斷續續地去學習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版本的應該是均可以運行的

相關文章
相關標籤/搜索