cocos2d-x+box2d+tiled 制作无规则碰撞地图

本文详细介绍了如何使用Cocos2d-x的Tiled地图编辑器创建地图对象层,并通过读取这些对象层来实现复杂的碰撞检测。具体步骤包括:创建对象层及绘制多边形,解析tmx文件中的polyline数据,以及利用Box2D创建刚体。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.youkuaiyun.com/bcx0713/article/details/8930108

 

问题内容:1  利用 tiled 对象层 绘制碰撞的边界 
                  2 通过 cocos2d-x "CCTMXTiledMap" 的对象 读取地图中的点信息 
                  3 通过读出的信息绘制 box2d “b2EdgeShape” 刚体 

问题解决:
                  引擎版本:cocos2d2.1beta3 + box2d 2.2.1 

                  一 关于tiled

                     1.1 创建对象层

                    点击历史上面的带星号按键 有添加对象层选项 点击创建 创建好后 图层中会显示对象层 

                     1.2 多边形与折线  

                  创建好对象层后 选择 此时上面折线选项可以应用  选择选项绘制不规则线 例如: 

                     1.3 tmx文件内容  

                    保存绘制完成的地图后 记事本打开tmx文件看代码 


                           objectgroup部分为对象层内容   name为对象层名字(最好是英文,中文可能会出现问题)
                           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);
                       }

                              此时即获得所需要的数据


                 3.3 polyline点坐标的拆分

                      此部分内容大家随意 就是字符串的拆分与保存 简单介绍下我的方法 

                      c++中提供了strtok方法拆分字符串 但个人认为有些小问题 所以用了其他方法:


                     typedef basic_string<char>::size_type S_T1;
                     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* 的转换 略过


                  string tok=" ,";     //分隔标志 为 空格 和 逗号
                     //用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();
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值