突然はなしが変わってRuby/Tkでアニメーションを作る話
http://d.hatena.ne.jp/miura1729/20080302/1204443134
という記事のコードを基に、自分なりにすこし変形させてみた。
ビリヤードゲームでのボールの動きを真似してみた。
(下は動画ではありません、スイマセン)
ボールが 壁に反射した時/床を転がる時に だんだんと速度を落としていくようになっています。
$ cat ball2.rb
# See http://d.hatena.ne.jp/miura1729/20080302/1204443134
require 'rubygems'
require 'tk'
require 'singleton'
class Viewer < TkFrame
include TkComposite
WIDTH, HEIGHT = 512, 512
def initialize_composite
@frame.configure(:width=>WIDTH, :height=>HEIGHT)
@frame.grid_propagate(false)
@canvas = TkCanvas.new(@frame)
@canvas.configure(:width=>WIDTH, :height=>HEIGHT)
@canvas.grid('row'=>0, 'column'=>0, 'sticky'=>'news')
end
def draw_oval(x, y, r)
TkcOval.new(@canvas, x - r, y - r, x + r, y + r, 'fill' => :red)
end
end
class Field
include Singleton
def initialize
@view = Viewer.new
@view.pack(:expand=>true, :fill=>:both)
end
def draw_oval(x, y, r)
@view.draw_oval(x, y, r)
end
end
class Ball
@@field = Field.instance
def initialize(r, x, y, vx = 0, vy = 0, factorWall = 0.9, factorFloor= 0.99, minSpeed = 0.05)
@r, @x, @y, = r, x, y
@vx, @vy = vx, vy
@shape = @@field.draw_oval(@x, @y, @r)
@factorWall = factorWall
@factorFloor = factorFloor
@minSpeed = minSpeed
end
def resetV(v)
@vx, @vy = v[0], v[1]
end
def redraw
@shape.coords = [ @x - @r, @y - @r, @x + @r, @y + @r ]
end
def speeddownByWall
@vx, @vy = @vx * @factorWall, @vy * @factorWall
end
def speeddownByFloor
@vx, @vy = @vx * @factorFloor, @vy * @factorFloor
end
def compute_next_pos
speeddownByFloor
@x += @vx
@y += @vy
if (@y <= @r) || (Viewer::HEIGHT - @r <= @y) then
@vy *= (-1)
@y += @vy
speeddownByWall
end
if (@x <= @r) || (Viewer::WIDTH - @r <= @x) then
@vx *= (-1)
@x += @vx
speeddownByWall
end
if (@vx.abs + @vy.abs) < @minSpeed then
return false # delete Ball
end
redraw
return true # move Ball
end
end
def newBall
v = newV
Ball.new(@r, @initX, @initY, v[0], v[1])
end
def newV
th = rand * Math::PI * 2
[@vx * Math.cos(th), @vy * Math.sin(th)]
end
@r = 10
@vx, @vy = 30, 30
@initX, @initY = 15 + @r , 15 + @r
balls = [ newBall ]
steps = 0
timer = TkAfter.start(10, -1, lambda {
steps += 1
balls.each do |ball|
ball.resetV(newV) if !ball.compute_next_pos
end
balls << newBall if steps % 500 == 0
# puts balls.size if steps % 500 == 0
})
Tk.mainloop
ちょっと長くなってしまった。
同様のものを xfy/xvcd + SVG で書いたらどうなるだろう...
最近のコメント