cocos2dx - tmx地图分层移动处理
接上一节内容:cocos2dx - 节点管理
瓦片地图(Tiled Map)
在cocos2dx文档中有简单的介绍及使用。详情可以看:http://www.cocos2d-x.org/docs/manual/framework/native/v2/graphic/tiled-map/zh
一、FastTMXTiledMap & TMXTiledMap选择
在cocos2dx有2种实现加载Tmx地图的方法,分别是FastTmxTiledMap和TmxTiledMap。
主要区别:
FastTmxTiledMap 的绘制层TMXLayer继承Node节点,直接利用opengl 的索引(indices)一次绘制所有的格子纹理。
TmxTiledMap 的绘制层TMXLayer则通过继承 SpriteBatchNode节点,利用cocos2dx中封装好的批量绘制图片节点的功能实现一次绘制。
性能区别:
FastTmxTiledMap 在绘制效率上相对于 TmxTiledMap 有显著提高,因为SpriteBatchNode实际流程是创建了批量的Node,通过SpriteBatchNode来管理这些Node的索引及统一绘制调用,
这样相对于一个FastTmxTiledMap中一个Node的调用多了顶点的消耗及内存的消耗。
GL verts 和 GL calls 对比
(FastTmxTiledMap)
(TmxTiledMap)
通过对比,可以看到同样的效果,绘制回调次数一致,但是顶点数 FastTmxTiledMap 仅占 TmxTileMap的 1/3多一点。
二、实际应用
功能: 实现通用的循环地图,同时让地图分层同屏移动。
首先,需要设计一个结构体SMapStruct来管理同一层的地图实现循环,同时利用一个map来管理不同层级的SMapStruct。
class CMapScreen; // 实际显示移动地图的管理
// 管理同一层级的地图
struct SMapStruct
{
SMapStruct() :nIdx(), nLastIdx(-){};
size_t nIdx; // 当前地图索引
size_t nLastIdx; // 上一层的索引
std::vector<int> vCircle; // 循环索引列表
std::vector<CMapScreen*> vScreen; // 实际地图列表
};
std::map<int, SMapStruct> m_mMapList; // 层级到SMapStruct列表
这里的索引可以指向csv读取出来的 SMapConfig 配置
// 地图配置
struct SMapConfig
{
int nID; // 索引
std::string strFile; // 地图资源
int nIdx; // 层级
int nSpeed; // 地图移动速度 px/s
bool bMoveY; // 是否Y移动
};
这样在游戏开始,对配置的地图信息进行加载,存到 m_mMapList列表中。
// 地图设置
{
for (size_t i = ; i < m_vMap.size(); i++)
{
SMapConfig* pConfig = m_vMap[i];
if (pConfig)
{
SMapStruct& sMapStruct = m_mMapList[pConfig->nIdx];
sMapStruct.vCircle.push_back(i);
}
}
}
这样m_mMapList列表中就存了当前游戏每一个层级需要的地图列表。然后在update对其进行更新显示,如下:
void CMapMgr::update(float dt)
{
auto it = m_mMapList.begin();
while (it != m_mMapList.end())
{
SMapStruct& sStruct = it->second;
// 判断当前层级地图列表是否存在
if (sStruct.vCircle.size() <= sStruct.nIdx)
{
CCLOG("地图列表更新错误!!");
break;
}
// 获取上一张显示的地图
if (CMapScreen* pMap = GetScreen(sStruct, sStruct.nLastIdx))
{
pMap->update(dt);// 更新坐标
// 显示出视口
if (pMap->IsOutViewPort())
{
pMap->Sleep(); //隐藏该地图
sStruct.nLastIdx = -;
}
}
// 获取当前显示的地图
if (CMapScreen* pMap = GetScreen(sStruct, sStruct.nIdx))
{
pMap->update(dt);
// 判断是否需要显示下一张地图
if (pMap->IsNeedNextScreen())
{
sStruct.nLastIdx = sStruct.nIdx;
// 显示出视口
if (pMap->IsOutViewPort())
{
pMap->Sleep();
sStruct.nLastIdx = -;
}
if (++sStruct.nIdx >= sStruct.vCircle.size())
{
sStruct.nIdx = ;
}
if (CMapScreen*pNextMap = GetScreen(sStruct, sStruct.nIdx))
{
// 显示新地图
pNextMap->Active(pMap->GetConnetPoint());
}
}
}
++it;
}
}
以上实现了地图分层移动的管理,可以实现不同层级不同速度移动,或者静止等,也可以往不同方向移动。
SMapStruct类的实现,不再这里详细描述了。主要实现以下方法:
// 每个地图层
class CMapScreen : public Node
{
public:
static CMapScreen* create(const SMapConfig* pConfig); void Release(); void Active(const Vec2& pt); // 启用update循环移动 void Sleep(); // 隐藏停止update bool IsNeedNextScreen() const; Vec2 GetConnetPoint() const; // 获取连接点 void update(float dt); bool IsOutViewPort() const ; // 出了视口an
}
三、黑缝处理
Tmx地图在cocos2dx移动的时候会偶尔出现黑线的现象。主要原因是底层顶点坐标取到了纹理之外导致颜色值取不到。
解决办法:
1、移动的偏移坐标用整数。
2、衔接处重叠1个像素。
3、采用Director::Projection::_2D的方式绘制游戏。
1、如下:
m_nDelta+= m_pConfig->nSpeed* dt;
// 取整数
int nDelta = int(m_nDelta);
m_nDelta -= nDelta;
// 移动对应的距离
m_pConfig->bMoveY ? setPositionY(getPositionY() + nDelta) : setPositionX(getPositionX() + nDelta);
2、代码如下:
Vec2 CMapScreen::GetConnetPoint() const
{
Vec2 pt;
if (!m_pConfig)
{
return pt;
}
Vec2 origin = Director::getInstance()->getVisibleOrigin(); if (m_pConfig->bMoveY)
{
pt = m_pConfig->nSpeed>0 ? getPosition() : Vec2(getPositionX(), getPositionY() + getContentSize().height);
pt.y = m_pConfig->nSpeed > 0 ? pt.y + 1: pt.y - 1; //重叠1个像素 防止黑缝出现
}
else
{
pt = m_pConfig->nSpeed>0 ? getPosition() : Vec2(getPositionX() + getContentSize().width, getPositionY());
pt.x = m_pConfig->nSpeed > 0 ? pt.x + 1 : pt.x - 1;//重叠1个像素 防止黑缝出现
}
return pt;
}
3、代码如下:
director->setProjection(Director::Projection::_2D);
另,3在cocos2dx-3.9中用2D方式绘制FastTmxMap有bug,需要回溯之前版本的配置如下:
void TMXLayer::draw(Renderer *renderer, const Mat4& transform, uint32_t flags)
{
updateTotalQuads(); //正交方式处理纹理,防止地图切换黑线
if (Director::getInstance()->getProjection() == Director::Projection::_2D)
{
if (flags != || _dirty || _quadsDirty)
{
Size s = Director::getInstance()->getWinSize();
auto rect = Rect(, , s.width, s.height); Mat4 inv = transform;
inv.inverse();
rect = RectApplyTransform(rect, inv); updateTiles(rect);
updateIndexBuffer();
updatePrimitives();
_dirty = false;
}
}
else
{
bool isViewProjectionUpdated = true;
auto visitingCamera = Camera::getVisitingCamera();
auto defaultCamera = Camera::getDefaultCamera();
if (visitingCamera == defaultCamera) {
isViewProjectionUpdated = visitingCamera->isViewProjectionUpdated();
} if (flags != || _dirty || _quadsDirty || isViewProjectionUpdated)
{
Size s = Director::getInstance()->getVisibleSize();
auto rect = Rect(Camera::getVisitingCamera()->getPositionX() - s.width * 0.5,
Camera::getVisitingCamera()->getPositionY() - s.height * 0.5,
s.width,
s.height); Mat4 inv = transform;
inv.inverse();
rect = RectApplyTransform(rect, inv); updateTiles(rect);
updateIndexBuffer();
updatePrimitives();
_dirty = false;
}
} if(_renderCommands.size() < static_cast<size_t>(_primitives.size()))
{
_renderCommands.resize(_primitives.size());
} int index = ;
for(const auto& iter : _primitives)
{
if(iter.second->getCount() > )
{
auto& cmd = _renderCommands[index++];
cmd.init(iter.first, _texture->getName(), getGLProgramState(), BlendFunc::ALPHA_NON_PREMULTIPLIED, iter.second, _modelViewTransform, flags);
renderer->addCommand(&cmd);
}
}
}
附上几张加了Tmx地图后,现在游戏的效果:


cocos2dx - tmx地图分层移动处理的更多相关文章
- 读取.tmx地图
读取.tmx地图 m_GameMap = CCTMXTiledMap::create("map1.tmx"); this->addChild(m_GameMap,1); 读取 ...
- Cocos2d-x Tiled地图编辑器(一)基本使用
Tiled地图编辑器支持普通视角地图和45度角地图, 它生成的地图数据文件cocos2d-x完美的支持,Tiled地图编辑器是一个以普通使用为目标地图编辑器,它使用简单而且能够轻松地在不同的游戏引擎中 ...
- 忍者无敌-实例解说Cocos2d-x瓦片地图
实例比較简单,如图所看到的,地图上有一个忍者精灵,玩家点击他周围的上.下.左.右,他能够向这个方向行走. 当他遇到障碍物后是无法穿越的,障碍物是除了草地以为部分,包含了:树.山.河流等. 忍者实例地图 ...
- 忍者无敌-实例讲解Cocos2d-x瓦片地图
实例比较简单,如图所示,地图上有一个忍者精灵,玩家点击他周围的上.下.左.右,他能够向这个方向行走.当他遇到障碍物后是无法穿越的,障碍物是除了草地以为部分,包括了:树.山.河流等. 忍者实例地图(TO ...
- Cocos2d-x 2地图步行实现:SPFA算法
本文乃Siliphen原创,转载请注明出处:http://blog.csdn.net/stevenkylelee 上一节<Cocos2d-x 地图行走的实现1:图论与Dijkstra算法> ...
- cocos2dx - 创建地图及玩家(伪)
接上一节内容:cocos2dx - 环境配置,项目创建 本节主要描述cocos中精灵的创建及点击事件的使用 打开创建好的test项目,看到下图的目录结构,真正的游戏逻辑路径在src下. AppDele ...
- 关于Cocos2d-x中地图轮播的实现
播放背景,两个背景的图片是一样的,紧挨着循环播放,以下代码写在playBackground()方法中,并在GameScene.cpp的init方法中调用. void GameScene::playBa ...
- cocos2dx游戏 地图
#include "HelloWorld.h" USING_NS_CC; CCScene* MyHelloWorld::scene() { // 'scene' is an aut ...
- cocos2dx迷你地图
用CCRenderTexture就可以了,不知是否有更好的方法. if (!miniMap) { miniMap=CCSprite::create(); miniMap->setZOrder() ...
随机推荐
- iOS ipa包瘦身------删除无用图片资源
随着客户端业务的增多和业务的更新,App包大小越来越大,优化包大小是迫在眉睫,客户端需要优化的地方也有很多,本期主要讲如何查找无用图片并且删除无用图片的方法. 方案1:(暴力方法) ...
- 【1414软工助教】团队作业4——第一次项目冲刺(Alpha版本) 得分榜
题目 团队作业4--第一次项目冲刺(Alpha版本) 作业提交情况情况 所有团队都在规定时间内完成了七次冲刺. 往期成绩 个人作业1:四则运算控制台 结对项目1:GUI 个人作业2:案例分析 结对项目 ...
- 结对作业1----基于GUI的四则运算生成器
组员:201421123015 陈麟凤 201421123019 张志杰 201421123020 黄海鸿 coding 地址:代码点这里 需求分析: 1.除了整数的四则运算还要支持分数的四则运算: ...
- 201521123026《Java程序设计》第8周学习总结
1. 本章学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 2. 书面作业 Q1.1.List中指定元素的删除(题目4-1) 1.1 实验总结 答: 1.通过equals ...
- 201521123075 《Java程序设计》第5周学习总结
1. 本周学习总结 2. 书面作业 作业参考文件下载 1 .代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过?哪句会出现错误?试改正该错误.并分 ...
- 201521123001《Java程序设计》第4周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 答:1.被继承的类称为父类,继承父类的类称为子类 2.继承时子类将获得父类的属性与方法,并具 ...
- 201521123005 《Java程序设计》第1周学习总结
1. 本章学习总结 了解JDK/JRE/JVM,学会了如何安装JDK 学会使用控制台和eclipse上运行java代码 了解PTA提交的常见套路 http://www.cnblogs.com/zhrb ...
- linux各类压缩解压命令大全
01-.tar格式解包:[*******]$ tar xvf FileName.tar 打包:[*******]$ tar cvf FileName.tar DirName(注:tar是打包,不是压缩 ...
- Servlet 3.0 使用注解配置URl提示404错误
我的环境是 Eclipse oxygen + Servlet 3.0 因为3.0已经开始使用注解了 之前我都是配置listenner 还有Servlet mapping 在 web.xml 中 就 ...
- windows 下面安装gcc
0.环境说明: win7 家庭版64位 1.下载编译器 https://sourceforge.net/projects/mingw/?source=typ_redirect 如图所示: 注意,安装的 ...