棒人間エディタその後

ほったらかしになってた棒人間エディタをまたいじっていた。

線の先に線をつなげるようにして、連動して回転するようにしたところ、腕の付け根が表現できないことに気付いて、急遽「首」を追加してみたのだが、何かが変だ。
関節を増やしすぎても使いにくくなるし、簡単で柔軟な棒人間というのはなかなか難しい。
たかが棒人間、されど棒人間。棒人間を笑うものは棒人間に泣くのだ。
なんにせよテキトーに作ったものをきちんとさせるのは骨が折れる。
せっかくなのでソースを置いておく。
頭が移動できないのも何とかしなければ。

# 棒人間エディタ
require 'dxruby'

class Line
  def initialize(a)
    @angle, @len, @connect, @slen = a
    @image = Image.new(32, 32)
    @x = 0
    @y = 0
  end
  def update(image, x1, y1)
    @image.box(0,0,31,31,[0,0,0,0])
    x1 = Math.cos(Math::PI * 2 * @angle / 360) * @slen + x1
    y1 = Math.sin(Math::PI * 2 * @angle / 360) * @slen + y1
    x2 = Math.cos(Math::PI * 2 * @angle / 360) * @len + x1
    y2 = Math.sin(Math::PI * 2 * @angle / 360) * @len + y1
    @image.line(x1+0.5, y1+0.5, x2+0.5, y2+0.5, [255,255,255,255])
    image.line(x1+0.5, y1+0.5, x2+0.5, y2+0.5, [255,255,255,255])

    @connect.each do |d|
      d.update(image, x2, y2)
    end
    @x = x1
    @y = y1
  end
  def check(x, y)
    @image[x, y] != [0,0,0,0]
  end
  def change(angle)
    @connect.each do |d|
      d.change(d.angle + (angle - @angle))
    end
    @angle = angle
  end
attr_accessor :x, :y, :angle
end

screen = Image.new(640, 480)
char = Image.new(32, 32)

bou = []
bou.push(Line.new([90, 6, [], 0])) # 左足先
bou.push(Line.new([90, 6, [bou[0]], 0])) # 左足根元
bou.push(Line.new([180, 6, [], 0])) # 右足先
bou.push(Line.new([180, 6, [bou[2]], 0])) # 右足根元
bou.push(Line.new([0, 5, [], 0])) # 左手先
bou.push(Line.new([0, 5, [bou[4]], 0])) # 左手根元
bou.push(Line.new([180, 5, [], 0])) # 右手先
bou.push(Line.new([180, 5, [bou[6]], 0])) # 右手根元
bou.push(Line.new([90, 10, [bou[1], bou[3]], 0])) # 胴体
bou.push(Line.new([90, 2, [bou[8], bou[5], bou[7]], 3])) # 首
moto = 9
bou[moto].update(char, 15, 7)

select = nil

Window.loop do
  x, y = Input.mousePosX, Input.mousePosY
  if Input.mouseDown?(M_LBUTTON) then
    if select == nil then
      bou.each do |line|
        if line.check(x/16, y/16) then
          select = line
          break
        end
      end
    end
  else
    select = nil
  end

  if select != nil then
    select.change(Math.atan2(y/16 - select.y, x/16 - select.x) * 360 / Math::PI / 2)
  end

  # 棒人間データ更新
  char.box(0,0,31,31,[0,0,0,0])
  bou[moto].update(char, 15, 7)
  char.circle(15, 7, 3, [255, 255, 255, 255])

  # 描画
  for i in 0..31
    for j in 0..31
      screen.box(j * 16, i * 16, j * 16 + 15, i * 16 + 15, char[j, i])
    end
  end
  Window.draw(0,0,screen)

  break if Input.keyPush?(K_ESCAPE)
end

例によってパブリックドメイン宣言。