多関節キャラ
リクエストがあったので簡単な多関節キャラを作ってみた。
理屈としてはオブジェクトに次のオブジェクトとの接続位置を持たせて、自分の姿勢にあわせて接続位置を回転して、次のオブジェクトはその位置をベースに自分を回転させて、という処理を再帰的に行えば可能だ。
ベースパーツ用のクラスとその他のパーツ用のクラスは分けたほうがいいのかもしれないが、面倒だったので共通にした。
シンプルにするためにパーツは円形、接続位置は同じにしてあるが、長細いパーツにすれば昆虫の足ぽいものを作ることもできるだろう。
面白いからもうちょっと動きをどうにかしてサンプルに入れようと思う。
昨日のやつとは違って今回はDXRuby1.3.4で動くので是非動くところをみてみて。
※コードに目を覆うような無駄な計算があったので修正しました。
#!ruby -Ks require 'dxruby' class Parts < Sprite attr_accessor :next, :joint_xp, :joint_yp, :joint_xn, :joint_yn, :joint_angle def initialize super @next = nil @joint_xp = @joint_yp = @joint_xn = @joint_yn = @joint_angle = 0 end # ベースパーツは引数省略で呼ばれる。接続パーツのupdateを呼ぶ。 def update(jx = nil, jy = nil, angle = 0) if jx 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 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 angle = 0 angle_d = 1 Window.loop do angle = angle + angle_d if angle > 20 or angle < -20 angle_d = -angle_d end parts.each do |p| p.joint_angle = angle end pb.update pb.draw end