Ruby でタイルマップ生成スクリプト

ruby

以下のような正確な png ファイルを

16×16 のタイルに分割して

以下のようなタイルを生成します。


ファイル名は 0.png, 1.png, 2.png 等になります。

同時に、どのタイルがどの部分に対応するかをしめす
csv も生成します。

csvのイメージ
(例えば64×64のイメージの場合 3×3 のタイルになる)

1, 2, 0
0, 0, 1
1, 1, 1

Ruby から ImageMagick を扱うためのライブラリ
RMagick を使用します。

RMagick のインストール(macOS)

% brew install imagemagick
% brew install pkg-config
% sudo gem install rmagick
実行方法

分割したいファイルを指定して以下のように
実行します。

% ruby divide_into_tile.rb hoge.rb

成功すると
output/*.png
tilemap.csv
が生成されます。

Ruby スクリプトは以下のようになります。

divide_into_tile.rb

require "RMagick"
require "csv"
require "fileutils"

include Magick

filename = ARGV[0]

unless filename
  puts "please set input image filename"
  puts "ex. % ruby divide_into_tile.rb hoge.jpg"
  exit
end

unless File.exist?(filename)
  puts "no such file #{filename}"
  exit
end

image_load = ImageList.new(filename)
# image_load = Magick::Image.read('field.png').first

width = image_load.columns
height = image_load.rows

puts " width #{width}"
puts " height #{height}"

sprite_x_count = width / 16
sprite_y_count = height / 16

tile_count = 0

FileUtils.mkdir_p("output")

metric = Magick::PeakSignalToNoiseRatioErrorMetric

tilemap_csv = CSV.open('tilemap.csv','w')
    
for num_y in 0 .. sprite_y_count - 1 do
  pos_y = num_y * 16

  array = []

  for num_x in 0..sprite_x_count - 1 do
    pos_x = num_x * 16

   # puts " "
   # puts "------------"
    puts "analysing x #{num_x} / #{sprite_x_count - 1}, y: #{num_y} / #{sprite_y_count - 1}"

    image_cropped = image_load.crop(pos_x, pos_y, 16, 16)

    if tile_count == 0
      image_name = "#{tile_count}.png"

    #  puts "writing #{image_name}"
 
      image_cropped.write("output/#{image_name}")

      array.append(0)

      tile_count += 1
    else
      # 過去に同じのないかチェック
      is_matched = false

      for num_tile in 0 .. tile_count - 1 do
      	image_tile_name = "#{num_tile}.png"
        image_tile = ImageList.new("output/#{image_tile_name}")

        diff = image_cropped.compare_channel(image_tile, metric)[1]

      #  puts "check match diff #{diff}"

        if diff == Float::INFINITY
       #   puts "matched"
          is_matched = true

          array.append(num_tile)

          break
        end
      end

      unless is_matched
        # 一個もマッチしない
        image_name = "#{tile_count}.png"

     #   puts "writing #{image_name}"
 
        image_cropped.write("output/#{image_name}")

        array.append(tile_count)

        tile_count += 1
      end
    end
  end

  tilemap_csv.puts array
end

tilemap_csv.close

コメント

タイトルとURLをコピーしました