多関節キャラ2

マウスのほうを向くようにして、オマケで角度に乱数を導入してみたらなんかすごく気持ち悪い動きになったので置いておく。

#!ruby -Ks
require 'dxruby'

class Parts < Sprite
  attr_accessor :prev, :joint_xp, :joint_yp, :joint_xn, :joint_yn, :joint_angle
  attr_reader :next

  def initialize
    super
    @next = nil
    @joint_xp = @joint_yp = @joint_xn = @joint_yn = @joint_angle = 0
  end

  def next=(n)
    @next = n
    n.prev = self
  end

  # ベースパーツは引数省略で呼ばれる。接続パーツのupdateを呼ぶ。
  def update(jx = nil, jy = nil, angle = 0)
    if jx
      @joint_angle += rand() * 1.2 - 0.6
      self.angle = @joint_angle + angle
      self.x = -@joint_xp + jx
      self.y = -@joint_yp + jy
      self.center_x = @joint_xp
      self.center_y = @joint_yp
      if @next
        jnx = (-@joint_xp + @joint_xn) * Math.cos(Math::PI * self.angle / 180) - (-@joint_yp + @joint_yn) * Math.sin(Math::PI * self.angle / 180) + jx
        jny = (-@joint_xp + @joint_xn) * Math.sin(Math::PI * self.angle / 180) + (-@joint_yp + @joint_yn) * Math.cos(Math::PI * self.angle / 180) + jy
        @next.update(jnx, jny, self.angle)
      end
    else
      if @next
        jnx = (@joint_xn - self.image.width / 2) * Math.cos(Math::PI * self.angle / 180) - (@joint_yn - self.image.height / 2) * Math.sin(Math::PI * self.angle / 180) + self.x + self.image.width / 2
        jny = (@joint_xn - self.image.width / 2) * Math.sin(Math::PI * self.angle / 180) + (@joint_yn - self.image.height / 2) * Math.cos(Math::PI * self.angle / 180) + self.y + self.image.height / 2
        @next.update(jnx, jny, self.angle)
      end
    end
  end

  def draw
    super
    @next.draw if @next
  end

  def guide
    mx,my = Input.mouse_pos_x, Input.mouse_pos_y
    x = (@joint_xn - @joint_xp) * Math.cos(Math::PI * self.angle / 180) - (@joint_yn - @joint_yp) * Math.sin(Math::PI * self.angle / 180) + self.x + @joint_xp
    y = (@joint_xn - @joint_xp) * Math.sin(Math::PI * self.angle / 180) + (@joint_yn - @joint_yp) * Math.cos(Math::PI * self.angle / 180) + self.y + @joint_yp
    mangle = Math.atan2(my - y, mx - x) / Math::PI * 180 +90
    angle = (mangle + (180 - (self.angle % 360))) % 360

    if 180 < angle
      @joint_angle = @joint_angle + 1
      if @joint_angle > 30
        @joint_angle = 30
        @prev.guide if @prev
      end
    elsif 180 > angle
      @joint_angle = @joint_angle - 1
      if @joint_angle < -30
        @joint_angle = -30
        @prev.guide if @prev
      end
    end
  end
end

# ベースパーツ
pb = Parts.new
pb.image = Image.new(60,60).circle_fill(30,30,30,[255,255,255])
pb.joint_xn = 30 # 次のパーツへの接続x
pb.joint_yn = 10 # 次のパーツへの接続y
pb.x = 300
pb.y = 300

p = pb
parts = [[255,0,0], [0,255,0], [0,0,255], [0,255,255], [255,0,255], [255,255,0]].map do |color|
  p = p.next = Parts.new # nextに次のパーツオブジェクトを入れる
  p.image = Image.new(60,60).circle_fill(30,30,30,color)
  p.joint_xp = 30 # 前のパーツからの接続x
  p.joint_yp = 50 # 前のパーツからの接続y
  p.joint_xn = 30 # 次のパーツへの接続x
  p.joint_yn = 10 # 次のパーツへの接続y
  p
end


Window.loop do

  parts[5].guide

  pb.update
  pb.draw
end