phi-jp / tmlib.js

JavaScript をより使いやすく, より便利に, そしてより豊かに.
http://phiary.me
211 stars 40 forks source link

MapSpriteで各レイヤー毎にTileset画像を指定できるようにしたい #122

Open emadurandal opened 10 years ago

emadurandal commented 10 years ago

こんにちはー。

表題の通りの要望ですー。 以下の様な感じにできると素敵だなーと思いまして。

  MAP_DATA = {
    'map.001': {
      name: '001',
      width: 10,
      height: 10,
      tilewidth: 64,
      tileheight: 64,
      tilesets: [
        {
          name: 'layer1',
          image: 'hoge.jpg'
        },
        {
          name: 'layer2',
          image: 'hoge2.jpg'
        }
      ],
      layers: [
        {
          type: 'layer',
          name: 'layer1',
          data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 
                 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        },
        {
          type: 'layer',
          name: 'layer2',
          data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 
                 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 
                 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        }
      ]
    }
  };

tmlibのコードのtm.display.MapSpriteの定義内のコードを以下のような感じにしたら(すっごい初心者なコード(汗))、とりあえず行けたのですが、

        _buildLayer: function(layer) {
            var self        = this;
            var mapSheet    = this.mapSheet;
            var tilesetUrl = "";
            for(var i = 0; i<mapSheet.tilesets.length; i++) {
                if(mapSheet.tilesets[i].name === layer.name) {
                    tilesetUrl = mapSheet.tilesets[i].image;
                    break;
                }
            }
            var texture     = tm.asset.Manager.get(tilesetUrl);
            .....

他のコード部分との整合性とか大丈夫か自信がなかったのでプルリクでなくイシューで上げさせていただきました。

ご検討よろしくお願いいたします。

fukuyama commented 10 years ago

Tiled map XML (tmx) 的には、複数の tileset を指定した場合は、全部をマージした tileset 1つになるみたいですね。

tmx はとりあえず置いておいて、 レイヤー1つにタイルセット1つって対応付けるなら…レイヤー側に、使うタイルセットを設定したほうがしっくりくる気がします。1つのタイルセットは、複数のレイヤーで使うかな~と。

tilesets: [
  {
    name: 'layer1',
    image: 'hoge.jpg'
  },
  {
    name: 'layer2',
    image: 'hoge2.jpg'
  }
],
layers: [
  {
    type: 'layer',
    name: 'layer1',
    tileset: 0 もしくは 'layer1',
    data: [...]
  }
]

1つのレイヤーで複数のタイルセットも使いたくなるから、Tiled では、全部1つにしてる気がしますね…

emadurandal commented 10 years ago

@fukuyama あ、たしかにレイヤー側に設定できた方が良いですね。

Tiled map XMLは私よく知らないんですが、全部一つのタイルセットにすると、 dataの、タイルのインデックスの指定が少しややこしくなるのがネックかなーと。

Tiledの場合と、この場合、両方認めてくれるとうれしーです♪

fukuyama commented 10 years ago

たぶん、福山もそのうち使いたくなるので、ちょっと手をつけてみようかな~

MapSprite は、1つのレイヤーで複数のタイルセットとか、複数のレイヤーに、1つのタイルセットとか 多対多にできると何でもできるとおもうので tmx よりの、全部1つにしてなんでも使える状態が いい気がします。

MapSheet か、その派生クラスの初期化方法の1つとして、 レイヤーが使うタイルセットを指定する方法とか data に、そのタイルセットの番号しか書かないって初期化方法を用意する。(内部的には、全タイルセットの通し番号に変換とか)

で、tmx での初期化とか、json での初期化とか、その他でも対応出来る感じがする。 data を通し番号に変換するヘルパー関数ってだけでもいいかも?

phi-jp commented 10 years ago

watch

fukuyama commented 10 years ago

自分のforkしたほうでは、できました~。 結局、MapSprite でがんばるようにしてみました。MapSheetだと、asset だからいろいろ後で大変かな~と思って、とりあえず。

125 がマージされたら、それをさらに修正って感じでプルリクします。

よろしくお願いします。 @phi-jp さま なにか問題あったら、修正します。

    # タイルセット
    tilesets: [
      {
        name: 'pink'
        image: 'img/test03.png'
      }
      {
        name: 'blue'
        image: 'img/test04.png'
      }
    ]

    # マップレイヤー
    layers: [
      {
        type: 'layer'
        name: 'layer1'

        tilesets: ['blue','pink']

        data: [
          5, 0, 0, 0, 5
          0, 0, 0, 0, 0
          0, 0,-1, 0, 0
          0, 0, 0, 0, 0
          0, 0, 0, 0, 0
        ]
      }
    ]

こんな感じです。今のところ。

layer の方の tilesets には、数値、文字列、数値配列、文字列配列が指定できて、 数値は、タイルセットのインデックス。文字列は、タイルセット名。 配列の場合は、その順番でマージされたタイルセットとして layer.data を MapSprite でつかう。

layer の tilesets 指定が無い場合は、もともとのタイルセットの順番。(tmxの場合は無い)

emadurandal commented 10 years ago

@fukuyama わー、ステキです! 私もプルリクできるように、tmlib.jsの仕様をちゃんと理解しないとなー^^;

この例の場合は、pink(test03.png)とblue(test04.png)の画像がマージされて、layer.data配列内の各セルの数値は、そのマージされた画像のセルのインデックスを指すという理解でよいでしょうか?

fukuyama commented 10 years ago

@emadurandal 上の例の場合は、blue(test04.png) + pink(test03.png) の順でマージですね。 layer.tilesets では、マージする順番を、指定する感じです。

tilesets: 'blue' だと、test04.png だけ使う感じです。tilesets: 1 でも同じ。 tilesets: ['pink','blue'] だと、設定しない場合と一緒。 (tmxと同じ。pink + blue の順番でマージしたインデックス)

emadurandal commented 10 years ago

developに取り込まれたようなので、早速使ってみたのですが、 上の例でいうと、 2つ目のレイヤーを追加したとして、そのレイヤーでtilesets: 'blue' を指定したのですが、

2つ目のレイヤーのdataの配列で要素に0を指定すると、blue(test04.png)の最初のマップチップでなく、pink(test03.png)の最初のマップチップが表示されてしまいます。なので、現状pink(test03.png)のタイル数を覚えておいて、その数だけオフセットしないといけない(pink(test03.png)のタイル数が5だったら、レイヤー2のdataでblue(test04.png)の最初のマップチップを表示したいときは5、2番目のマップチップを表示したいなら6を指定しないといけない)状況です。

これ、オフセットを内部で自動でやってくれるようにはできないでしょうか?

fukuyama commented 10 years ago

@emadurandal もう少々お待ちを~ 今のマージは、tmx に対応しただけなので、さらにプルリクします。

emadurandal commented 10 years ago

ありがとうございます。なんだか要求してばっかりですみません(汗) 私も最近tmlib.jsのコードリーディング始めましたので、 そのうちちゃんとプルリクして貢献できるようになるかと^^;