Cocos2d-x 3.2 學習筆記(十二)TimberMan!瘋狂伐木工!


  學習cocos2dx有一段時間了,試着做了2048游戲,最近又發現個經典游戲,啥也不說果斷開工做自己的游戲——TimberMan

  首先說明:游戲資源摘自同類游戲,感謝這些游戲的資源讓我完成自己的開發。

一、TimberMan玩法--根本停不下來!

    這款游戲的玩法比較簡單,通過手指點擊左右屏幕來決定砍樹站立的方向,不能讓樹枝碰觸Hero,同時有時間限制(時間通過砍樹增加),如果停止砍樹時間結束=游戲結束。

  讓我們看看成品的效果吧!(ps:錄像失幀,看到的不直觀,可以下載已打包好的apk 在最下方)

二、代碼結構

  HelloWorldScene 主場景

  TreeModel  樹木(由樹節點組合而成)

  Timber 伐木Hero

  TreeNode 樹木節點

  GameScore 場景生命和得分

  GameOver 游戲結束

 

  當然由小到大,一顆大樹是由無數的樹節點組成的,因此先寫樹結類,然后才是大樹類,最后才是場景。這樣拆分之后就很簡單的做出了demo

三、樹節點TreeNode 

  樹節點是一顆樹的基礎,包括樹枝。當然,有沒有樹枝、樹枝的方向是由 大樹控制的。因此有如下枚舉貫穿游戲

  

enum TreeBranchDirection
{
    DEFINE,//無節點
    LEFT,//
    RIGHT//
};

  節點的基本功能:1、設置樹枝2、獲取樹枝類型(返回TreeBranchDirection)

void TreeNode::setBranch(TreeBranchDirection enums)
{
    enumBranch = enums;
    auto branch = this->getChildByName("branch");
    auto body = this->getChildByName("body");
    branch->setVisible(enums!=DEFINE);
    if(enums==DEFINE)return;
    if(enums == RIGHT)
    {
        branch->setScaleX(1);
        branch->setPositionX(body->getContentSize().width);
    }
    else
    {
        branch->setScaleX(-1);
        branch->setPositionX(-body->getContentSize().width);
    }
}

TreeBranchDirection TreeNode::getHasBranch()
{
    return enumBranch;
}

四、大樹TreeModel

  大樹是樹節點的集合,由一個一個的節點依次排列組成。最基本的功能如下

  TreeNode* getTreeHeadNode();獲得頭節點

  TreeNode* deleteTreeHeadNode();刪除頭節點

  void initTree();初始化

  TreeBranchDirection getFirstBranch();獲得頭節點的樹枝方向

  void onReset();重置整個樹

  Vector<TreeNode*> treeQueue;樹節點列表

  Vector<TreeNode*> treeCache;樹節點緩存列表

  優化:這個游戲一直在變化的是樹節點,如果不停的刪除和new節點 將會使程序不健康!為此除了要有樹列表treeQueue外要有一個緩存隊列treeCache,緩存隊列的工作就是避免重復的new節點,同時回收砍掉的節點等待下次使用。

  當然,作為大樹的類是整個游戲的重點邏輯:生成什么樣節點?

    1、通過玩法得知必須在不同方向的樹枝之間存在一個沒有樹枝的節點,使hero能生存。

    2、如果前一個是有樹枝的,那么以什么概率來產生下一個節點是否要有樹枝(有樹枝必須是同方向的 or 無樹枝),使hero生存。

    3、如果前一個樹節點是無樹枝的,那么再向前一個的樹節點是否有樹枝?根據難度來調節是否要產生樹枝,增加難度。

  圍繞着這三個問題要有一個得到樹枝的邏輯函數TreeModel::getBranch()

TreeBranchDirection TreeModel::getBranch()
{
    auto isBranch = CCRANDOM_0_1()*10 < 7;
    if( treeQueue.size() == 0 )
        return DEFINE;
    if( !isBranch ) return DEFINE;
    auto protree = treeQueue.at(treeQueue.size()-1);
    switch (protree->getHasBranch())
    {
        case LEFT:
            return (CCRANDOM_0_1()*10 < 5) ? DEFINE : LEFT;
            break;
        case RIGHT:
            return (CCRANDOM_0_1()*10 < 5) ? DEFINE : RIGHT;
            break;
        case DEFINE:
            return getAgainBranch();
            break;
        default:
            return DEFINE;
            break;
    }
}

TreeBranchDirection TreeModel::getAgainBranch()
{
    if( treeQueue.size() < 2 )
        return DEFINE;
    auto protree = treeQueue.at(treeQueue.size()-2);
    switch (protree->getHasBranch())
    {
    case LEFT:
        return (CCRANDOM_0_1()*10 < 6) ? RIGHT : LEFT;
        break;
    case RIGHT:
        return (CCRANDOM_0_1()*10 < 6) ? LEFT : RIGHT;
        break;
    case DEFINE:
        return (CCRANDOM_0_1()*10 < 4) ? LEFT : RIGHT;
        break;
    default:
        return DEFINE;
        break;
    }
}

  這其中的 概率隨機數是可以調整的,如果你想增加難度 那就調整吧!

五、時間線GameScore

  游戲結束有兩個點1、碰到樹枝2、時間終止

  時間進度我用的ProgressTimer 進度表示時間百分比。

  我想到了兩種邏輯:

    1、speed 法, 通過分數來決定速度,分數越高時間越少,不斷的砍樹來維持時間平衡。

    2、addProgress 增量法, 通過分數來決定砍樹獲得每次增加的量,分數越高增量越低,最后維持在一個平衡點,在這個平衡點上保持速度均衡。

  我最后選得增量,這兩種方法相對都很不錯。

 

六、數據存儲UserDefault

  整個游戲不需要大量的存儲數據,因為只是記錄最高分數,在設置游戲結束分數的時候進行讀寫

void GameOver::setScore(int score)
{
    int maxScore = score;
    char string[50] = {0};
    sprintf(string, "Score %d", score);
    _newScore->setString(string);

    maxScore = UserDefault::getInstance()->getIntegerForKey("maxScore");
    if( maxScore < score )
    {
        UserDefault::getInstance()->setIntegerForKey("maxScore",score);
    }
    newScore->setVisible(( maxScore < score ));
    char str2[50] = {0};
    sprintf(str2, "Max Score %d", ( maxScore < score ) ? score : maxScore);
    _highestScore->setString(str2);

    UserDefault::getInstance()->flush();
}

七、主場景 HelloWorldScene

  主場景控制游戲的開始與結束。邏輯判斷並不多。

  點擊判斷:

bool HelloWorld::onTouchBegans(Touch *touch, Event *event)
{
    auto pos = touch->getLocation();
    Size visibleSize = Director::getInstance()->getVisibleSize();
    auto model = TreeModel::getInstance();

    auto isRight = pos.x > visibleSize.width/2;
    timber->playAction(isRight ? RIGHT : LEFT);
    if(isRight)
    {
        timber->setPosition(visibleSize.width/2+timber->getContentSize().width/2+20,150);
    }
    else
    {
        timber->setPosition(visibleSize.width/2-timber->getContentSize().width/2-20,150);
    }

    if(getIsOver())
    {
        timber->setTimberDie();
        gameOver();
        return false;
    }

    auto dic = visibleSize.width*2;
    auto time = 0.5;
    auto tree = model->deleteTreeHeadNode();
    if( isRight )
    {
        tree->runAction(Spawn::create(RotateBy::create(time,-180),MoveBy::create(time,Vec2(-dic,0)),nullptr));
    }
    else
    {
        tree->runAction(Spawn::create(RotateBy::create(time,180),MoveBy::create(time,Vec2(dic,0)),nullptr));
    }

    _score++;
    score->setScore(_score);
    if(getIsOver())
    {
        timber->setTimberDie();
        gameOver();
    }

    return true;
}

  是否游戲結束:

bool HelloWorld::getIsOver()
{
    auto model = TreeModel::getInstance();

    if(model->getFirstBranch() == timber->getTimberDir()) return true;
    return false;
}

  重置游戲,從新開始:

void HelloWorld::onRest()
{
    _score = 0;
    TreeModel::getInstance()->onReset();
    score->onReset();
    timber->onReset();
    list->setEnabled(true);
    auto isBgShow = (CCRANDOM_0_1()*10 < 5);
    bg1->setVisible(isBgShow);
    bg2->setVisible(!isBgShow);
    Size visibleSize = Director::getInstance()->getVisibleSize();
    timber->setPosition(visibleSize.width/2-timber->getContentSize().width/2-20,150);
}

  當然coco2dx的粒子系統也很不錯 我加入了 雪花特效以及聲音特效:

 

ParticleSystem* pl = ParticleSnow::create();
     pl->setTexture(Director::getInstance()->getTextureCache()->addImage("particle.png"));
     pl->setPosition(visibleSize.width/2,visibleSize.height);
     this->addChild(pl);

 

八、總結

  這個游戲算是我做的比較全的demo了,加入了屏幕適配、桌面圖片icon、聲音、粒子、數據。雖然比較簡單,但能學習、做好、完善其實還是比較不錯的,因為工作比較忙所以抽空能敲一敲代碼,不過總算沒有半途而廢。

  TimberMan.apk

  鏈接:http://pan.baidu.com/s/1o6A0Dce 密碼:29mz

  TimberMan代碼

  鏈接: http://pan.baidu.com/s/1pJynvdT 密碼: bt1v

 


免責聲明!

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



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