$dimensions = 600 PI=3.141592653 def deg2rad deg deg/180.0*PI end class Actor attr_accessor :offscreen def initialize(x,y,dir,v) @x=x; @y=y; @d=dir; @v=v; self.color(rand(255),rand(255),rand(255)) end def draw $app.fill @color $app.oval(@x-10.round,@y-10.round,20,20) unless @offscreen || @y<10 || @x<10 end def color r,g,b @color=rgb(r,g,b) end def tick return if @offscreen @x+= @v * Math.cos(@d) @y+= -@v * Math.sin(@d) if @x < 0 || @x > 620 || @y < 0 || @y > 620 @offscreen=true end if @x>450 && @x<460 if -(Math.sin(@d)) < 0 @d+=PI else @d-=PI end end end def to_s "(#{@x},#{@y}) #{@v} -> #{@d}" end end Shoes.app :width => 600, :height => 600, :title => "Clogs" do $app = self actors=[] 5.times do actors.push(Actor.new(300,300,deg2rad(rand(360)),rand(5)+1)) end animate(30) do clear do actors.each do |actor| actor.tick actor.draw end end end animate(1) do actors=actors.delete_if do |_| _.offscreen end end startx=0;starty=0; click do |btn,x,y| startx=x;starty=y end ########## important bit ########## release do |btn,x,y| dx=x-startx;dy=y-starty h=Math.sqrt(dx*dx+dy*dy) if dx==0 && dy==0 dir=deg2rad(rand(360)) elsif dx==0 dir=PI/2 if dy<0 dir=-PI/2 if dy>0 elsif dx<0 dir=Math.atan(-(dy.to_f)/(dx.to_f))+3.141592653 else dir=Math.atan(-(dy.to_f)/(dx.to_f)) end if(dx==0 && dy==0) v=1 else v=h/10 end puts "dx: #{dx}, dy: #{dy} -> #{dir}" actor=Actor.new(startx,starty,dir,v) actors.push(actor) end ########## End important bit ########## end