Bouncing Balls

escargo 16 Mar 2003 - The following code appeared recently in the comp.lang.tcl news group (posted by Ed Suominen). I made two changes; I added the wm withdraw . to get the console window to go away, and I changed a while { 1 }... to a while { [winfo ...] } so that no error gets thrown if you click on the close box for the top level window with the bouncing balls.

## Bouncing Balls
## Ed Suominen -- dedicated to the public domain
package require Tk

## Procs
proc rcolor { colorList } {
    return [lindex $colorList \
                [expr { int(rand()*[llength $colorList]) }] ]
}

wm withdraw .

## Configuration
set width 600
set height 500
set radius 20
set colorList {red blue yellow white orange green}

## CANVAS SETUP
destroy .canvas
set w [toplevel .canvas]
set m [label $w.m]
set c [canvas $w.c -bg gray -width $width -height $height]
pack $m $c -side top
$m configure -text "Bouncing Balls"

bind $c left { puts left }

## Item Setup
catch {unset itemList}
for { set itemCount 0 } { $itemCount < 10 } { incr itemCount } {
    set handle [$c create oval \
                    [expr {$width/2-$radius}] \
                    [expr {$height/2-$radius}] \
                    [expr {$width/2+$radius}] \
                    [expr {$height/2+$radius}] \
                    -fill [rcolor $colorList] \
                    -outline black]
    set DX($handle) [expr { (rand()-0.5)*10 }]
    set DY($handle) [expr { (rand()-0.5)*10 }]
    lappend itemList $handle
}

set script {
    foreach oval $itemList {
        $c move $oval $DX($oval) $DY($oval)
        foreach i {xmin ymin xmax ymax} j [$c coords $oval] {
            set $i $j
        }
        if { $xmax > $width || $xmin < 0 } {
            set DX($oval) [expr { -$DX($oval) }]
        }
        if { $ymax > $height || $ymin < 0 } {
            set DY($oval) [expr { -$DY($oval) }]
        }
    }
    after 25 { eval $script }
}

eval $script

David Easton: See Colliding balls for a similar example in which the balls collide with each other.

Ed Suominen: David's example is well worth a look. It uses some pretty advanced calculations to create a very realistic simulation.