Created
March 22, 2015 17:46
-
-
Save unak/fa8c3c92e3b1e4df769c to your computer and use it in GitHub Desktop.
中点変位法によるランダム地形生成器
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!ruby | |
require 'zlib' | |
PNG = 'sample.png' | |
WIDTH = 192 | |
HEIGHT = 192 | |
# 中点変位法による基礎データ生成 | |
d = [WIDTH, HEIGHT].max | |
m = 1 | |
m *= 2 while m < d | |
d = m | |
map = [[]] | |
map[0][0] = rand(256) | |
map[0][d] = rand(256) | |
map[d] = [] | |
map[d][0] = rand(256) | |
map[d][d] = rand(256) | |
offx = 0 | |
offy = 0 | |
while d > 0 | |
0.step(m - 1, d) do |offy| | |
0.step(m - 1, d) do |offx| | |
map[offy + d / 2] = [] unless map[offy + d / 2] | |
map[offy + d / 2][offx + d / 2] = ((map[offy][offx] + map[offy][offx + d] + map[offy + d][offx] + map[offy + d][offx + d]) / 4.0 + ((rand(d) - d / 2) * d / m)).to_i | |
if offy <= 0 | |
map[offy][offx + d / 2] = ((map[offy][offx] + map[offy][offx + d] + map[offy + d / 2][offx + d / 2]) / 3.0 + ((rand(d) - d / 2) * d / m)).to_i | |
else | |
map[offy][offx + d / 2] = ((map[offy][offx] + map[offy][offx + d] + map[offy + d / 2][offx + d / 2] + map[offy - d / 2][offx + d / 2]) / 4.0 + ((rand(d) - d / 2) * d / m)).to_i | |
end | |
if offx <= 0 | |
map[offy + d / 2][offx] = ((map[offy][offx] + map[offy + d][offx] + map[offy + d / 2][offx + d / 2]) / 3.0 + ((rand(d) - d / 2) * d / m)).to_i | |
else | |
map[offy + d / 2][offx] = ((map[offy][offx] + map[offy + d][offx] + map[offy + d / 2][offx + d / 2] + map[offy + d / 2][offx - d / 2]) / 4.0 + ((rand(d) - d / 2) * d / m)).to_i | |
end | |
map[offy + d / 2][offx + d] = ((map[offy][offx + d] + map[offy + d][offx + d] + map[offy + d / 2][offx + d / 2]) / 3.0 + ((rand(d) - d / 2) * d / m)).to_i | |
map[offy + d][offx + d / 2] = ((map[offy + d][offx] + map[offy + d][offx + d] + map[offy + d / 2][offx + d / 2]) / 3.0 + ((rand(d) - d / 2) * d / m)).to_i | |
end | |
end | |
d /= 2 | |
end | |
# いらん範囲は捨てる | |
map = map[0, HEIGHT].map{|e| e[0, WIDTH]} | |
# 各ピクセルの最大値・最小値を取って、0~255に正規化する | |
max, min = 0, 255 | |
HEIGHT.times do |y| | |
WIDTH.times do |x| | |
max = [map[y][x], max].max | |
min = [map[y][x], min].min | |
end | |
end | |
diff = max - min | |
if diff < 255 | |
rate = 255.0 / diff | |
HEIGHT.times do |y| | |
WIDTH.times do |x| | |
map[y][x] = ((map[y][x] - min) * rate).to_i | |
end | |
end | |
end | |
# パレット生成(てきとー) | |
col = [] | |
col[0] = [0, 0, 0x10] | |
col[64] = [0x40, 0x40, 0xff] | |
col[72] = [0xc0, 0xc0, 0xc0] | |
col[80] = [0x60, 0xc0, 0x60] | |
col[128] = [0x40, 0xc0, 0x40] | |
col[192] = [0x20, 0x90, 0x20] | |
col[208] = [0x80, 0x60, 0x60] | |
col[224] = [0x90, 0x80, 0x80] | |
col[255] = [0xff, 0xff, 0xff] | |
col.size.times do |n| | |
unless col[n] | |
x = n - 1 | |
while true | |
prev = col[x] | |
break if col[x] | |
x -= 1 | |
end | |
y = n + 1 | |
while true | |
break if col[y] | |
y += 1 | |
end | |
col[n] = [] | |
col[n][0] = (col[x][0] + (col[y][0] - col[x][0]) * 1.0 / (y - x)).to_i | |
col[n][1] = (col[x][1] + (col[y][1] - col[x][1]) * 1.0 / (y - x)).to_i | |
col[n][2] = (col[x][2] + (col[y][2] - col[x][2]) * 1.0 / (y - x)).to_i | |
end | |
end | |
# PNG出力 | |
# やってることの中身はmameさんの日記を参照 | |
# http://d.hatena.ne.jp/ku-ma-me/20091003/ | |
def chunk(hdr, data) | |
[data.bytesize, hdr, data, Zlib.crc32(hdr + data)].pack('NA4A*N') | |
end | |
open(PNG, 'wb') do |f| | |
f.print "\x89PNG\r\n\x1a\n" | |
f.print chunk('IHDR', [WIDTH, HEIGHT, 8, 2, 0, 0, 0].pack('NNCCCCC')) | |
data = '' | |
HEIGHT.times do |y| | |
data << [0, *map[y].map{|e| col[e]}.flatten].pack('C*') | |
end | |
f.print chunk('IDAT', Zlib.deflate(data, 9)) | |
f.print chunk('IEND', '') | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment