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

 

posted @ 2014-10-16 22:01  richliu1023  阅读(2591)  评论(20编辑  收藏  举报