}
proc poly args {eval .c create polygon $args} proc sun {x y r} { .c create oval $x $y [expr $x+$r] [expr $y+$r] -fill red -tag sun set ::g(sun,dy) -1 sun' .c lower sun } proc sun' {} { .c lower star .c move sun 1 $::g(sun,dy) upvar #0 g(bright) bright foreach {x0 y0 x1 y1} [.c bbox sun] break set bright [expr 256-$y0] set bgcolor [color [expr $bright/1.5] [expr $bright/1.5] $bright] .c config -background $bgcolor if {$bright<100} { .c itemconfig star -fill grey[expr 100-$bright/3] } else { .c itemconfig star -fill $bgcolor } set suncolor [color 255 [expr {$bright*1}] 0] .c itemconfig sun -fill $suncolor -outline $suncolor set dt 1000 if {[lindex [.c bbox sun] 3]<0} { set dt 10000 .c move sun 200 0 set ::g(sun,dy) 1 } if {[lindex [.c bbox sun] 1]>200} { set dt 5000 .c move sun -700 0 set ::g(sun,dy) -1 } after $dt sun' } proc stars {n} { for {set i 0} {$i<$n} {incr i} { set x [expr rand()*640] set y [expr rand()*200] .c create oval $x $y [expr $x+2] [expr $y+2] -fill white \ -outline {} -tag star } } proc color {r g b} { foreach i {r g b} { if [set $i]<0 {set $i 0} if [set $i]>255 {set $i 255} } format #%02x%02x%02x [expr round($r)] [expr round($g)] [expr round($b)] } proc funicular {x0 y0 x1 y1} { .c create line $x0 $y0 $x1 $y1 .c create rect $x0 [expr $y0+4] [expr $x0+30] [expr $y0+18] \ -fill red -tag fcar .c create rect [expr $x0+14] [expr $y0-10] [expr $x0+16] [expr $y0+5]\ -fill grey -tag fcar poly [expr $x0+8] [expr $y0-4] [expr $x0+6] [expr $y0-2] \ [expr $x0+20] [expr $y0-14] [expr $x0+22] [expr $y0-12]\ -fill black -tag fcar set x [expr $x0+2] set y [expr $y0+7] foreach i {1 2 3} { .c create rect $x $y [expr $x+8] [expr $y+6] -fill white\ -tag fcar incr x 9 } poly 5 388 5 360 42 332 42 388 -fill tan -outline black .c create rect 9 370 16 380 -fill white .c create rect 19 370 26 380 -fill white .c create rect 29 370 36 380 -fill white poly 445 60 475 65 475 100 445 120 -fill grey80 \ -outline black -tag mountain set ::g(funicular,dir) 1 after 0 funicular' } proc funicular' {} { set dir $::g(funicular,dir) .c move fcar [expr {3*$dir}] [expr {-2*$dir}] set bbox [.c bbox fcar] set dt 100 if {[lindex $bbox 0]<10 || [lindex $bbox 2]>470} { set ::g(funicular,dir) [expr {$dir*-1}] set dt 6000 if {[lindex $bbox 2]>470} { foreach i {0 2000 4100 6200 8500 10100 12345 14567 16789} { after $i skier } } elseif {$dir==1 && $::g(bright)<180} {set dt 20000} } after $dt funicular' } proc flag {x y h} { set y1 [expr $y-$h] .c create line $x $y $x $y1 .c create rect $x $y1 [expr $x+12] [expr $y1+12] -fill red .c create text [expr $x+6] [expr $y1+6] -text + \ -font {Helvetica 12 bold} -fill white } proc random:select L {lindex $L [expr {int(rand()*[llength $L])}]} proc somecolor {} { random:select {red yellow blue green purple pink orange grey black} } proc skier {} { set id s:[expr {int(rand()*10000)}] set ski [somecolor] if {rand()<0.6} { .c create line 0 -10 10 0 11 0 -fill $ski -width 2 -tag $id .c create line 4 -14 14 -4 15 -4 -fill $ski -width 2 -tag $id .c create line 2 -15 -5 -15 -tag $id .c create line 12 -19 0 -19 -tag $id set ::g($id,dx) 1 } else { poly 1 -3 12 -13 15 -10 2 0 -fill $ski -outline [somecolor] -tag $id set ::g($id,dx) -1 } .c create line 5 -5 6 -16 7 -16 9 -9 -fill [somecolor] -width 2 -tag $id set shoes [random:select {black blue purple red}] .c create line 5 -5 6 -3 -fill $shoes -width 2 -tag $id .c create line 9 -9 10 -7 -fill $shoes -width 2 -tag $id .c create line 2 -15 6 -21 6 -16 8 -16 8 -21 12 -19\ -fill [somecolor] -width 2 -tag $id .c create oval 6 -24 8 -21 -fill orange -tag $id .c move $id 478 107 .c raise $id mountain set ::g($id,n) 0 set ::g($id,accident) 0 skier' $id } proc skier' {id} { upvar #0 ::g($id,accident) acc upvar #0 ::g($id,dx) dx upvar #0 ::g($id,n) n set dt 40; set dy 1 if {[lindex [.c bbox $id] 1]>400} {.c delete $id; return} if {rand()<0.001} {incr acc} if $acc { set dt 200 flip $id -1 -1 ;# accident: turn upside-down incr acc; set dy 6 if {$acc>8} {set dt 5000; set acc 0} } else { incr n if {$n>10 && rand()<0.05} {flip $id; set n 0} } .c move $id $dx $dy after $dt skier' $id } proc flip {tag {xflip -1.05} {yflip 1.05}} { foreach {x0 y0 x1 y1} [.c bbox $tag] break if ![info exists x0] return set xm [expr {($x0+$x1)/2.}] set ym [expr {($y0+$y1)/2.}] .c scale $tag $xm $ym $xflip $yflip set ::g($tag,dx) [expr {$::g($tag,dx)*-1}] } #--------------------------------------------------------- if ![winfo exists .c] { canvas .c -width 640 -height 400 -background lightblue pack .c bind .c <1> [list source [info script]] } .c delete all foreach i [after info] {after cancel $i} stars 50 sun 0 100 40 poly 0 400 0 100 40 120 100 150 160 130 200 150 250 110 300 130 350 80\ 700 500 -fill grey95 poly 0 400 0 370 170 380 330 200 360 120 420 70 540 90 570 60 700 200\ 700 400 -fill white -tag mountain funicular 20 360 470 60 flag 160 380 40 skier