cocos2d-x+box2d+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();
}