A Day In The Life

とあるプログラマの備忘録

Isometric MapのZオーダーの指定方法

Cocos2d-xでIsometric Mapを使ったゲームのサンプルを作成していたところz-order(zorder, zindex, z-index)の指定で結構ハマったのでメモです。
Isometric Mapというのはよくある2.5D的な1マスが菱形になっているマップのことです。こんな感じのやつです。
Isometric Map
Isometric Mapを使った有名なゲームだとクラッシュオブクランなんかがあります。
ゲームで使用するマップデータの作成を無料のTiled Map Editorというツールを使ってCocos2d-xと連携させて使っていました。
TiledMap Editorを使うとわりと簡単にマップを作成することはできるものの、マップの上にキャラだったり建物だったりを配置するとZオーダーの問題が出てきます。
そこで以下の図のようにマップ座標のxとyを足した値をZオーダーに設定するとうまくいきました(図は40マス×40マスのマップの例です)。
Isometric MapのZオーダー
プログラムにすると以下のような感じになります。

bool HelloWorldScene::init()
{
  //////////////////////////////
  // 1. super init first
  if ( !Layer::init()) {
    return false;
  }
  auto tiledMap = TMXTiledMap::create("tiledmap.tmx");
  this->addChild(tiledMap, 1, "tiledMap");  
  auto layer = tiledMap->getLayer("layer_name");
  Size size = tiledMap->getMapSize();
  // マップのサイズ分まわす
  for (int i = 0; i < size.width; i++) {
    for (int j = 0; j < size.height; j++) {
      Vec2 pos = Vec2(i, j);
      // タイルオブジェクトを取得
      auto tile = layer->getTileAt(pos);
      // タイルが存在する場合
      if (tile) {
        // GIDを取得
        auto gid = layer->getTileGIDAt(pos);
        // GIDごとに建物を配置
        if (gid == 1) {
          auto sprite = Sprite::create("building.png");
          // タイルの真ん中の位置にスプライトをセット
          Vec2 midPoint = tile->getPosition() + (tile->getContentSize() / 2);
          sprite->setPosition(midPoint);
          // Zオーダーを指定してスプライトをタイルマップに追加する
          tiledMap->addChild(sprite, i + j);
        }
      }
    }
  }
}

上記は動かないスプライトの例ですが、スプライトを動かす場合はポジションからマップ上の座標を計算してZオーダーを設定してやると上手くいきます。
通常の座標からマップ上に座標に変換する方法は以下のサイトが参考になります。