1. 程式人生 > >醬油帶你用cocos2dx3.0完成一款戰棋遊戲 (曹操傳)(一)地圖製作篇 1

醬油帶你用cocos2dx3.0完成一款戰棋遊戲 (曹操傳)(一)地圖製作篇 1

這是醬油第一次寫部落格,所以如果有什麼寫的不好,大家多多海涵啊。那麼廢話就不多說了,直接進入正題吧。

製作一款戰棋遊戲,在醬油看來最大的難度便是 ai的設計以及 實現劇本對遊戲整體的控制,當然啦,這都是比較深的問題了,醬油會放到以後的章節來加以介紹。那麼現在就正式開始打醬油啦。。。

首先,製作一款戰棋遊戲我們需要什麼,首先,我們得有一張地圖是吧。在這裡,我隆重推薦一款地圖製作工具 tiled.接下來放一個地圖製作的視訊

http://v.youku.com/v_show/id_XNzQwMzQyMTUy.html。不管有沒有tiled使用經驗的都可以看看,因為這裡涉及到了戰棋地圖的一些設計思路。

那好,現在就開始上程式碼了。首先,戰棋遊戲說白了,也是一種格子游戲,那麼,我們就得有一個類,來儲存格子資料,在這裡,我命名為PieceData,以後就都用圖塊來稱呼。

class PieceData
{
public:
static void Exchange(PieceData* moveBegin,PieceData* moveEnd);
void setRoleDataInPiece(std::string roleName,int ID,int power);
void init(const TerrainData* terrainData,std::string pieceName,Point p1,Point p2);
void clear();
PieceData();
private:
//這四個是隨著角色的變化而變化的
CREATE_GET_SET(int,power,Power)//改圖塊角色所屬勢力,有敵(-1)我(1)友(2)軍3種 0代表沒


//戰場的每一個角色都有一個唯一ID,包括小兵
CREATE_GET_SET(int,ID,ID)
CREATE_GET_SET(std::string,roleName,RoleName)//圖塊當前角色名,沒角色為空;
CREATE_GET_SET(bool,isHaveRole,IsHaveRole)//圖塊上是否有角色


CREATE_GET_SET(const TerrainData*,terrainData,TerrainData)//該圖塊地形資料
CREATE_GET_SET(bool,canMove,CanMove)
CREATE_GET_SET(std::string,terrain,Terrain)//所屬地形名(這個名字和TerrainData名不一定一樣)
CREATE_GET_SET(Point,coordinateOfMap,CoordinateOfMap)//在圖塊中的座標
CREATE_GET_SET(Point,coordinate,Coordinate)//在地圖中的座標
};

這個圖塊資訊儲存著戰場最重要的資料,查詢角色及劇本和ai的實現都要使用到圖塊的資料。。

好了,圖塊資料有了,接下來,我們就要有一個管理整個地圖的類,我命名為MapData,地圖類就不一一列出函數了,接下來,就放上如何載入地圖的函式



MapData* MapData::createWithTMXMap(const char *fileName)
{
MapData *mapData = MapData::create();
mapData->tmxMap = TMXTiledMap::create(fileName);


//物件層,用來設定戰鬥角色起始座標(也就是製作地圖時物件層的作用)
mapData->playerBegin = mapData->tmxMap->objectGroupNamed("playerBegin");
//如果有多個角色和多個起始點的話那麼角色的起始點的分佈要考慮一下,還有,一般來說,角色數應該少於起始點數
//AI物件層
mapData->enemyAIBegin = mapData->tmxMap->objectGroupNamed("enemyAIBegin");


//是否有友軍是可選的,但敵軍是必須滴.
mapData->friendAIBegin = mapData->tmxMap->objectGroupNamed("friendAIBegin");


Size mapSize = mapData->tmxMap->getMapSize();
mapData->mapSize = mapSize;


Size tiledSize = mapData->tmxMap->getTileSize();
mapData->MapContenSize = Size(tiledSize.width * mapSize.width,tiledSize.height * mapSize.height);
//這裡要注意,因為設定了縮放比例,所以圖塊的大小要進行相應的設定,
//這個是提供給外部使用的,內部使用的時候,是不用理會縮放比例的


//動態生成圖塊數,每一個格子即為一個圖塊資料
int size = mapSize.height * mapSize.width;
mapData->pieceData = new PieceData[size];


mapData->arrayOfTerrainData = TerrainDataManager::shardTerrainDataManager()->getTerrainData();


Vector<Node*> arrayOfLayer = mapData->tmxMap->getChildren();

//這個for迴圈的作用是設定每個圖塊的資料
for(int x = 0;x<mapSize.width;x++)
{
//這裡要注意,tiledMap的座標是以左上方為原點的
for(int y = 0;y<mapSize.height;y++)
{
int gid;
std::string layerName;

//先得到所有的圖層
Vector<Node*>::iterator iter = arrayOfLayer.begin();

for(;iter!=arrayOfLayer.end();iter++)
{
TMXLayer* tmxLayer = (TMXLayer*)*iter;
gid = tmxLayer->getTileGIDAt(Point(x,mapSize.height-1-y));

//如果gid有數值的話說明這個圖塊屬於這個圖層
if(gid)
{
layerName = Mytools::shardMytools()->getStrOfDeleteFirstNumber(tmxLayer->getLayerName());
break;
}
}

通過圖層名字找到地形資料,(注意,多個圖層對應1個地形資料 比如說 城牆和山地都是對應的 石頭這個地形資料 因為都是不可移動)
TerrainData* terrainData = mapData->searchTerrainDataByName(layerName);
(mapData->pieceData+(int)x+(int)y*(int)mapSize.width)->init(terrainData,layerName,Point(x,y),
//座標設定的是中間點
Point((x+0.5)*tiledSize.width,(y+0.5)*tiledSize.height));
}
}

記得要retain ,因為mapData沒有馬上addChild,否則會被回收。。

mapData->retain();
return mapData;
}

之後這個讀取進來的mapData並不會被馬上顯示出來,而是會被加入到一個遊戲資料管理類儲存 ,我命名為GameData  至於GameData我暫時就先不詳細解釋了,因為這個類設計到太多東西。總之,只要先理解到這個類存放這遊戲的大量資料,包括玩家資料和關卡等等大量資料,用的是單例模式,只要一開始遊戲就一直存在,直到遊戲結束。

之後要顯示地圖的時候,我們只需要簡單的addChild就可以了,node節點是管理整個戰鬥介面(不包括ui),可以實現地圖的拖動以及縮放。

TMXTiledMap* map = GameData::shardGameData()->getMapData()->getMap();
node->addChild(map,ZORDER_MAP);//地圖是第0層;

好了,今天的戰棋製作就先講到這兒,大家應該大概瞭解了怎麼地圖的流程,下一章,醬油會講解一下怎麼實現地圖的拖動以及放大縮小。。

那好,加上地圖的效果就是這樣啦,ui和人物先暫時不管。。