学习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();
branch->setPositionX(body->getContentSize().width);
}
else
{
branch->setScaleX(-);
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()* < ;
if( treeQueue.size() == )
return DEFINE;
if( !isBranch ) return DEFINE;
auto protree = treeQueue.at(treeQueue.size()-);
switch (protree->getHasBranch())
{
case LEFT:
return (CCRANDOM_0_1()* < ) ? DEFINE : LEFT;
break;
case RIGHT:
return (CCRANDOM_0_1()* < ) ? DEFINE : RIGHT;
break;
case DEFINE:
return getAgainBranch();
break;
default:
return DEFINE;
break;
}
} TreeBranchDirection TreeModel::getAgainBranch()
{
if( treeQueue.size() < )
return DEFINE;
auto protree = treeQueue.at(treeQueue.size()-);
switch (protree->getHasBranch())
{
case LEFT:
return (CCRANDOM_0_1()* < ) ? RIGHT : LEFT;
break;
case RIGHT:
return (CCRANDOM_0_1()* < ) ? LEFT : RIGHT;
break;
case DEFINE:
return (CCRANDOM_0_1()* < ) ? 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[] = {};
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[] = {};
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/;
timber->playAction(isRight ? RIGHT : LEFT);
if(isRight)
{
timber->setPosition(visibleSize.width/+timber->getContentSize().width/+,);
}
else
{
timber->setPosition(visibleSize.width/-timber->getContentSize().width/-,);
} if(getIsOver())
{
timber->setTimberDie();
gameOver();
return false;
} auto dic = visibleSize.width*;
auto time = 0.5;
auto tree = model->deleteTreeHeadNode();
if( isRight )
{
tree->runAction(Spawn::create(RotateBy::create(time,-),MoveBy::create(time,Vec2(-dic,)),nullptr));
}
else
{
tree->runAction(Spawn::create(RotateBy::create(time,),MoveBy::create(time,Vec2(dic,)),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 = ;
TreeModel::getInstance()->onReset();
score->onReset();
timber->onReset();
list->setEnabled(true);
auto isBgShow = (CCRANDOM_0_1()* < );
bg1->setVisible(isBgShow);
bg2->setVisible(!isBgShow);
Size visibleSize = Director::getInstance()->getVisibleSize();
timber->setPosition(visibleSize.width/-timber->getContentSize().width/-,);
}

  当然coco2dx的粒子系统也很不错 我加入了 雪花特效以及声音特效:

ParticleSystem* pl = ParticleSnow::create();
pl->setTexture(Director::getInstance()->getTextureCache()->addImage("particle.png"));
pl->setPosition(visibleSize.width/,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!疯狂伐木工!的更多相关文章

  1. python3.4学习笔记(十二) python正则表达式的使用,使用pyspider匹配输出带.html结尾的URL

    python3.4学习笔记(十二) python正则表达式的使用,使用pyspider匹配输出带.html结尾的URL实战例子:使用pyspider匹配输出带.html结尾的URL:@config(a ...

  2. Go语言学习笔记十二: 范围(Range)

    Go语言学习笔记十二: 范围(Range) rang这个关键字主要用来遍历数组,切片,通道或Map.在数组和切片中返回索引值,在Map中返回key. 这个特别像python的方式.不过写法上比较怪异使 ...

  3. java jvm学习笔记十二(访问控制器的栈校验机制)

    欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 本节源码:http://download.csdn.net/detail/yfqnihao/4863854 这一节,我们 ...

  4. (C/C++学习笔记) 十二. 指针

    十二. 指针 ● 基本概念 位系统下为4字节(8位十六进制数),在64位系统下为8字节(16位十六进制数) 进制表示的, 内存地址不占用内存空间 指针本身是一种数据类型, 它可以指向int, char ...

  5. Python学习笔记(十二)—Python3中pip包管理工具的安装【转】

    本文转载自:https://blog.csdn.net/sinat_14849739/article/details/79101529 版权声明:本文为博主原创文章,未经博主允许不得转载. https ...

  6. ROS学习笔记十二:使用gazebo在ROS中仿真

    想要在ROS系统中对我们的机器人进行仿真,需要使用gazebo. gazebo是一种适用于复杂室内多机器人和室外环境的仿真环境.它能够在三维环境中对多个机器人.传感器及物体进行仿真,产生实际传感器反馈 ...

  7. JavaScript权威设计--命名空间,函数,闭包(简要学习笔记十二)

    1.作为命名空间的函数 有时候我们需要声明很多变量.这样的变量会污染全局变量并且可能与别人声明的变量产生冲突. 这时.解决办法是将代码放入一个函数中,然后调用这个函数.这样全局变量就变成了 局部变量. ...

  8. MySQL学习笔记十二:数据备份与恢复

    数据备份 1.物理备份与逻辑备份 物理备份 物理备份就是将数据库的数据文件,配置文件,日志文件等复制一份到其他路径上,这种备份速度一般较快,因为只有I/O操作.进行物理备份时,一般都需要关闭mysql ...

  9. Java基础学习笔记十二 类、抽象类、接口作为方法参数和返回值以及常用API

    不同修饰符使用细节 常用来修饰类.方法.变量的修饰符 public 权限修饰符,公共访问, 类,方法,成员变量 protected 权限修饰符,受保护访问, 方法,成员变量 默认什么也不写 也是一种权 ...

  10. Python学习笔记十二

    HTML全称:Hyper Text Markup Language超文本标记语言 不是编程语言 HTML使用标记标签来描述网页 2.  HTML标签 开始标签,结束标签.  例如:<html&g ...

随机推荐

  1. [原] XAF How to bind a stored procedure to a ListView in XAF

    First, I suggest that you review the following topic to learn how to show a custom set of objects in ...

  2. day11---异步IO\数据库\队列\缓存

    一.RabbitMQ队列 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议. MQ全称为Message Queue, 消息 ...

  3. jQuery树形菜单(1)jquery.treeview

    jQuery的树形插件资料URL:http://bassistance.de/jquery-plugins/jquery-plugin-treeview/从该网站Download得到jquery.tr ...

  4. SSIS oracle 64位 数据源链接

    新建数据源 提供程序选择:本机OLE DB ORACLE Provider For OLE DB 服务器名或文件名中选择Oracle Net Manager中配置好的服务名即可 填写账号,密码,测试, ...

  5. MySQL5:性能优化

    性能优化 优化MySQL数据库是数据库管理员和数据库开发人员的必备技能.MySQL优化,一方面是找出系统的瓶颈,提高MySQL数据库的整体性能:一方面需要合理的结构设计和参数调整,以提高用户操作响应的 ...

  6. XSS零碎指南

    该文章是本人两天的学习笔记,共享出来,跟大家交流.知识比较零散,但是对有一定 JS 基础的人来说,每个小知识都有助于开阔你的 Hack 视角.首先声明,本文只是 XSS 攻击的冰山一角,读者自行深入研 ...

  7. js中各种跨域问题实战小结(二)

    这里接上篇:js中各种跨域问题实战小结(一) 后面继续学习的过程中,对上面第一篇有稍作休整.下面继续第二部分: -->5.利用iframe和location.hash -->6.windo ...

  8. L# ForUnity Helloworld的更新方法

    Forunity目录结构 进入plugins 删除这三个目录 从Github代码位置copy 然后删除里面 bin obj property 项目文件等,仅留代码即可. 在editor运行test项目 ...

  9. COM思想的背后

    最近看公司的一些新产品和框架 , 发现清一色的“COM思想架构 ”, 这里说的“COM思想架构”是指不完全是标准COM组件的方式,而是指在设计上用到了COM思想. COM组件技术大概在1993年产生, ...

  10. 如何为编程爱好者设计一款好玩的智能硬件(八)——LCD1602点阵字符型液晶显示模块驱动封装(中)

    六.温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)! 七.点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计 ...