SLGの移動可能範囲算出

シミュレーションゲームはマスに移動コストが決められていて、キャラの移動量からどのマスに移動できるかというのを計算して、その範囲を表示してあげる必要がある。
表示しないと不親切極まりない。
逆に、ユーザーがいちいち数えて移動先を選択して、移動できないマスを選択したら移動できずにそのターンが終わるとかいうひどいゲームがあってもいいかもしれない。いまどき。

さて、基本的にはそういう計算は再帰処理でやることになるわけだが、この手のゲームは作ったことがないし、興味も無かったから人のソースを見たりしたことも無かった。
ひらめき一発で作ったらどうなるのか、ということで。
やってみた。

めっちゃ適当だけど、範囲内をクリックしたら移動することはできる。
ゲームぽくするなら移動経路も保存しておいて、クリックしたら1マスずつ移動して見せるのがいいかもしれない。
範囲がちょっと見難いから何かしら手を入れた画像を作るか、シェーダを使って縁取りするとかなんかするといい。
その前にマップの画像をなんとかしろという話ではある。

require 'dxruby'

map_image = [
  Image.new(32,32,[128,128,128]),
  Image.new(32,32,[100,230,100]),
  Image.new(32,32,[0,200,0]),
  Image.new(32,32,[255,220,100]),
  Image.new(32,32,[255,100,0]),
  Image.new(32,32,[0,0,255])
]

$map = [
  [1,3,3,3,1,0,1,2,2,2,2,4,4,4,4,4],
  [3,3,3,3,2,0,1,1,2,2,2,4,4,4,4,4],
  [1,3,3,3,1,0,2,1,1,2,2,2,2,2,2,1],
  [5,1,3,3,1,0,1,1,1,1,1,1,2,2,2,2],
  [5,1,3,3,1,0,1,2,1,1,1,2,1,1,1,1],
  [5,1,2,3,1,0,0,1,1,2,1,1,1,1,2,1],
  [5,5,1,1,1,1,0,0,0,0,0,1,1,2,1,1],
  [5,5,5,5,5,1,1,1,1,1,0,0,0,0,1,1],
  [5,5,5,5,5,5,5,5,5,1,1,1,1,0,0,2],
  [5,5,5,5,1,1,1,1,5,5,5,5,1,1,0,1],
  [5,5,5,1,1,1,2,1,1,1,1,5,5,5,0,5],
  [5,5,5,1,2,4,4,4,4,4,1,1,2,1,0,1],
]

x = 5
y = 5
s = Sprite.new(x*32, y*32, Image.new(32,32).circle_fill(16,16,16,C_WHITE))
speed = 9

$d = [[0,0],[0,0],[0,1],[0,0],[-1,0],[0,0],[1,0],[0,0],[0,-1],[0,0]]

def find(x, y, speed, temp)
  [2,4,6,8].each do |i|
    tx = x + $d[i][0]
    ty = y + $d[i][1]
    next if tx < 0 or tx > 15 or ty < 0 or ty > 11

    if speed - $map[ty][tx] - 1 >= 0
      if temp[ty][tx] == nil or temp[ty][tx] < speed - $map[ty][tx] - 1
        temp[ty][tx] = speed - $map[ty][tx] - 1
        find(tx, ty, speed - $map[ty][tx] - 1, temp)
      end
    end
  end
end

range = Image.new(32,32,[150,255,180,180])
cursor = Image.new(32,32).box(0,0,31,31,C_WHITE)

temp = Array.new(12) { Array.new(15) }
find(x, y, speed, temp)

Window.loop do

  if Input.mouse_push?(M_LBUTTON)
    if temp[Input.mouse_pos_y / 32][Input.mouse_pos_x / 32]
      x = Input.mouse_pos_x / 32
      y = Input.mouse_pos_y / 32
      temp = Array.new(12) { Array.new(15) }
      find(x, y, speed, temp)
      s.x = x * 32
      s.y = y * 32
    end
  end

  Window.draw_tile(0,0,$map,map_image,0,0,16,12)

  (0..11).each do |iy|
    (0..15).each do |ix|
      if temp[iy][ix]
        Window.draw(ix*32, iy*32, range)
      end
    end
  end

  s.draw
  Window.draw((Input.mouse_pos_x / 32) * 32, (Input.mouse_pos_y / 32) * 32, cursor)

  break if Input.key_push?(K_ESCAPE)
end