As a late night project, I converted some VB code I wrote years ago to create an animated starfield. My original VB code can be found here [
1]. 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, and not *quite* as complete as the original, 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
# --- give us a way out...
bind . <Control-c> {destroy .}
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 <B1-Motion> {getNewVortex %x %y}
bind .c1 <ButtonPress-1> {getNewVortex %x %y}
wm title . "StarField Demo"
}
main