Cocos引擎《保卫萝卜》04实现简单的游戏原型.docx
《Cocos引擎《保卫萝卜》04实现简单的游戏原型.docx》由会员分享,可在线阅读,更多相关《Cocos引擎《保卫萝卜》04实现简单的游戏原型.docx(18页珍藏版)》请在冰豆网上搜索。
Cocos引擎《保卫萝卜》04实现简单的游戏原型
cocos引擎—《保卫萝卜》04:
实现简单的游戏原型
一、前提:
完成HelloGame项目的创建编译。
具体参考:
HelloGame项目创建篇
二、本篇目标:
说说关于塔防游戏的想法和思路
实现一个简单的塔防游戏原型
三、内容:
∙
说说关于塔防游戏的想法和思路
∙
首先上一张塔防游戏PSD设计效果图
游戏故事设定:
这个游戏说是保卫萝卜,但不能真的是保卫萝卜了,因为保卫萝卜的游戏已经有了,只是借用一下这个大名鼎鼎的塔防游戏宣传和参照一下。
现在网络上主流游戏都会先讲一下故事让玩家有一种入戏感,那我们的这个故事是这样的:
很久很久以前,在美丽的大学宿舍区住着一群美丽天真的女孩,但是邪恶的色狼大叔们总想对她们做一些坏事,那么我们的英雄善良勇敢的女生宿舍管理员利用生活中的武器菜刀、皮鞋、玩具飞机等在大叔必经的路上狙击他们,保护女孩们免受这些大叔的伤害。
游戏元素组成:
1、地图:
每一关地图均不相同,主要是道路不同和炮台位的不同。
2、炮塔:
水果刀、菜刀、老鼠药、高跟鞋、玩具飞机等,不同的炮台具备不同的价格、攻击速度、攻击属性、攻击方式。
3、子弹:
由炮台发射的,具备不同的攻击值、扩散值、迟缓值、攻击范围值等。
4、怪物:
各类猥琐大叔、叫兽、色狼,不同的色狼具备不同的速度值、伤害值、耐揍值,沿着地图上的道路不断的靠近道路终点的女主角。
5、女主角:
道路终点的女孩,不具备攻击力需要炮塔的保护,具有一定的纯洁值,当纯洁值被大叔玷污光了就自杀了,游戏也就结束了。
6、分数&资源:
杀死不同的色狼能获得一定的分数,分数可以用来购买新的炮台,每一关都会有一定的初始分数用来支撑游戏最初的消耗,每一关的分数只限在本关使用,下一关开启时前面积累的分数清空。
7、宝箱:
用分数资源购买宝箱,能有一定几率获得比投入分数几倍的回报。
8、医生:
用分数购买医疗,对女主角的纯洁值进行修补。
游戏开发模式:
整个游戏开发的方式是这样,首先实现一个很小的游戏核心原型,然后不断的修改扩大这个游戏原型直至游戏完成为止。
本人认为这样的方式比较适合读者理解,并且跟着文章自己学会理解这个游戏的开发。
∙
实现一个简单的游戏原型
∙
新建游戏工程名为DefendTheGirl(保卫女孩),包名为:
com.game.defendthegirl。
如果还不会创建工程请参照:
HelloGame项目创建篇
本篇原型需要实现内容:
1、在主场景中载入一张地图。
2、在地图终点放置一个女主角,在地图的起点放置一个色狼大叔。
3、让色狼大叔沿着地图指定的路线向女主角的位置靠近。
素材图片准备:
地图图片
女主角图片
色狼大叔图片
把这几张素材图片拷贝到文件夹Resources下面即可。
1、在主场景中载入一张地图
第一步:
用MicrosoftVisualStudio2012打开proj.win32工程,然后在src下新建MainScene.h、MainScene.cpp作为游戏的主场景(Scene不会建?
参考:
HelloGame项目解析)。
第二步:
在init()方法里载入地图图片level_bg_1.png,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
return true;
}
第三步:
打开AppDelegate.cpp文件,引入MainScene.h头文件,并且在applicationDidFinishLaunching方法中把autoscene=HelloWorld:
:
createScene();改成autoscene=MainScene:
:
createScene();然后运行。
2、在地图终点放置一个女主角,在地图的起点放置一个色狼大叔
第一步:
在init()方法里添加如下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//载入地图背景
……
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);
//在地图起点处放置一个色狼
auto dsSprite = Sprite:
:
create("dashu.png");
dsSprite->setPosition(Vec2(40, 390));
this->addChild(dsSprite, 0);
//在地图终点处放置一个女主角
auto nhSprite = Sprite:
:
create("girl.png");
nhSprite->setPosition(Vec2(920, 480));
this->addChild(nhSprite, 0);
…...
第二步:
然后运行就可以在画面上看到色狼大叔和女主角了
3、让色狼大叔沿着地图指定的路线向女主角的位置靠近
这个一个有点难度的任务,首先我们对这张地图的道路路径进行一下坐标分析:
如上图所示,以地图的右下顶点为坐标系原点,整个道路分成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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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 (0);
return bRet;
}
void Waypoint:
:
setNextWaypoint(Waypoint* waypoint)
{
_nextWaypoint=waypoint;
}
Waypoint* Waypoint:
:
getNextWaypoint()
{
return _nextWaypoint;
}
第二步:
在MainScene.h里声明如下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 wayPositions;
//判断2个点是否靠近
bool collisionWithCircle(cocos2d:
:
Vec2 circlePoint,float radius,cocos2d:
:
Vec2 circlePointTwo, float radiusTwo);
这里代码,也对之前代码进行了修改重构,比如把之前在init()方法里声明的dsSprite(色狼)改到了这里变成了一个全局变量,因为在后续的update方法中需要对它进行操作。
第三步:
在MainScene.cpp的init()方法中创建路径点集合编写如下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
……
//获得色狼大叔的高
float dsh=dsSprite->getTextureRect().size.height;
//初始化地图路径点集合
this->wayPositions = Vector();
//添加地图1号路径点到集合中
Waypoint *waypoint1=Waypoint:
:
nodeWithTheLocation(Point(920, 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, 435+dsh/2.0f));
if(this->wayPositions.size()>0)
{
waypoint2->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint2);
//添加地图3号路径点到集合中
Waypoint *waypoint3=Waypoint:
:
nodeWithTheLocation(Point(762, 360+dsh/2.0f));
if(this->wayPositions.size()>0)
{
waypoint3->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint3);
//添加地图4号路径点到集合中
Waypoint *waypoint4=Waypoint:
:
nodeWithTheLocation(Point(685, 360+dsh/2.0f));
if(this->wayPositions.size()>0)
{
waypoint4->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint4);
//添加地图5号路径点到集合中
Waypoint *waypoint5=Waypoint:
:
nodeWithTheLocation(Point(685, 116+dsh/2.0f));
if(this->wayPositions.size()>0)
{
waypoint5->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint5);
//添加地图6号路径点到集合中
Waypoint *waypoint6=Waypoint:
:
nodeWithTheLocation(Point(520, 116+dsh/2.0f));
if(this->wayPositions.size()>0)
{
waypoint6->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint6);
//添加地图7号路径点到集合中
Waypoint *waypoint7=Waypoint:
:
nodeWithTheLocation(Point(520, 180+dsh/2.0f));
if(this->wayPositions.size()>0)
{
waypoint7->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint7);
//添加地图8号路径点到集合中
Waypoint *waypoint8=Waypoint:
:
nodeWithTheLocation(Point(285, 180+dsh/2.0f));
if(this->wayPositions.size()>0)
{
waypoint8->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint8);
//添加地图9号路径点到集合中
Waypoint *waypoint9=Waypoint:
:
nodeWithTheLocation(Point(285, 268+dsh/2.0f));
if(this->wayPositions.size()>0)
{
waypoint9->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint9);
//添加地图10号路径点到集合中
Waypoint *waypoint10=Waypoint:
:
nodeWithTheLocation(Point(204, 268+dsh/2.0f));
if(this->wayPositions.size()>0)
{
waypoint10->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint10);
//添加地图11号路径点到集合中
Waypoint *waypoint11=Waypoint:
:
nodeWithTheLocation(Point(204, 350+dsh/2.0f));
if(this->wayPositions.size()>0)
{
waypoint11->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint11);
//添加地图12号路径点到集合中
Waypoint *waypoint12=Waypoint:
:
nodeWithTheLocation(Point(50, 350+dsh/2.0f));
if(this->wayPositions.size()>0)
{
waypoint12->setNextWaypoint(this->wayPositions.back());
}
this->wayPositions.pushBack(waypoint12);
……
第四步:
在MainScene.cpp的init()方法中初始化几个变量以及精灵的初始位置编写如下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
……
//获取集合中的最后一个点,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中