http://blog.youkuaiyun.com/bcx0713/article/details/8930108
2 通过 cocos2d-x "CCTMXTiledMap" 的对象 读取地图中的点信息
3 通过读出的信息绘制 box2d “b2EdgeShape” 刚体
问题解决:
引擎版本:cocos2d2.1beta3 + box2d 2.2.1
一 关于tiled
1.1 创建对象层
点击历史上面的带星号按键 有添加对象层选项 点击创建 创建好后 图层中会显示对象层
1.2 多边形与折线
创建好对象层后 选择 此时上面折线选项可以应用 选择选项绘制不规则线 例如:
1.3 tmx文件内容
保存绘制完成的地图后 记事本打开tmx文件看代码
object部分为所需要的内容 其中X,Y 表示绘制的不规则图形的起点位置 ployline 为以起点为初始点 连续绘制的坐标点值
以上为地图所需要内容
二 引擎部分修改 使之能够完成地图内容的读取
2.1 读取方式可以有两种
一是 利用cocos2d-x所提供的接口 CCTMXTiledMap 读取 (下文详解)
二是 利用xml解析器 TinyXml读取 (此部分略过 有兴趣的话可以自己尝试下)
2.2 修改引擎
其中CCTMXTiledMap 不支持读取polyline 需要修改引擎代码 CCTMXXMLPaerser.cpp 中CCTMXMapInfo::startElement函数 下部 有elementName == "polyline" / elementName == "polygon" 代码块 内容被隐藏掉 需要修改其中内容 如下:
然 后重新生成cocos2d-x项目 将生成好的.lib .dll拷到自己的项目中
以上为引擎部分修改
三 创建box2d刚体
3.1 思路是这样的 读取polyline 点的坐标 利用坐标绘制 b2EdgeShape
涉及的问题: 1 点坐标获取 2 polyline点坐标的拆分 3 创建刚体
3.2 点坐标获取
3.2.1 需要的变量
CCTMXTiledMap *m_pMap = CCTMXTiledMap::create(“地图TMX文件的名字”);
CCTMXObjectGroup* m_pGroup = m_pMap->objectGroupNamed("tmx文件中objectgroup的名字 上文有介绍");
CCArray* m_pObjects = m_pGroup->getObjects();
CCDictionary* m_pDict = NULL;
CCObject* m_pObj = NULL;
3.2.2 查找数据的方法
//循环查找所有object
CCARRAY_FOREACH(m_pObjects, m_pObj)
{
m_pDict = (CCDictionary*)m_pObj;
//保存值的时候需要同时保存X Y 和polyline 的 points XY为所画多边形的起始点
//查找X Y 值
const char* key = "x";
int x = ((CCString*)m_pDict->objectForKey(key))->intValue();
key = "y";
int y = ((CCString*)m_pDict->objectForKey(key))->intValue();
key = "polyline"
// 如果名字为 “polyline” 读取并保存points值
CCString* s_points = (CCString*)m_pDict->objectForKey(key);
}
此时即获得所需要的数据
此部分内容大家随意 就是字符串的拆分与保存 简单介绍下我的方法
c++中提供了strtok方法拆分字符串 但个人认为有些小问题 所以用了其他方法:
static const S_T1 npos = -1;
//字符串分割
//src 原字符串 tok分隔字符(可多个) trim是否保留空串(默认保留) null_subst 空标记
//输出 分隔结果向量
vector<string> myTokenize(const string& src, string tok, bool trim=false, string null_subst="")
{
if (src.empty() || tok.empty())
{
throw "emptystring/0";
}
vector<string> v;
S_T1 pre_index = 0, index = 0, len = 0;
while ((index = src.find_first_of(tok,pre_index)) != npos)
{
if ((len = index-pre_index) != 0)
{
v.push_back(src.substr(pre_index,len));
}
else if (trim == false)
{
v.push_back(null_subst);
}
pre_index = index + 1;
}
string endstr = src.substr(pre_index);
if (trim == false)
{
v.push_back(endstr.empty()?null_subst:endstr);
}
else if(!endstr.empty())
{
v.push_back(endstr);
}
return v;
}
当然用这个涉及一点string / const char* 的转换 略过
//用vector保存提取出来的所有点坐标
typedef vector<string> V;
V v;
v = myTokenize(points,tok,true);
V::iterator it = v.begin();
这样 就获得了 polyline 的points 所有的坐标
3.4 3 创建刚体
float StringToFloat(string* str)
{
int len = str->length();
char* c = new char[len+1];
strcpy(c,str->c_str());
float f = (float)atof(c);
return f;
}
//遍历保存XY坐标
//画图方式 V1->V2 V2-V3 V3-V4..
//第二条线起始点为第一条线终点
b2Vec2 vs[2];
for (; it!=v.end(); )
{
//分别保存第一点第二点XY
float x1,y1,x2,y2;
//定义刚体 刚体类型为b2EdgeShape
b2BodyDef bd;
b2Body* ground = m_World->CreateBody(&bd);
b2EdgeShape shape;
x1 = StringToFloat(&(*it));
++it;
y1 = StringToFloat(&(*it));
++it;
//只第一次不做 第一条线起始点为首先读取点值
if (!m_bIsSaveV2)
{
vs[0].Set((posx+x2)/PTM_RATIO, (posy-y2)/PTM_RATIO);
vs[1].Set((posx+x1)/PTM_RATIO, (posy-y1)/PTM_RATIO);
shape.Set(vs[0], vs[1]);
ground->CreateFixture(&shape, 0.0f);
}
//控制第一次不做 这个变量在初始赋值时为true 等循环创建完刚体后 再次变为true
m_bIsSaveV2 = false;
//防止点的数量为单数 it无值
if(it==v.end())
{
break;
}
x2 = StringToFloat(&(*it));
++it;
y2 = StringToFloat(&(*it));
++it;
//设置点位置 cocos2d坐标系与tmx坐标系Y方向相反 得出的Y值需相减
//posx posy 为之前保存的起始点坐标X Y
vs[0].Set((posx+x1)/PTM_RATIO, (posy-y1)/PTM_RATIO);
vs[1].Set((posx+x2)/PTM_RATIO, (posy-y2)/PTM_RATIO);
shape.Set(vs[0], vs[1]);
ground->CreateFixture(&shape, 0.0f);
}
刚体创建完成
else if (elementName == "polygon")
{
CCTMXObjectGroup* objectGroup = (CCTMXObjectGroup*)pTMXMapInfo->getObjectGroups()->lastObject();
CCDictionary* dict = (CCDictionary*)objectGroup->getObjects()->lastObject();
const char* val = valueForKey("points", attributeDict);
CCString* obj = new CCString(val);
dict->setObject(obj, "polygon");
obj->release();
}
else if (elementName == "polyline")
{
CCTMXObjectGroup* objectGroup = (CCTMXObjectGroup*)pTMXMapInfo->getObjectGroups()->lastObject();
CCDictionary* dict = (CCDictionary*)objectGroup->getObjects()->lastObject();
const char* val = valueForKey("points", attributeDict);
CCString* obj = new CCString(val);
dict->setObject(obj, "polyline");
obj->release();
}