转自:http://www.cnblogs.com/hll2008/p/4235714.html

一、前提:

完成Hello Game项目的创建编译。

具体参考:Cocos2dx.3x_Hello Game项目创建篇

二、本篇目标:

l 说说关于塔防游戏的想法和思路

l 实现一个简单的塔防游戏原型

三、内容:

l 说说关于塔防游戏的想法和思路

首先上一张塔防游戏PSD设计效果图

游戏故事设定:

这个游戏说是保卫萝卜,但不能真的是保卫萝卜了,因为保卫萝卜的游戏已经有了,只是借用一下这个大名鼎鼎的塔防游戏宣传和参照一下。现在网络上主流游戏都会先讲一下故事让玩家有一种入戏感,那我们的这个故事是这样的:很久很久以前,在美丽的大学宿舍区住着一群美丽天真的女孩,但是邪恶的色狼大叔们总想对她们做一些坏事,那么我们的英雄善良勇敢的女生宿舍管理员利用生活中的武器菜刀、皮鞋、玩具飞机等在大叔必经的路上狙击他们,保护女孩们免受这些大叔的伤害。

游戏元素组成:

1、地图:每一关地图均不相同,主要是道路不同和炮台位的不同。

2、炮塔:水果刀、菜刀、老鼠药、高跟鞋、玩具飞机等,不同的炮台具备不同的价格、攻击速度、攻击属性、攻击方式。

3、子弹:由炮台发射的,具备不同的攻击值、扩散值、迟缓值、攻击范围值等。

4、怪物:各类猥琐大叔、叫兽、色狼,不同的色狼具备不同的速度值、伤害值、耐揍值,沿着地图上的道路不断的靠近道路终点的女主角。

5、女主角:道路终点的女孩,不具备攻击力需要炮塔的保护,具有一定的纯洁值,当纯洁值被大叔玷污光了就自杀了,游戏也就结束了。

6、分数&资源:杀死不同的色狼能获得一定的分数,分数可以用来购买新的炮台,每一关都会有一定的初始分数用来支撑游戏最初的消耗,每一关的分数只限在本关使用,下一关开启时前面积累的分数清空。

7、宝箱:用分数资源购买宝箱,能有一定几率获得比投入分数几倍的回报。

8、医生:用分数购买医疗,对女主角的纯洁值进行修补。

游戏开发模式:

整个游戏开发的方式是这样,首先实现一个很小的游戏核心原型,然后不断的修改扩大这个游戏原型直至游戏完成为止。本人认为这样的方式比较适合读者理解,并且跟着文章自己学会理解这个游戏的开发。

l 实现一个简单的游戏原型

新建游戏工程名为DefendTheGirl(保卫女孩),包名为:com.game. defendthegirl。如果还不会创建工程请参照:Cocos2dx.3x入门三部曲-Hello Game项目创建(二)篇

本篇原型需要实现内容:

1、 在主场景中载入一张地图。

2、 在地图终点放置一个女主角,在地图的起点放置一个色狼大叔。

3、 让色狼大叔沿着地图指定的路线向女主角的位置靠近。

素材图片准备:

地图图片level_bg_1.png 960px,640px

女主角图片 girl.png

色狼大叔图片 dashu.png

把这几张素材图片拷贝到文件夹Resources下面即可

1、在主场景中载入一张地图

第一步:

用Microsoft Visual Studio 2012打开proj.win32工程,然后在src下新建MainScene.h、MainScene.cpp作为游戏的主场景(Scene不会建?参考:Cocos2dx.3x入门三部曲-Hello Game项目解析(三)篇)。

第二步:在init()方法里载入地图图片level_bg_1.png,代码如下:

bool MainScene::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
    //载入地图背景
    auto sprite = Sprite::create("level_bg_1.png");
    sprite->setPosition(Vec2(visibleSize.width/2 + origin.x,visibleSize.height/2 + origin.y));
    this->addChild(sprite,0);
    true;
}

第三步:打开AppDelegate.cpp文件,引入MainScene.h头文件,并且在applicationDidFinishLaunching方法中把auto scene = HelloWorld::createScene(); 改成auto scene = MainScene::createScene();然后运行。

2、在地图终点放置一个女主角,在地图的起点放置一个色狼大叔

第一步:在init()方法里添加如下代码

载入地图背景 …… auto sprite = Sprite::create(0); 在地图起点处放置一个色狼 auto dssprite = Sprite::create(dashu.png"); dssprite->setPosition(Vec2(40,128); line-height:1.5!important">390)); this->addChild(dssprite,0); line-height:1.5!important">在地图终点处放置一个女主角 auto nhSprite = Sprite::create(girl.png"); nhSprite->setPosition(Vec2(920,128); line-height:1.5!important">480)); this->addChild(nhSprite,128); line-height:1.5!important">0); …...

第二步:然后运行就可以在画面上看到色狼大叔和女主角了

1、让色狼大叔沿着地图指定的路线向女主角的位置靠近

这个一个有点难度的任务,首先我们对这张地图的道路路径进行一下坐标分析:

如上图所示,以地图的右下顶点为坐标系原点,整个道路分成12个坐标点,女主角在1号坐标点,色狼大叔在12号坐标点。现在色狼大叔将沿着图中黄色的线路从12点开始 11点、10点、9点…直至到达1点,我的实现思路是这样,色狼从12点出发时告诉它目标点是11点,当色狼到达11点的时候继续告诉它下一个目标点是10点直到1点。

几个实现技术点:

1、 对Sprite(色狼)进行setPosition的方式可以改变Sprite在图上的位置从而实现Sprite的移动

2、 计算Sprite(色狼)位置到目标点的向量值,然后根据这个向量值和色狼移动速度计算Sprite在x,y方向上的距离偏移值,用这个偏移值调整Sprite的位置

判断Sprite(色狼)到达目标点(如:11点),如下图所示通过Sprite坐标点和目标点之间的距离小于一定值的时就判定为到达目标点,需要设置新的下一个目标点。

有了这些实现思路,现在开始代码编写:

第一步:由上面是实现思路可知我们的基本实现是路径点,那么这里先新建一个路径点类对象,名称为:Waypoint.h、Waypoint.cpp,继承自:cocos2d::CCNode。

Waypoint.h:

class Waypoint: public cocos2d::CCNode { public: Waypoint(void); ~Waypoint(void); 初始化方法 static Waypoint* nodeWithTheLocation(cocos2d::Point location); bool initWithTheLocation(cocos2d::Point location); 设置当前点的下一个路径点 void setNextWaypoint(Waypoint* waypoint); 获取当前点的下一个路径点 Waypoint* getNextWaypoint(); 当前路径点位置 CC_SYNTHESIZE(cocos2d::Point,_myPosition,MyPosition); private: 下一个路径点 Waypoint* _nextWaypoint; }; Waypoint.cpp: Waypoint::Waypoint(void) { _nextWaypoint=NULL; } Waypoint::~Waypoint(void) { } Waypoint* Waypoint::nodeWithTheLocation(cocos2d::Point location) { Waypoint* pRet=new Waypoint(); if (pRet && pRet->initWithTheLocation(location)) { pRet->autorelease(); return pRet; } else { delete pRet; pRet=NULL; return NULL; } } bool Waypoint::initWithTheLocation(cocos2d::Point location) { bool bRet=false; do { _myPosition=location; this->setPosition(Point::ZERO); bRet=true; } while (return bRet; } void Waypoint::setNextWaypoint(Waypoint* waypoint) { _nextWaypoint=waypoint; } Waypoint* Waypoint::getNextWaypoint() { return _nextWaypoint; }

第二步:在MainScene.h里声明如下代码

public: …… 重写Layer的update方法 我们主要在这个方法里实现色狼移动 virtual void update(float delta); CREATE_FUNC(MainScene); 路径开始点 Waypoint *beginningWaypoint; 路径目标点 Waypoint *destinationWaypoint; 色狼的移动速度 float walkingSpeed; 色狼当前位置 cocos2d::Vec2 myPosition; 色狼大叔 cocos2d::Sprite* dssprite; 路径点集合 cocos2d::Vector<Waypoint*> wayPositions; 判断2个点是否靠近 bool collisionWithCircle(cocos2d::Vec2 circlePoint,float radius,cocos2d::Vec2 circlePointTwo,255); line-height:1.5!important">float radiusTwo);

这里代码,也对之前代码进行了修改重构,比如把之前在init()方法里声明的dssprite(色狼)改到了这里变成了一个全局变量,因为在后续的update方法中需要对它进行操作。

第二步:在MainScene.cpp的init()方法中创建路径点集合编写如下代码

……

//获得色狼大叔的高
float dsh=dssprite->getTextureRect().size.height;

初始化地图路径点集合
    this->wayPositions = Vector<Waypoint*>();

    添加地图1号路径点到集合中
    Waypoint *waypoint1=Waypoint::nodeWithTheLocation(Point(435+dsh/2.0f));
    if(this->wayPositions.size()>0)
    {
        设置下一个节点
        waypoint1->setNextWaypoint(this->wayPositions.back());
    }
    this->wayPositions.pushBack(waypoint1);
    添加地图2号路径点到集合中
    Waypoint *waypoint2=Waypoint::nodeWithTheLocation(Point(762,128); line-height:1.5!important">0)
    {
        waypoint2->setNextWaypoint(this->wayPositions.pushBack(waypoint2);
    添加地图3号路径点到集合中
    Waypoint *waypoint3=Waypoint::nodeWithTheLocation(Point(360+dsh/0)
    {
        waypoint3->setNextWaypoint(this->wayPositions.pushBack(waypoint3);
    添加地图4号路径点到集合中
    Waypoint *waypoint4=Waypoint::nodeWithTheLocation(Point(685,128); line-height:1.5!important">0)
    {
        waypoint4->setNextWaypoint(this->wayPositions.pushBack(waypoint4);
    添加地图5号路径点到集合中
    Waypoint *waypoint5=Waypoint::nodeWithTheLocation(Point(116+dsh/0)
    {
        waypoint5->setNextWaypoint(this->wayPositions.pushBack(waypoint5);
    添加地图6号路径点到集合中
    Waypoint *waypoint6=Waypoint::nodeWithTheLocation(Point(520,128); line-height:1.5!important">0)
    {
        waypoint6->setNextWaypoint(this->wayPositions.pushBack(waypoint6);
    添加地图7号路径点到集合中
    Waypoint *waypoint7=Waypoint::nodeWithTheLocation(Point(180+dsh/0)
    {
        waypoint7->setNextWaypoint(this->wayPositions.pushBack(waypoint7);
    添加地图8号路径点到集合中
    Waypoint *waypoint8=Waypoint::nodeWithTheLocation(Point(285,128); line-height:1.5!important">0)
    {
        waypoint8->setNextWaypoint(this->wayPositions.pushBack(waypoint8);
    添加地图9号路径点到集合中
    Waypoint *waypoint9=Waypoint::nodeWithTheLocation(Point(268+dsh/0)
    {
        waypoint9->setNextWaypoint(this->wayPositions.pushBack(waypoint9);
    添加地图10号路径点到集合中
    Waypoint *waypoint10=Waypoint::nodeWithTheLocation(Point(204,128); line-height:1.5!important">0)
    {
        waypoint10->setNextWaypoint(this->wayPositions.pushBack(waypoint10);
    添加地图11号路径点到集合中
    Waypoint *waypoint11=Waypoint::nodeWithTheLocation(Point(350+dsh/0)
    {
        waypoint11->setNextWaypoint(this->wayPositions.pushBack(waypoint11);
    添加地图12号路径点到集合中
    Waypoint *waypoint12=Waypoint::nodeWithTheLocation(Point(50,128); line-height:1.5!important">0)
    {
        waypoint12->setNextWaypoint(this->wayPositions.pushBack(waypoint12);
……

第三步:在MainScene.cpp的init()方法中初始化几个变量以及精灵的初始位置编写如下代码

 ……
   获取集合中的最后一个点,12号点
    Waypoint *waypoint0=wayPositions.back();
    设置运动的开始点
    beginningWaypoint=waypoint0;
    设置运动的目标点为12号点的下一个点,11号点
    destinationWaypoint=waypoint0->getNextWaypoint();
    设置色狼当前位置值
    myPosition=waypoint0->getMyPosition();
    设置色狼在地图的初始位置
    dssprite->setPosition(myPosition);
    设置女主角在地图的初始位置,为集合中的1号点
    nhSprite->setPosition(wayPositions.front()->getMyPosition());
设置移动速度
    this->walkingSpeed=0.2f;
    定时器
    this->scheduleUpdate();
……

第四步:在MainScene.cpp中对collisionWithCircle方法进行实现编写如下代码

判断2个圆点是否靠近 circlePoint:第一个圆点坐标 radius:第一个圆半径 circlePointTwo:第二个圆点坐标 radiusTwo:第二个圆半径 bool MainScene::collisionWithCircle(cocos2d::Vec2 circlePoint,255); line-height:1.5!important">float radiusTwo) { 2点间距离公式计算 float xdif = circlePoint.x - circlePointTwo.x; float ydif = circlePoint.y - circlePointTwo.y; float distance = sqrt(xdif * xdif + ydif * ydif); if(distance <= radius + radiusTwo) { true; } false; }

第五步:在MainScene.cpp中对update方法进行实现:

判断色狼大叔是否和目标点碰到 if (this->collisionWithCircle(myPosition,128); line-height:1.5!important">1,destinationWaypoint->getMyPosition(),128); line-height:1.5!important">1) ) { 是否还有下一个目标点 if (destinationWaypoint->getNextWaypoint()) { 重新设定开始点和目标点 beginningWaypoint=destinationWaypoint; destinationWaypoint=destinationWaypoint->getNextWaypoint(); } } 获取目标点的坐标 Point targetPoint=destinationWaypoint->getMyPosition(); 计算目标点的向量 Point normalized=Point(targetPoint.x-myPosition.x,targetPoint.y-myPosition.y).getnormalized(); 根据速度和向量分别计算x,y方式上的偏移值 float ox=normalized.x * walkingSpeed; float oy=normalized.y *walkingSpeed; myPosition = Point(myPosition.x + ox,myPosition.y +oy); 重新设定色狼的位置实现移动 dssprite->setPosition(myPosition);

第六步:运行测试游戏效果,看看色狼会不会沿着我们设定的路径移动。

Windows下的效果

在看看android手机下的效果,把新加的2个cpp文件添加到Android.mk文件里然后开始编译打包so文件(不会请参考:Cocos2dx.3x入门三部曲-Hello Game项目解析(三)篇)。完成打包后在eclipse中连接手机运行看到如下效果:

发现在真机上运行时女主角、色狼的位置相当于道路都有点偏上了,并且好像背景地图也没有显示全背景的顶部和底部有一部分没有显示出来,但是在windows下运行确正常,这个是什么原因呢,该怎么调整呢?我的手机分辨率是:960x540 而我们的地图素材图片分辨率是:960x640,所以导致了这个问题,这个是关于不同手机屏幕分辨率适配问题,在下一篇中我们将继续的完善修改这个游戏原型解决这个问题。

作者交流QQ:2303452599

邮箱:mymoney1001@126.com

Cocos2d-x3.x塔防游戏保卫萝卜从零开始(一)的更多相关文章

  1. 详解HTML5中CSS外观属性

    这篇文章主要介绍了HTML5中CSS外观属性的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,,需要的朋友可以参考下

  2. Swift HTTP请求集合

    )->Voidinprintln})带参数的get请求varrequest=HTTPTask()request.GET("http://google.com",parameters:["param":"param1","array":["firstarrayelement","second","third"],"num":23],arial;font-size:14px;line-height:21px">println("response:\(response.responSEObject!)")POS

  3. swift 创建cocoapod

    Butwhenyou’redevelopingyourownCocoaPod,youwillinsteadspecifyalocalpath,likethis:Therearetwobenefitstothisapproach:Itusesthelocalfilesonyourmachineforthepod,insteadoffetchingthemfromaremoterepository.n

  4. Swift - 文件,文件夹操作大全

    ios开发经常会遇到读文件,写文件等,对文件和文件夹的操作,这时就可以使用NSFileManager,NSFileHandle等类来实现。)//contentsOfPath:Optionalprint//类似上面的,对指定路径执行浅搜索,返回指定目录路径下的文件、子目录及符号链接的列表contentsOfURL=try?important;font-family:Consolas,options:NSDirectoryEnumerationoptionsSkipsHiddenFiles);//conten

  5. Swift - 使用表格组件UITableView实现单列表

    2,效果图3,单元格复用机制:由于普通的表格视图中对的单元格形式一般都是相同的,所以本例采用了单元格复用机制,可以大大提高程序性能。实现方式是初始化创建UITableView实例时使用registerClass创建一个可供重用的UITableViewCell。并将其注册到UITableView,ID为SwiftCell。下次碰到形式(或结构)相同的单元就可以直接使用UITableView的dequeueReusableCellWithIdentifier方法从UITableView中取出。.dataSou

  6. Swift - 使用表格组件UITableView实现分组列表

    1,样例说明:列表以分组的形式展示同时还自定义分区的头部和尾部点击列表项会弹出消息框显示该项信息。overridefuncloadView(){super.loadView()}viewDidLoad(){.viewDidLoad()//初始化数据,这一次数据,我们放在属性列表文件里self.allnames=[0:[String](["UILabel标签"ottom:auto!important;font-family:Consolas,"UITableView表格视图"])];print.adHead

  7. Swift - 给表格的单元格UITableViewCell添加图片,详细文本标签

    表格UITableView中,每一单元格都是一个UITableViewCell。其支持简单的自定义,比如在单元格的内部,添加图片和详细文本标签。注意UITableViewCell的style:UITableViewCellStyle.Default:默认的,只有一个常规内容标签和一个可选的UIImageViewUITableViewCellStyle.Value1:内容标签在左,详细标签在右,右边是蓝色或灰色的文本UITableViewCellStyle.Value2:同Value1位置相同,左边是蓝色文

  8. Swift - 给表格添加编辑功能删除,插入

    overridefuncloadView(){super.loadView()}viewDidLoad(){.viewDidLoad()//初始化数据,这一次数据,我们放在属性列表文件里self.allnames=[0:[](["UILabel标签"ottom:auto!important;font-family:Consolas,"UITableView表格视图"])];print.adHeaders=["常见UIKit控件"ottom:auto!important;font-family:Consol

  9. Swift - 使用导航条和导航条控制器来进行页面切换

    下面通过一个简单“组件效果演示”的小例子来说明如何通过代码来进行页面的切换。)->Bool{//把起始ViewController作为导航控件封装,我们在ViewController里就能调用导航条进行页面切换了letrootViewController=ViewController()letrootNavigationController=UINavigationControllerself.window!.rootViewController=rootNavigationControllerretur

  10. Swift - 使用UIWebView和UIToolbar制作一个浏览器

    //进度条计时器ptimer:NSTimer!overridefuncviewDidLoad(){super.viewDidLoad()//Doanyadditionalsetupafterloadingtheview,typicallyfromanib.self.webview.delegate=;loadindicator=;loadindicator.activityIndicatorViewStyle=UIActivityIndicatorViewStyle.Gray.view.addSubvie

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部