Rubyを使って画像をRPGツクールMV用のマップに変換する

#1. はじめに
私はRPGツクールに於いて，システムやキャラクターの絵を作るのは好きですが，マップを作る事は苦手です．町のマップを作る場合，土台を描いて道を描いて家を描いて木々を描いて他の装飾を･･･何とか完成させても，他人の作ったマップのクォリティの高さに愕然とする事が多々ありました．

お陰でゲーム制作でも，マップを描く段階になると，PCの前に座っても作る気力が沸かなくなります．一方で，仕事中の休み時間等に数分だけ取って何かを作る，と言う方法は意外と長続きする事が分かりました．つまり，PCではなく携帯機器でマップの一部だけでも作成出来れば，この状況を打破出来るかも知れない！と言う考えに至ったわけです．

携帯機器でゲーム用のマップを作るにはどうすれば良いか？と言う事を色々考えた結果，ドット絵エディタなどで画像を作成し，それをRPGツクールMV用のjson形式に変換してしまえば良いと言う結論になりました．最近のツクールはデータがテキストになっていて，スクリプトとの相性がとても良いです．

#2. 変換の流れ
とても単純です．

 * 画像を参照し，1ドットずつRGB値を取得する
 * RGB値→マップチップIDのリストに従って変換する
 * json形式に出力する

これだけです．RGB値の取得は，バイナリを読んで自力で変換していくのは手間がかかりそうだったので，ImageMagickを使用する事にしました．マップチップのIDは，前もってRPGツクールMV側で調べておきます．

#3. ソース
Windows環境で動かす事を想定しているため，参考にする方は文字\の使い方等に注意して下さい．

```ruby:image2map.rb
require "open3"

def tr_color_chip(color, color_chip, default_id = "0000")
  for a1 in color_chip
    if(a1[0] == color)
      return a1[1]
    end
  end
  return default_id
end

input_image = ARGV[0]
output_map  = ARGV[1]
chipid_list = ARGV[2]

im_path  = "[ImageMagickのpath]"

xy_color     = []
color_chip   = []
chip_id_list = []

for list_line in File.open(chipid_list)
  if(list_line.include?("#"))
    color_chip << list_line.chomp.split(" ")
  end
end

### Reading image by ImageMagick

Open3.popen3( "#{im_path} #{input_image} txt:" ){|stdin, stdout, stderr, wait_thr|
  for s1 in stdout
    if(s1.include?("ImageMagick"))
      next
    end
    if(s1.include?(":") && s1.include?("#"))
      xy = s1.split(" ")[0].gsub(":","")
      x_c = xy.split(",")[0].to_i
      y_c = xy.split(",")[1].to_i
      color = s1.split(" ")[2]
      xy_color << [x_c, y_c, color]
    end
  end
}

### Calculating map size & Translation HTML color to ChipID

mapx, mapy = 0, 0
for a1 in xy_color
  mapx = a1[0] if(a1[0] > mapx)
  mapy = a1[0] if(a1[1] > mapy)
  chip_id_list << tr_color_chip(a1[2], color_chip)
end

tile_a = chip_id_list.join(",")
tile_b = ",0" * chip_id_list.size * 5

mapx = mapx + 1
mapy = mapy + 1

t_header = "\"autoplayBgm\":false,\"autoplayBgs\":false,\"battleback1Name\":\"\",\"battleback2Name\":\"\",\"bgm\":{\"name\":\"\",\"pan\":0,\"pitch\":100,\"volume\":90},\"bgs\":{\"name\":\"\",\"pan\":0,\"pitch\":100,\"volume\":90},\"disableDashing\":false,\"displayName\":\"\",\"encounterList\":[],\"encounterStep\":30,\"height\":#{mapy},\"note\":\"\",\"parallaxLoopX\":false,\"parallaxLoopY\":false,\"parallaxName\":\"\",\"parallaxShow\":true,\"parallaxSx\":0,\"parallaxSy\":0,\"scrollType\":0,\"specifyBattleback\":false,\"tilesetId\":1,\"width\":#{mapx},\n"
t_data = "\"data\":[#{tile_a}#{tile_b}],\n"
t_events = "\"events\":[\n]\n"

### json output

outm = File.open(output_map, "w")

outm.write("{\n")
outm.write(t_header)
outm.write(t_data)
outm.write(t_events)
outm.write("}")

outm.close
```

```
ruby image2map.rb image.png map.json list.txt
```

のように実行します．image.pngは入力画像，map.jsonは出力するマップです．list.txtはRGB値→マップチップIDのリストで，以下のように作成します．

```list.txt
#000000 2048
#FFFFFF 2816
```

左側のRGB値はHTMLカラーとしました．右側の番号がRPGツクールMV側のチップIDで，この例では，黒いドットが海，白いドットが陸地になります．

#4. 実行結果

![s8x8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652281/792d0be4-03d3-5d8b-29f1-1eacf5a4732e.png)
このような画像を作成しました．上の画像は拡大していますが，実際は8x8の非常に小さいサイズで描いています．

![m8x8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652281/f10ecebd-62de-5179-ece8-853edaab6613.png)
変換後のjsonを開いてみました．意図通り変換されている事が分かります．

#5. 終わりに

最近のRPGツクールは隣接するマップに応じて自動的に形が変わったり，レイヤを重ねたりと，非常に複雑なマップを作成する事が可能です．そのため，このような方法では詳細なマップを作る事は出来ません．しかし，マップ作りは基本的には，｢大まかな土台を作る｣→｢細かい装飾を付けていく｣流れで作る人が多く，この前半部分を作る事が狙いです．これで少しでもモチベーションが上がれば･･･．