As a late night project, I converted some VB code I wrote years ago to create an animated starfield. I must say that the job was much easier, and required less code in TK than my original VB version. Anyway, it's not perfect, but it's kind of interesting... Try clicking and dragging the mouse in canvas area. - Jeff Godfrey ---- proc main {} { initVars buildUI getNewVortex [expr {$::global(sfWidth) / 2}] [expr {$::global(sfHeight) / 2}] initStars animLoop } proc initVars {} { set ::global(sfWidth) 800 set ::global(sfHeight) 600 set ::global(maxStars) 100 } proc initStars {} { set xl $::global(xlVortex) set xh $::global(xhVortex) set yl $::global(ylVortex) set yh $::global(yhVortex) for {set i 1} {$i <= $::global(maxStars)} {incr i} { set xs [expr {($xh - $xl - 1) * rand() + $xl}] set ys [expr {($yh - $yl - 1) * rand() + $yl}] set me [.c1 create line $xs $ys $xs $ys -width 2 -fill black -tag "star"] # --- calculate a random star speed from .1 to 1.1 set ::global(speed,$me) [expr {rand() + 0.1}] } } proc animLoop {} { set xCen $::global(xCenVortex) set yCen $::global(yCenVortex) set sfWidth $::global(sfWidth) set sfHeight $::global(sfHeight) set xlVortex $::global(xlVortex) set xhVortex $::global(xhVortex) set ylVortex $::global(ylVortex) set yhVortex $::global(yhVortex) foreach star [.c1 find withtag "star"] { set starCoords [.c1 coords $star] set xs [lindex $starCoords 0] set ys [lindex $starCoords 1] set xe [lindex $starCoords 2] set ye [lindex $starCoords 3] set speed $::global(speed,$star) # --- calculate the X and Y distances from the current vortex center set xVector [expr {abs($xCen - $xe)}] set yVector [expr {abs($yCen - $ye)}] # --- calculate the star's X direction and length based on # the current vortex X center if {$xe > $xCen} { set newXe [expr {$xe + int($xVector * 0.2) * $speed}] } else { set newXe [expr {$xe - int($xVector * 0.2) * $speed}] } # --- calculate the star's Y direction and length based on # the current vortex Y center if {$ye > $yCen} { set newYe [expr {$ye + int($yVector * 0.2) * $speed}] } else { set newYe [expr {$ye - int($yVector * 0.2) * $speed}] } # --- if new start coord is off the screen, reset it "near" the # vortex center if {$xe < 0 || $xe > $sfWidth || $ye < 0 || $ye > $sfHeight} { set xs [expr {($xhVortex - $xlVortex - 1) * rand() + $xlVortex}] set ys [expr {($yhVortex - $ylVortex - 1) * rand() + $ylVortex}] .c1 coords $star $xs $ys $xs $ys .c1 itemconfigure $star -fill black } else { set range [getStarRange $xe $ye] set colorVector [expr {$range * 25}] set color [format "#%x%x00" $colorVector $colorVector] .c1 coords $star $xe $ye $newXe $newYe .c1 itemconfigure $star -fill $color } } update after 1 animLoop } # --- Calculate a star's brightness based on its distance from the vortex. # Since this is called within the animation loop for *every* star, it is # computationally expensive. This should be improved, but it'll do for # now... proc getStarRange {x y} { set xVector [expr {abs($::global(xCenVortex) - $x)}] set yVector [expr {abs($::global(yCenVortex) - $y)}] # --- Calculate the distance from vortex center set dist [expr {sqrt($xVector * $xVector + $yVector * $yVector)}] # --- return a value in the range of 1-10 set range [expr {int(($dist / $::global(maxRad)) * 10)}] if {$range < 1} { set range 1 } elseif {$range > 10} { set range 10 } return $range } proc getNewVortex {xVortexCen yVortexCen} { set xCen $xVortexCen set yCen $yVortexCen # --- calculate a range distance from teh vortex center set xOffset [expr {int($::global(sfWidth) * 0.1)}] set yOffset [expr {int($::global(sfHeight) * 0.1)}] # --- calculate the GLOBAL actual range for both axis' # a new star will always be "born" within this area... set xlVortex [expr {$xCen - $xOffset}] set xhVortex [expr {$xCen + $xOffset}] set ylVortex [expr {$yCen - $yOffset}] set yhVortex [expr {$yCen + $yOffset}] # --- Calculate a "maximum screen radius". This is used in the # star's brightness calculation if {$::global(sfWidth) < $::global(sfHeight)} { set maxRad [expr {$::global(sfWidth) / 2}] } else { set maxRad [expr {$::global(sfHeight) / 2}] } set ::global(xCenVortex) $xCen set ::global(yCenVortex) $yCen set ::global(xlVortex) $xlVortex set ::global(xhVortex) $xhVortex set ::global(ylVortex) $ylVortex set ::global(yhVortex) $yhVortex set ::global(maxRad) $maxRad } proc buildUI {} { canvas .c1 \ -width $::global(sfWidth) \ -height $::global(sfHeight) \ -background black \ -highlightthickness 0 \ -borderwidth 0 pack .c1 -fill both -expand 1 bind .c1 {getNewVortex %x %y} bind .c1 {getNewVortex %x %y} wm title . "StarField Demo" } main