MC logo

Bouncing Balls

^  Ruby Example Code

<<Host Lookup bounce.rb Binding and Actions>>
#!/usr/bin/ruby

#
# This creates a simple animation of five balls bouncing around inside a 
# rectagle.  Balls bounce off the sides, but pass through each other.  Nothing
# fancy.
#

# Import the library.
require 'tk'

# Dot diameter.
Diameter = 10

# Update rate (ms).
Frequency = 25

# Canvas size.
Width = 400
Height = 300

# Set defaults.  Some we keep in constants to use later.
BG = '#ccccff'
TkOption.add('*background', BG)

# Root window.
root = TkRoot.new('background' => BG) { title 'Bouncy, Bouncy' }

# Canvas.
c = TkCanvas.new(root) {
  width Width
  height Height
  pack('fill' => 'both')
}

# This is the circle that wanders around the canvas.
class MovingCircle < TkcOval 
  # Create with a moving circle on the canvas c with indicated color.
  def initialize(c, color)
    # Remember the canvas.
    @canv = c

    # Choose an initial location at random and create the object there.
    @xpos = rand(Width - Diameter)
    @ypos = rand(Height - Diameter)
    super(c, @xpos, @ypos, @xpos + Diameter, @ypos + Diameter, 'fill' => color)

    # Chose a velocity at random.  1 to 3 pixels per Frequency in each
    # dimension.
    @delx = (rand(3)+1)*(if rand(2) == 1 then 1 else -1 end)
    @dely = (rand(3)+1)*(if rand(2) == 1 then 1 else -1 end)

    # Start moving
    Tk.after(Frequency, proc { self.move } )
  end

  # This adjusts a single dimension by one step, taking account of the
  # walls.  Send a position, increment, and limit, and get back a new pos
  # and new increment (which might have its sign changed).
  def del(pos, inc, limit)
    # Move
    pos += inc

    # See if we hit the top or left, and reverse.
    if pos < 0 then
      pos = -pos
      inc = -inc

    # Likewise check for hitting the right or bottom
    elsif pos > limit - Diameter then
      pos = (limit - Diameter) - (pos - (limit - Diameter))
      inc = -inc
    end

    # Send back the results.
    return pos, inc
  end

  # Move one step, then schedule the next move.
  def move
    # Remember current position, and compute the new one.
    oldx, oldy = @xpos, @ypos
    @xpos, @delx = del(@xpos, @delx, Width)
    @ypos, @dely = del(@ypos, @dely, Height)
    
    # Tell Tk about it.
    @canv.move(self, @xpos - oldx, @ypos - oldy)

    Tk.after(Frequency, proc { self.move } )
  end
end

# Make several balls of different color.
for color in [ '#FF9999', '#99FFFF', '#005588', '#992211', '#FF0055' ]
  MovingCircle.new(c, color)
end

Tk.mainloop
<<Host Lookup Binding and Actions>>