一、前提:

完成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/ + origin.x, visibleSize.height/ + origin.y));
this->addChild(sprite, );
return true;
}

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

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

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

//载入地图背景
……
auto sprite = Sprite::create("level_bg_1.png");
sprite->setPosition(Vec2(visibleSize.width/ + origin.x, visibleSize.height/ + origin.y));
this->addChild(sprite, ); //在地图起点处放置一个色狼
auto dsSprite = Sprite::create("dashu.png");
dsSprite->setPosition(Vec2(, ));
this->addChild(dsSprite, ); //在地图终点处放置一个女主角
auto nhSprite = Sprite::create("girl.png");
nhSprite->setPosition(Vec2(, ));
this->addChild(nhSprite, );
…...

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

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); private:
//路径开始点
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, float radiusTwo);

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

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

……

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

//初始化地图路径点集合
this->wayPositions = Vector<Waypoint*>(); //添加地图1号路径点到集合中
Waypoint *waypoint1=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
//设置下一个节点
waypoint1->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint1);
//添加地图2号路径点到集合中
Waypoint *waypoint2=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
waypoint2->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint2);
//添加地图3号路径点到集合中
Waypoint *waypoint3=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
waypoint3->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint3);
//添加地图4号路径点到集合中
Waypoint *waypoint4=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
waypoint4->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint4);
//添加地图5号路径点到集合中
Waypoint *waypoint5=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
waypoint5->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint5);
//添加地图6号路径点到集合中
Waypoint *waypoint6=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
waypoint6->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint6);
//添加地图7号路径点到集合中
Waypoint *waypoint7=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
waypoint7->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint7);
//添加地图8号路径点到集合中
Waypoint *waypoint8=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
waypoint8->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint8);
//添加地图9号路径点到集合中
Waypoint *waypoint9=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
waypoint9->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint9);
//添加地图10号路径点到集合中
Waypoint *waypoint10=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
waypoint10->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint10);
//添加地图11号路径点到集合中
Waypoint *waypoint11=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
waypoint11->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint11);
//添加地图12号路径点到集合中
Waypoint *waypoint12=Waypoint::nodeWithTheLocation(Point(, +dsh/2.0f));
if(this->wayPositions.size()>)
{
waypoint12->setNextWaypoint(this->wayPositions.back());
}
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,float radius,cocos2d::Vec2 circlePointTwo, 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)
{
return true;
}
return false;
}

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

//判断色狼大叔是否和目标点碰到
if (this->collisionWithCircle(myPosition,,destinationWaypoint->getMyPosition(),) )
{
//是否还有下一个目标点
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:

           邮箱:mymoney1001@126.com

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

  1. Cocos2d-x3.x塔防游戏(保卫萝卜)从零开始(三)

    一.前提: 完成前一篇的内容. 具体参考:Cocos2d-x3.x塔防游戏(保卫萝卜)从零开始(二)篇 二.本篇目标: l  说说游戏中各种角色的动作.属性以及重构思路 l  进行代码重构让色狼大叔和 ...

  2. Cocos2d-x3.x塔防游戏(保卫萝卜)从零开始(二)

    一.前提: 完成前一篇的内容. 具体参考:Cocos2d-x3.x塔防游戏(保卫萝卜)从零开始(一)篇 二.本篇目标: l  说说关于cocos2dx手机分辨率适配 l  对前一篇完成的塔防游戏原型进 ...

  3. Cocos2D:塔防游戏制作之旅(一)

    原文地址:http://www.raywenderlich.com/37701/how-to-make-a-tower-defense-game-tutorial 由Pablo Ruiz写的入门教程, ...

  4. Cocos2D:塔防游戏制作之旅(十八)

    在Enemy.m的getDamaged:方法只给你添加如下1行(在if条件内): [theGame awardGold:200]; 现在运行游戏你将注意到你不能放置超出你资源金币的炮塔了.当然杀死敌人 ...

  5. Cocos2D:塔防游戏制作之旅(十六)

    编译运行你的app,放置一些炮塔在你的地图上吧!你将看到炮塔在敌人移动如攻击范围时如何立即开始攻击,并且敌人的血条将随着攻击不断减少知道它们被人道毁灭!胜利即将来临了! 哦!Okay,这里只有少数细节 ...

  6. Cocos2D:塔防游戏制作之旅(二)

    一个象牙塔的视图 如果你并不熟悉此类型的游戏,塔防游戏是一个战略游戏,你需要购买和将武装塔放置在战略位置,去阻止一波又一波的敌人到达并摧毁你的基地 每一波敌人都更强,这些更强的对手有着更快的速度和对于 ...

  7. 制作一个塔防游戏 Cocos2d-x 2.1.4 (一)

    在这篇文章,将会学习到怎样制作一个塔防游戏.在这其中,学习怎样在设定的时间内出现一波波的敌人,使这些敌人沿着指定的路点前进.怎样在地图上指定的位置创建炮塔.怎样使炮塔射击敌人,怎样可视化调试路点和炮塔 ...

  8. 三国塔防游戏android源码

    三国塔防游戏源码,这个游戏源码比较完整的,因为上传有20M限制,把代码工程包分开了,主文件是TFGame,其他res大家按照安卓包加进去就行,欢迎下载并交流 ,大家可以参考一下吧.<ignore ...

  9. HTML5塔防游戏——《三国塔防》 - Yorhom's Game Box

    h3{ font-size:20px; } HTML5塔防游戏--<三国塔防> 游戏介绍: <三国塔防>是一款基于HTML5和Javascript的2D塔防游戏.游戏中除了塔防 ...

随机推荐

  1. 数字电路-异同步 复位 线与 oc门

    1.同步电路和异步电路的区别是什么? 异步电路:主要是组合逻辑电路,用于产生地址译码器.FIFO或RAM的读写控制信号脉冲,但它同时也用在时序电路中,此时它没有统一的时钟,状态变化的时刻是不稳定的,通 ...

  2. 2016/9/21 leetcode 解题笔记 395.Longest Substring with At Least K Repeating Characters

    Find the length of the longest substring T of a given string (consists of lowercase letters only) su ...

  3. android stuido build 慢的解决办法

    Enable Offline Work: Click File -> Settings. Search for "gradle" and click in Offline w ...

  4. 必填项(required)

    当你设计表单时,你可以指定某些选项为必填项(required),只有当用户填写了该选项后,用户才能够提交表单. 例如,如果你想把一个文本输入字段设置为必填项,在你的input元素中加上required ...

  5. hdu - 3959 Board Game Dice(数学)

    这道题比赛中没做出来,赛后搞了好久才出来的,严重暴露的我薄弱的数学功底, 这道题要推公式的,,,有类似于1*a+2*a^2+3*a^3+...+n*a^n的数列求和. 最后画了一张纸才把最后的结果推出 ...

  6. WebSphere试用过期问题处理

    WebSphere Application Server的试用期为60天,过期将无法启动WAS. E:\IBM\WebSphere\AppServer\profiles\Dmgr01\bin>s ...

  7. 在jsp中常用的内置对象(5个)小总结和两种页面跳转方式(服务器端调转、客户端跳转)的区别

    jsp中常用的几个内置对象: 一.request对象 主要作用:  (1)获取请求页面的信息   比如:request.getParameter("参数名");  (2)获取客户端 ...

  8. win7 64系统安装oracle客户端使用PL/SQL Developer工具

    1)安装Oracle 11g 64位,我用的版本下载地址: http://www.oracle.com/technetwork/database/enterprise-edition/download ...

  9. python os&shutil 文件操作

    python os&shutil 文件操作 # os 模块 os.sep 可以取代操作系统特定的路径分隔符.windows下为 '\\' os.name 字符串指示你正在使用的平台.比如对于W ...

  10. servlet+jsp+java实现Web 应用

    servlet+jsp+java实现Web 应用 用java来构建一个web应用是特别容易的事情,jsp和php很像,可以嵌套在html中.程序的结构很简单,也很清楚,本文主要记录下大概的开发过程和环 ...