衝突判定範囲の描画

DXRubyEx用には作ってあったのだが、DXRubyにSpriteを追加してから衝突判定範囲を描画する機能が無かったので作ってみた。

これはDXRuby添付の衝突判定サンプルにコードを追加した画面だが、範囲が見えやすいようにSprite#collision_syncをfalseにしてある。描画の回転・スケーリングに衝突判定範囲が追従しないのでズレて見えるということだ。

Spriteの派生クラスにincludeすることでdrawをオーバーライドして、self.imageとself.collisionから衝突判定範囲画像を生成して描画するようになっている。つまりSpriteの派生クラスを作らないと使えない。まあ普通作るからこれでいいかなーという感じである。
衝突判定範囲は描画と連動して回転・スケーリングするものなので、Spriteの各パラメータを衝突判定範囲の描画に反映させている。Spriteは多少複雑なので面倒なことになっているが、よく見てみれば見たままだと思う。愚直に書いただけだ。

まともにテストしてないのでバグってる可能性は高い。

module HitRange
  def draw
    super
    if self.visible and self.collision_enable and !self.vanished?
      if @hitrange_image == nil or 
         @hitrange_image.width != self.image.width or 
         @hitrange_image.height != self.image.height

        @hitrange_image.dispose if @hitrange_image != nil
        @hitrange_image = Image.new(self.image.width, self.image.height)

        color = [200, 255, 255, 0]
        color_fill = [100, 255, 255, 0]

        if self.collision == nil
          @hitrange_image.box_fill(0, 0, @hitrange_image.width-1, @hitrange_image.height-1, color_fill)
          @hitrange_image.box(0, 0, @hitrange_image.width-1, @hitrange_image.height-1, color)
        else
          temp = self.collision
          temp = [temp] if temp[0].class != Array
          temp.each do |col|
            case col.size
            when 2 # point
              @hitrange_image[col[0], col[1]] = color
            when 3 # circle
              @hitrange_image.circle_fill(col[0], col[1], col[2], color_fill)
              @hitrange_image.circle(col[0], col[1], col[2], color)
            when 4 # box
              @hitrange_image.box_fill(col[0], col[1], col[2], col[3], color_fill)
              @hitrange_image.box(col[0], col[1], col[2], col[3], color)
            when 6 # triangle
              @hitrange_image.triangle_fill(col[0], col[1], col[2], col[3], col[4], col[5], color_fill)
              @hitrange_image.triangle(col[0], col[1], col[2], col[3], col[4], col[5], color)
            end
          end
        end
      end

      hash = {}
      if self.collision_sync
        hash[:scale_x] = self.scale_x
        hash[:scale_y] = self.scale_y
        hash[:center_x] = self.center_x
        hash[:center_y] = self.center_y
        hash[:angle] = self.angle
      end
      hash[:z] = self.z + 1

      ox = oy = 0
      if self.offset_sync
        ox = self.center_x
        oy = self.center_y
      end

      target = self.target ? self.target : Window

      target.draw_ex(self.x - ox, self.y - oy, @hitrange_image, hash)
    end
  end
end