您的位置:首页 > 移动开发 > Cocos引擎

cocos2dx 植物大战僵尸 1 简言创建关卡层

2017-05-19 14:51 459 查看
本系列不定期更新,我也在网上找了一些资源,但都没能很好地还原原作,不得不说有些遗憾,这次的编写使用的是类cocos2dx的语法,因为cocos2dx的更新速度很快,所以我采用的是类似于伪代码的形式,只贴上具体的代码,另外,我是边写程序边写心得,称不上是教程,我会写下来让我感到纠结的地方,有什么不对的或者不好的,请指点,大家共同努力

游戏框架采用的是MVC(应该是吧)。GameScene作为控制器,继承自Scene,目前没什么内容

植物大战僵尸(以下简称pvz)的关卡是多种多样的,有草地,后院,屋顶等类型,在这里我打算使用tmx来保存关卡的数据,比如初始阳光啦,是白天还是晚上啦,僵尸的出场等等。

pvz是塔防游戏,塔防游戏不可避免地就是炮塔可以放置在什么地方,即塔基,对pvz来说,关卡原生的塔基有3种,分别是草地,水面和石头面

这三种,大多数植物可以直接种在草地上







,一部分可以种植在水面上(如荷叶),有些则可以种植在石头面上(如花盆),并且毁灭蘑菇,也会在草地上留下一个被炸毁的痕迹,所以,我打算使用一个类来表示当前的地形状态,Terrain,这个类保存在LevelLayer层中,是和关卡息息相关的

class Terrain:public Entity
{
CC_SYNTHESIZE(TerrainType,m_terrainType,TerrainType);//该地形的类型
CC_BOOL_SYNTHESIZE(m_bDestroyed,Destroyed);//当前的地形是否被毁坏 这个是自己封装的,类似与SYNTHESIZE
public:
Terrain();
~Terrain();
CREATE_FUNC(Terrain);
bool init();
};
还有就是实体类,实体类倒是简单,就是一切看的见的就是实体类,这里我是采用了组合,当然,继承也是可以的。

class Entity:public Node
{
protected:
Sprite*m_pSprite;
public:
Entity();
~Entity();
Sprite*getSprite()const;
//和bind不同,此函数不改变content size
void setSprite(Sprite*sprite);
void bindSprite(Sprite*sprite);
bool bindSpriteWithSpriteFrameName(const string&spriteName);
//创建动画
static Animate*createAnimate(std::string format,int begin,int end,float delayPerUnit,unsigned int loops=-1);


这样做对目前的好处是,当前的Terrain并不是都需要显示在界面上的,如果要继承Sprite,就必须赋值一个图片,要不就会出错(继承自Sprite,就会有渲染,没有初始化的话渲染失败,就会出错)

接下来就是地图了。







第一张图是5*9 相对比较规则的图形,第二张是6*9相对规则的图形,而第三张就不是规则图形了。



我一开始计划使用上面瓦片,三种颜色对应三种不同的Terrain类型,这样满足前两个图形,那第三个图怎么办呢?自己独立开发一个地图编辑器不太可能,那就只有使用tiled的对象层功能了。

我新建了一个对象层,自己决定里面的地形的位置和类型,那不就可以了嘛。当然,这个方法可行,那么问题就在于程序中如何解析并生成对应的Terrain了



class TerrainMaker
{
private:
function<void (Terrain*)> m_callback;
public:
TerrainMaker();
//开始解析
void startParse(TMXTiledMap*tiledMap,const function<void (Terrain*)>& callback);
private:
void parseTileLayer(TMXLayer*layer,TMXTiledMap*tiledMap);
void parseObjectGroup(TMXObjectGroup*objectGroup);
TerrainType convertStrToTerrainType(const string&sType);
这个就是Terrain解析,并且每解析一个就回调函数

bool LevelLayer::initWithLevel(const string&sLevel)
{
//加载关卡
m_pTiledMap = TMXTiledMap::create(sLevel);
this->addChild(m_pTiledMap);
//获取地形
TerrainMaker maker;
maker.startParse(m_pTiledMap,SDL_CALLBACK_1(LevelLayer::makeTerrainCallback,this));

return true;
}
生成Terrain回调函数,并进行一个小测试
void LevelLayer::makeTerrainCallback(Terrain*terrain)
{
m_terrains.push_back(terrain);
this->addChild(terrain);
//进行一个小小的测试
Sprite*sprite = Sprite::create("0.png");
terrain->setSprite(sprite);
}

好了,放上效果图



目测很不错

对地图

目前分为两种,使用图块解析和,使用对象解析。
使用图块,图块内的属性包含着地形的类型,对象层也是如此,并且这里的地图类型分为3种,Lawn Water Stone 即草地 水面 石面,由于在外部文件中保存的这些是字符串,所以还要有一个转换,这个转换目前在TerrainMaker中进行,至于以后要不要再增加其他的类型,则是以后扩展使用了,比如你可以加个沙漠类型的图,上面只能种仙人掌,其他的植物只能种在花盆上。
在生成Terrain对象的时候,要设置
1 地形类型
2 位置
3 尺寸大小
4 当前是否可以种植()
这三个是必选的,需要注意的是,这里的Terrain继承自Entity,也就是说,它是可以显示图形的,而地形显示图形的目前仅一种,就是被毁灭菇炸后留下的坑,这个是草地所特有的,不过也没必要特地再创建一个子类,在被毁灭菇炸坏后可以设置一个动画,只不过这个动画特别长,每隔一段不短的时间会换帧,在动画结束时就可以设置地形状态可种植,不过需要注意的是,当前的地形的精灵是空的,所以无法运行动画,这难不倒我,先从AnimationCache获取到对应动画,然后获取该动画的第一SpriteFrame,然后内部精灵通过createWithSpriteFrame创建就可以了,还有一个需要注意的,由于使用的是组合,所以得设置两个动作,一个为动画,另一个为DelayTime和CallFunc的组合动作,上面那个交给内部精灵,组合动作交给地形类,各司其职
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: