首页 > 代码库 > Cocos2d-x 3.2 学习笔记(十二)TimberMan!疯狂伐木工!

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

 

Cocos2d-x 3.2 学习笔记(十二)TimberMan!疯狂伐木工!