书生教你cocos2d-x-保卫萝卜(一)

原本是打算把整个游戏写完才整理教程的,可是细想起来,全部写完才发可能会耽搁不少时间,并且开发过程中的中间代码大家就看不到了。

因为本来这个教程的定位就是帮助刚入门的朋友学习如何做游戏,比起代码框架以及cocos2d-x Api,教大家一些开发游戏的思路,以及写代码的方式反而更加重要,如果只是介绍游戏代码,等这个游戏做完后,我自己优化代码,然后单开个《保卫萝卜开源代码框架说明》说明就是了。所以我打算分阶段的把项目进度和代码发上来(这就表示可能大家会看到一些未写完的代码,只是部分完善了功能),至少每周都更新一下博客,免得到最后没人看。

保卫萝卜大家应该都玩过,一款塔防游戏,每关开始后会定时刷怪,一共20波左右,每波有N个敌兵,按给定路线移动,若怪物成功移动到目的地,玩家守护的萝卜会掉血,萝卜死亡,则游戏失败。玩家可以在指定地点建造“塔”来***敌兵,从而进行防御。

没必要完全复刻保卫萝卜的所有功能,下面说明一下我们要完成怎样一个规模的游戏。

首先一些界面,我们必须得完成,这个跑不掉,但是游戏模式,我们只做它的冒险模式,boss模式和怪物窝功能就不做了。

然后原本的保卫萝卜有好几个大关卡(他们称为主题),每个有很多小关卡。由于结构差不多,我们只做一个主题就行了,也就是说我们的游戏没有主题的概念。

直接由9个小关卡组成。为了简单,我们选主题一里面的9关。

这里,我们需要设计每个关卡的数据结构,以后会说。

下面说关卡里的它和敌兵,主题一一共五种塔

特征分别是普通***,减速***,aoe***,直线aoe***,以及针对boss的必杀***。

以及涵盖大部分的塔的类型了。之后大家有兴趣可以自己扩充。

我目前的分析,大部分的敌兵都是不会还手的,ai都是向目标点移动。区别是血量和移动速度。游戏有胜利和失败,没有解锁,我们把所有的关卡都固定开放,方便调试。

简单来说,我们实现一个一种游戏模式,5种哨塔,7个小关的保卫萝卜。

暂定如此,如果之后发现有不同的,再修改。

---------------------------------分割线----------------------------------------------------------

下面是我们的开发计划,以及目前的成果汇报:

1, 首先得制作一个主界面,这个已经完成了。主界面要留一个debug入口,方便我们进入测试场景,进行单元测试。

2, 针对手上的资源,定制一个属于我们自己的动画类。Cocos2d-x虽然也有自己的动画类,不过很不直观,很多人说不好用。我们制作一个自己的动画类,熟悉一下相关概念。并在以后不断扩充,有机会的话把它扩充为切片动画类和骨骼动画类。

3, 完成选关界面,这里就要开始设计关卡的描述信息,也就是数据结构了。

4, 完成一个关卡,这里可以细分为地图逻辑,敌兵逻辑以及防御塔的逻辑,做到再说吧。

源代码太大,不让在附件里上传,我正在研究新方法.

×××地址 http://down.51cto.com/data/1015763

备用地址 http://down.51cto.com/data/1015743

这是目前的代码结构,随便弄的,还没整理。有个好的工程目录结构对自己之后查阅代码很有帮助,特别是大家以后上班了,如果把代码都塞在一个目录里,会被老大骂的。common文件夹是个大的垃圾堆,大家一般把暂时不想分类或是懒得分类的文件塞进去,这里我扔了一个记录const常量的文件,不过我一个字都没写,others放一堆不知道干什么用的文件,scenes是我们的场景,目前只有一个主界面,support里放一些基本元件,我放了一个动画类(尚未完全实现),test里test相关的代码,也有人喜欢单独开个工程做test,这个看实际情况和当时情况,tools里相关的辅助类,我放了一个utiles类,里面会不断扩充辅助函数,让我们写代码能轻松点。

主界面已经完成了,看看main_scene.cpp,里面有几个知识点(写代码的时候,老板在旁边说事情,胆战心惊,难免有写的不规范的地方,大家莫喷)

bool MainLayer::init(){
if(!cocos2d::CCLayer::init()){
returnfalse;
    }
    cocos2d::CCSize win_size=cocos2d::CCDirector::sharedDirector()->getWinSize();
//缓存图片
    cocos2d::CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("mainscene1.plist");
//背景
    cocos2d::CCSprite* bg=cocos2d::CCSprite::createWithSpriteFrameName("mainbg.png");
this->addChild(bg,-1);
    bg->setPosition(ccp(win_size.width/2,win_size.height/2) );
//大云
    cocos2d::CCSprite* cloud2=cocos2d::CCSprite::createWithSpriteFrameName("cloud2.png");
this->addChild(cloud2,-1);
    cloud2->setPosition(ccp( win_size.width*0.75,win_size.height*0.8   ));
    cocos2d::CCMoveTo* move1=cocos2d::CCMoveTo::create(20,ccp(win_size.width+cloud2->getContentSize().width/2,win_size.height*0.8));
    cocos2d::CCMoveTo* move2=cocos2d::CCMoveTo::create(0,ccp(-cloud2->getContentSize().width/2,win_size.height*0.8));
    cocos2d:: CCSequence* seq1  = cocos2d:: CCSequence::create(move1, move2, NULL);
    cocos2d::CCAction* rep1     =  cocos2d::CCRepeatForever::create(seq1);
    cloud2->runAction(rep1);
//小云
    cocos2d::CCSprite* cloud1=cocos2d::CCSprite::createWithSpriteFrameName("cloud1.png");
this->addChild(cloud1,-1);
    cloud1->setPosition(ccp(win_size.width/2,win_size.height/2) );
    cloud1->setPosition(ccp( win_size.width*0.25,win_size.height*0.75   ));
    move1=cocos2d::CCMoveTo::create(15,ccp(win_size.width+cloud1->getContentSize().width/2,win_size.height*0.75 ));
    move2=cocos2d::CCMoveTo::create(0,ccp(-cloud1->getContentSize().width/2,win_size.height*0.75 ));
    seq1  = cocos2d:: CCSequence::create(move1, move2, NULL);
    rep1     =  cocos2d::CCRepeatForever::create(seq1);
    cloud1->runAction(rep1);
//萝卜节点
    cocos2d::CCNode* carrot_node=cocos2d::CCNode::create();
this->addChild(carrot_node);
    carrot_node->setPosition(ccp(win_size.width/2,win_size.height/2-60) );
    carrot_node->setScale(0.3);
    cocos2d::CCScaleTo* scale_to=cocos2d::CCScaleTo::create(0.2,1);
    carrot_node->runAction(scale_to);
//萝卜
    cocos2d::CCSprite* carrot=cocos2d::CCSprite::createWithSpriteFrameName("carrot.png");
    carrot_node->addChild(carrot);
    carrot->setAnchorPoint(ccp(0.5,0));
    carrot->setPosition(ccp(0,0) );
//三片叶子
    cocos2d::CCSprite* leaf1=cocos2d::CCSprite::createWithSpriteFrameName("leaf-1.png");
    carrot_node->addChild(leaf1,-1);
    leaf1->setAnchorPoint(ccp(1,0));
    leaf1->setPosition(ccp(0,carrot->getPositionY()+150) );
    cocos2d::CCSprite* leaf3=cocos2d::CCSprite::createWithSpriteFrameName("leaf-3.png");
    carrot_node->addChild(leaf3,-1);
    leaf3->setAnchorPoint(ccp(0,0));
    leaf3->setPosition(ccp(0,carrot->getPositionY()+150) );
int delay_time=10;
    cocos2d::CCRotateBy* route1=cocos2d::CCRotateBy::create(0.1,30);
    cocos2d::CCActionInterval* route1_bac = route1->reverse();
    cocos2d::CCRotateBy* route2=cocos2d::CCRotateBy::create(0.1,20);
    cocos2d::CCActionInterval* route2_bac = route2->reverse();
    cocos2d::CCDelayTime* delay=cocos2d::CCDelayTime::create(delay_time);
    seq1  = cocos2d:: CCSequence::create(delay,route1,route1_bac, route2,route2_bac, NULL);
    rep1     =  cocos2d::CCRepeatForever::create(seq1);
    leaf3->runAction(rep1);
    cocos2d::CCSprite* leaf2=cocos2d::CCSprite::createWithSpriteFrameName("leaf-2.png");
    carrot_node->addChild(leaf2,-1);
    leaf2->setAnchorPoint(ccp(0.5,0));
    leaf2->setPosition(ccp(0,carrot->getPositionY()+150) );
    route1=cocos2d::CCRotateBy::create(0.1,30);
    route1_bac = route1->reverse();
    route2=cocos2d::CCRotateBy::create(0.1,20);
    route2_bac = route2->reverse();
    cocos2d::CCDelayTime* delay1=cocos2d::CCDelayTime::create(delay_time/2);
    cocos2d::CCDelayTime* delay2=cocos2d::CCDelayTime::create(delay_time/2);
    seq1  = cocos2d:: CCSequence::create(delay1,route1,route1_bac, route2,route2_bac,delay2, NULL);
    rep1     =  cocos2d::CCRepeatForever::create(seq1);
    leaf2->runAction(rep1);
//标题
    cocos2d::CCSprite* title=cocos2d::CCSprite::createWithSpriteFrameName("mainbg_CN.png");
this->addChild(title);
    title->setPosition(ccp(win_size.width/2,win_size.height/2) );
//鸟
    cocos2d::CCSprite* bird=cocos2d::CCSprite::createWithSpriteFrameName("bird.png");
this->addChild(bird);    
    bird->setPosition(ccp(win_size.width/2-300,win_size.height/2+150) );
    cocos2d::CCMoveBy* move=cocos2d::CCMoveBy::create(2,ccp(0,-50));    
    cocos2d::CCActionInterval* move_back = move->reverse();
    cocos2d:: CCSequence* seq  = cocos2d:: CCSequence::create(move, move_back, NULL);
    cocos2d::CCAction* rep     =  cocos2d::CCRepeatForever::create(seq);
    bird->runAction(rep);
//菜单
    cocos2d::CCMenu* menu=cocos2d::CCMenu::create();
this->addChild(menu);
    menu->setPosition(ccp(0,0));
//开始按钮
    cocos2d::CCSprite* btn_adventure_normal=cocos2d::CCSprite::createWithSpriteFrameName("btn_adventure_normal_CN.png");
    cocos2d::CCSprite* btn_adventure_pressed=cocos2d::CCSprite::createWithSpriteFrameName("btn_adventure_pressed_CN.png");
    cocos2d::CCMenuItemSprite* btn_adventure=cocos2d::CCMenuItemSprite::create(btn_adventure_normal,btn_adventure_pressed);
    menu->addChild(btn_adventure);
    btn_adventure->setPosition(ccp(win_size.width/2,btn_adventure->getContentSize().height/2+10));
//测试按钮
    btn_adventure->setTarget(this,menu_selector(MainLayer::BtnStartCallback));
    cocos2d::CCMenuItemSprite*  test_btn=GCreateBtnWithFrameSprite("weiboicon01_normal.png","weiboicon01_press.png");
    menu->addChild(test_btn);
    test_btn->setPosition(ccp(win_size.width*0.1,win_size.height*0.9));
    test_btn->setTarget(this, menu_selector(MainLayer::BtnTestCallback));
returntrue;
}

我们创建一个精灵,之前都是用cocos2d::CCSprite::create(图片名)这个接口,

其实还有cocos2d::CCSprite::create(图片名,对应图片区域中的位置)

这个接口,它会创建一个精灵,这个精灵对应的绘制纹理是图片中的指定区域,用它我们可以把许多小图合成一张大图,在创建精灵时指定图片中的区域来创建精灵。

在这个基础上就有了CCSpriteFrame这个概念,这个类是对图片切片的描述。通过它,我们可以定位一张图片纹理,以及其中对应的一块区域信息 。

而代码中的
cocos2d::CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("mainscene1.plist");

是通过文件,读取多数量的切片信息,将其缓存起来,意思就是读取”mainscene1.plist”文件缓存切片信息

之后我们可以通过

cocos2d::CCSprite* bg=cocos2d::CCSprite::createWithSpriteFrameName("mainbg.png");

这个函数来创建精灵,意思是通过名叫”mainbg.png”的切片信息创建纹理,这个切片信息是从之前的plist文件读进来的。

一般做游戏到后来,利用切片节省空间是很常见的,之后如果要做切片动画,也得用这个机制。毕竟在游戏包里散落几百个小碎图不是什么光彩的事。

第二个知识点在于按钮的创建

//开始按钮
    cocos2d::CCSprite* btn_adventure_normal=cocos2d::CCSprite::createWithSpriteFrameName("btn_adventure_normal_CN.png");
    cocos2d::CCSprite* btn_adventure_pressed=cocos2d::CCSprite::createWithSpriteFrameName("btn_adventure_pressed_CN.png");
    cocos2d::CCMenuItemSprite* btn_adventure=cocos2d::CCMenuItemSprite::create(btn_adventure_normal,btn_adventure_pressed);
    menu->addChild(btn_adventure);
    btn_adventure->setPosition(ccp(win_size.width/2,btn_adventure->getContentSize().height/2+10));

注意看,这是另外一种按钮的创建方法,传入2个精灵,来构建一个按钮。分辨是平时和按下的显示,我把这个函数在utiles里做了封装

#include "utiles.h"
cocos2d::CCMenuItemSprite* GCreateBtnWithFrameSprite(constchar *normalFrameName,constchar *pressedFrameName ){
    cocos2d::CCSprite* btn_normal=cocos2d::CCSprite::createWithSpriteFrameName(normalFrameName);
    cocos2d::CCSprite* btn_pressed=cocos2d::CCSprite::createWithSpriteFrameName(pressedFrameName);
    cocos2d::CCMenuItemSprite* btn=cocos2d::CCMenuItemSprite::create(btn_normal,btn_pressed);
return btn;
}
cocos2d::CCMenuItemSprite* GCreateBtnText(constchar *text ){
    cocos2d::CCSprite* btn_normal=cocos2d::CCSprite::createWithSpriteFrameName("NT-1.png");
    cocos2d::CCLabelTTF* label_normal=cocos2d::CCLabelTTF::create(text,"Marker Felt.ttf",50);
    btn_normal->addChild(label_normal);
    label_normal->setPosition(ccp(btn_normal->getContentSize().width/2,btn_normal->getContentSize().height/2));
    cocos2d::CCSprite* btn_pressed=cocos2d::CCSprite::createWithSpriteFrameName("NT-2.png");
    cocos2d::CCLabelTTF* label_press=cocos2d::CCLabelTTF::create(text,"Marker Felt.ttf",50);
    btn_pressed->addChild(label_press);
    label_press->setPosition(ccp(btn_pressed->getContentSize().width/2,btn_pressed->getContentSize().height/2));
    cocos2d::CCMenuItemSprite* btn=cocos2d::CCMenuItemSprite::create(btn_normal,btn_pressed);
return btn;
}

这就封装了2个方便我们创建按钮的函数。以后也可以用。

第三个知识点是强化对action的运用。如果你有编译运行这份代码,会注意到,我们主界面的元素是动态的,首先,左边的小鸟一直在上下飞。

实现代码如下

//鸟
    cocos2d::CCSprite* bird=cocos2d::CCSprite::createWithSpriteFrameName("bird.png");
this->addChild(bird);    
    bird->setPosition(ccp(win_size.width/2-300,win_size.height/2+150) );
    cocos2d::CCMoveBy* move=cocos2d::CCMoveBy::create(2,ccp(0,-50));    
    cocos2d::CCActionInterval* move_back = move->reverse();
    cocos2d:: CCSequence* seq  = cocos2d:: CCSequence::create(move, move_back, NULL);
    cocos2d::CCAction* rep     =  cocos2d::CCRepeatForever::create(seq);
    bird->runAction(rep);

move 是一个向下移动50像素的动作

而move_back是通过move->reverse()取得的相反动作,也就是向上移动50像素

cocos2d:: CCSequence* seq = cocos2d:: CCSequence::create(move, move_back, NULL);

seq是个组合动作,创建函数是(动作1,动作2,动作3……NULL结尾),它能让精灵按顺序执行一个有一个连续动作

而cocos2d::CCAction* rep = cocos2d::CCRepeatForever::create(seq);则是通过seq创建出一个循环动作,它让精灵重复的执行一个动作

之后runaction就看到我们的小鸟一直在屏幕里上下移动了。

类似的我们还实现了云彩的不断右移

以及萝卜叶子每过5秒左右颤抖一下的效果。大家可以自己看下。

这篇博写的比较急,大家有不明白的地方可以给我留言,我会尽快修改。

主界面有2个按钮,一个是开始游戏的按钮,现在没实现,另一个是左上角的新浪微博,通过它,我们进入测试场景,进行单元测试。之后大概2篇博文的时间

,我们在里面实现我们的动画类的雏形。

先把这篇发上来,测试一下我新装的代码插件好不好用.

转载于:https://blog.51cto.com/luoposhusheng/1328095

书生教你cocos2d-x-保卫萝卜(一)相关推荐

  1. 书生教你cocos2d-x-保卫萝卜(二)

    书生教你cocos2d-x-保卫萝卜(二) 上一章搭建了主界面.这一章开始,我们构建游戏里要用的动画类.动画是游戏开发里很重要的一个概念,可惜的是公司不会安排一个新人去写这一块.许多新人朋友接手代码的 ...

  2. 计算机乘法公式多列,书生妙招:一招轻松搞定Excel多列数据乘积后求和问题-excel乘法公式...

    大家在日常工作中经常会遇到多列数据乘积后求和的问题,如图1所示,计算"数列1x数列2"后的总和,甚至需要计算"数列1x数列2x数列3"后的总和. 图1 我们一般 ...

  3. 古代名言名句 汉魏南北朝

    百川东到海,何时复西归.少壮不努力,老大徒伤悲.--<汉乐府·长歌行>  [解读]时间像江河向东流入大海,一去不复返:人在年轻时不努力学习,年龄大了一事无成,那就只好空留悲伤.后悔.人生积 ...

  4. 形象思维法与抽象思维法

    综合运用形象思维法和抽象思维法有助子促进大脑两半球功能平衡协作发展,能大大提高学习能力和效率. 心理学家认为,人类的大脑是个生物学的超级电子计算机,而对它非凡功能的认识,只不过刚刚跨进这个领域的门坎. ...

  5. 技术博客2013年11月份头条记录

    =============11.29-11.30头条回顾============ Hadoop完整安装配置 [Hadoop专业解决方案之构建Hadoop企业级应用][Hadoop运维全记录] [从库宕 ...

  6. 译文1 手把手教你用cocos2d开发iphone游戏

    手把手教你用cocos2d开发iphone游戏-译文1 (2011-07-07 16:37:00) Learning Cocos2d – A Hands On Guide to Building iO ...

  7. 手把手教你用cocos2d开发iphone游戏-译文1

    Learning Cocos2d – A Hands On Guide to Building iOS Gaming 说明:本书的英文版美国当地时间7月8日出版,译文基于该书的Rough Cut版本( ...

  8. 【Cocos2d实例教程一】xcode5下Cocos2d环境的搭建

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 第一步,现在要安装集成环境xcode5,安装xcode5需要系统至少是os x 10.8.5. 第二步,下载co ...

  9. cocos2d之教你画一条直线

    我们画一条直线用到的是CCDrawLine,代码如下: void MyLineLayerBase::initLayer() { CCSize size = CCDirector::sharedDire ...

最新文章

  1. 注意力机制-深度学习中的注意力机制+注意力机制在自然语言处理中的应用
  2. 穿墙透视真的来了!MIT华人团队超强动作检测模型,小黑屋照样夜视
  3. Java编程书籍收集(高级)
  4. 内外网切换BAT脚本
  5. 计算机二级1px等于多少厘米,px和pt换算(1px等于多少pt)
  6. 4招教你们怎么做海报,想要宣传推广就来这
  7. FineReport中cjk编码转换
  8. nodejs高速公路收费管理系统vue
  9. Java 获取网络url图片返回file文件对象
  10. 计算机函数countifs使用,countifs函数(countifs使用方法举例)
  11. 面经手册 · 第1篇《认知自己的技术栈盲区》
  12. 5款OCR文字识别软件推荐_分享好用的OCR(图片转文字)工具
  13. 华为OD机试真题 Python 实现【机器人】【100%通过率】【2022.11 Q4 新题】
  14. 中医针灸学综合练习题库【5】
  15. java GUI实现记事本
  16. “笨办法”学Python3,Zed A. Shaw,习题21
  17. 光流文件(.flo)转成图片(.png)
  18. 腾讯汤道生:践行“科技向善”,推动可持续社会价值创新
  19. PTA 线性表 7-1 约瑟夫环(Josephus)问题(by Yan) (100分) 按出列次序输出每个人的编号
  20. 记事本编写java代码出现中文乱码

热门文章

  1. 开发、部署第一个去中心化应用(Dapp) - 宠物商店
  2. Fiddler对安卓应用手机抓包图文教程
  3. java-php-python-ssm腾讯网游辅助小助手计算机毕业设计
  4. shell02:必须要会的辅助(awk)
  5. 风电机组的预测性维护应该如何进行?
  6. 合并类游戏模板Demo
  7. 影响网络购物公平 潜藏信息安全隐患
  8. 电脑Windows7系统上的appdata是什么文件夹
  9. JavaScript读取元素当前css样式——解决currentStyle不兼容问题
  10. 使用OpenCV进行实时车道检测