[Keith Vetter] 2006-01-13 : Here's a simple but fun little game. Click on the red square and move it around trying to avoid colliding into the wall or the other blocks. Things start to speed up quickly and if you can last more than 20 seconds you've done very well. ---- [HZe] 2006-01-14: Great! This is really fun. And it perfectly is scaleable to a [PocketPC]. I've added a scale variable, which scales the whole user interface. Default is 1, which will leave everything as it was before. But setting to 0.42 it will fit on the screen of the [PocketPC]. I tested it with [eTcl]. Since size and speed is scaled, the timing on different scales should be compareable. [KPV] Changed the default scaling back to 1. Also added random initial direction for the blue blocks. [HZe] yes, sorry, my fault. I wanted to leave the default 1, but then copied the version one time too often from my test version. [HZe] now, the scale factor is calculated from the size of the display, but only if the display x or y does not allow 560 pixel. This should not only work for PDA-like PocketPCs (240x320), but also for [Windows CE] devices with kind of wide-screen display. [http://holgerzeinert.gmxhome.de/share/collidingblocks_pocketpc.gif] ---- [HZe] 2006-01-22: added an exit button. Using the x on the top right corner of the window will not stop the program on a Pocket PC, but just close the window. Also, if the application is running on a Pocket PC, it will only run once. If a second instance is started, it will trigger the first instance to come to the front and then exit. This is more like applications behave on Pocket PCs. ---- ##+########################################################################## # # Colliding Blocks -- simple arcade type game # by Keith Vetter, January 2006 # # http://www.anvari.org/fun/Games/One_Red_and_Four_Blue_Squares.html # package require Tk # calculate a scale factor for small displays, # e.g. for PocketPC 0.42 set maxsize [wm maxsize .] set maxsizex [lindex $maxsize 0] set maxsizey [lindex $maxsize 1] if {$maxsizex < $maxsizey} { set min $maxsizex } else { set min $maxsizey } if {$min < 560} { # small display set scale [expr $min / 560.0] } else { # normal displays set scale 1 } if {$tcl_platform(os) eq "Windows CE"} { # on a Pocket PC, an application usually only runs once. If started a second # time, the first instance is brought up again # Here, we simulate this set socketno 12345 ;# change this, if already used by other applications proc MoveWindowUp {args} { wm deiconify . } if { [catch {socket -server MoveWindowUp $socketno}] } { # socket is already in use, so connect to the running instance # to bring it in front and then exit this instance close [socket localhost $socketno] exit } } array set S [list title "Colliding Blocks" w [expr 560*$scale] \ h [expr 560*$scale] b [expr 60*$scale]] array set B [list me [list [expr 256*$scale] [expr 256*$scale] [expr 306*$scale] [expr 306*$scale]] \ 0 [list [expr 337*$scale] [expr 74*$scale] [expr 412*$scale] [expr 138*$scale]] \ 1 [list [expr 374*$scale] [expr 413*$scale] [expr 499*$scale] [expr 443*$scale]] \ 2 [list [expr 90*$scale] [expr 400*$scale] [expr 128*$scale] [expr 474*$scale]] \ 3 [list [expr 90*$scale] [expr 90*$scale] [expr 165*$scale] [expr 165*$scale]]] array set SPEED [list 0 [list [expr -10*$scale] [expr 12*$scale]] \ 1 [list [expr -12*$scale] [expr -20*$scale]] \ 2 [list [expr 15*$scale] [expr -13*$scale]] \ 3 [list [expr 17*$scale] [expr 11*$scale]] \ me {0 0}] array set C {border black field white me \#9c0204 them \#04029c} proc DoDisplay {} { global S B P C set S(lm) $S(b) set S(tm) $S(b) set S(rm) [expr {$S(w)-$S(b)}] set S(bm) [expr {$S(h)-$S(b)}] wm title . $S(title) canvas .c -width $S(w) -height $S(h) -highlightthickness 0 -bd 2 \ -bg $C(border) -bd 2 -relief ridge .c create text [expr {$S(w)/2}] [expr {$S(b)/2}] -anchor c \ -text $S(title) -font "Helvetica [expr int(18*$::scale)] bold" -fill yellow .c create text [expr {$S(w)/2}] [expr {$S(h)-10}] -anchor s -tag ttime \ -font "Helvetica [expr int(18*$::scale)] bold" -fill white button .about -text "?" -font {Times 10 bold} -command About .c create window [expr {$S(w)-10}] [expr {$S(h)-10}] -anchor se \ -tag a -window .about button .exit -text "X" -font {Times 10 bold} -command exit .c create window [expr {10}] [expr {$S(h)-10}] -anchor sw \ -tag a -window .exit pack .c -side top } proc DrawBlocks {} { global S B C P if {[.c find withtag id,0] != {}} { ;# Already exists--reposition foreach id {0 1 2 3 me} { .c coords id,$id $B($id) set P(speed,$id) [RandomDir $::SPEED($id)] } return } .c create rect $S(lm) $S(tm) $S(rm) $S(bm) -fill $C(field) \ -outline $C(field) foreach id {0 1 2 3 me} { set clr [expr {$id eq "me" ? $C(me) : $C(them)}] .c create rect $B($id) -fill $clr -outline $clr -tag id,$id set P(speed,$id) [RandomDir $::SPEED($id)] } .c bind id,me [list BDown] #.c bind id,me [list BMotion %x %y] } proc RandomDir {dxy} { foreach {dx dy} $dxy break set dx [expr {rand() < .5 ? $dx : -$dx}] set dy [expr {rand() < .5 ? $dy : -$dy}] return [list $dx $dy] } proc BDown {} { global P if {$P(state) eq "idle"} { set P(state) play set P(start) [clock clicks -milliseconds] MoveAllBlocks .c bind id,me [list BMotion %x %y] } foreach {x0 y0 x1 y1} [.c bbox id,me] break set x [expr {($x0+$x1)/2}] set y [expr {($y0+$y1)/2}] event generate . -warp 1 -x $x -y $y set P(mouse) [list $x $y] } proc BMotion {x y} { global S P if {$P(state) ne "play"} return foreach {x0 y0} $P(mouse) break set dx [expr {$x-$x0}] set dy [expr {$y-$y0}] set P(mouse) [list $x $y] .c move id,me $dx $dy foreach {x0 y0 x1 y1} [.c coords id,me] break if {[CheckCollisions]} Collide } proc Collide {} { set ::P(state) "over" .c bind id,me {} set txt "You lasted [format %.1f $::P(ttime)] seconds" tk_messageBox -message $txt -icon warning -title "$::S(title) Score" NewGame } proc CheckCollisions {} { global S foreach {x0 y0 x1 y1} [.c coords id,me] break if {$x0 <= $S(lm) || $x1 >= $S(rm) || $y0 <= $S(tm) || $y1 >= $S(bm)} { return 1 } foreach who {0 1 2 3} { foreach {X0 Y0 X1 Y1} [.c coords id,$who] break if {$x0 > $X1 || $x1 < $X0 || $y0 > $Y1 || $y1 < $Y0} continue return 1 } return 0 } proc NewGame {} { DrawBlocks set ::P(cnt) 0 set ::P(state) idle set ::P(ttime) 0 Timer } proc Timer {} { .c itemconfig ttime -text [format "%.1f seconds" $::P(ttime)] } proc About {} { set txt "$::S(title)\nby Keith Vetter, January 2006\n\n" append txt "Click and move the red block.\n" append txt "See how long you go without\n" append txt "hitting a blue block or the wall.\n\n" append txt "My best time is around 24 seconds." tk_messageBox -title "About $::S(title)" -message $txt } proc MoveAllBlocks {} { if {$::P(state) ne "play"} return set ::P(ttime) [expr {([clock clicks -milliseconds]-$::P(start))/1000.0}] Timer foreach id {0 1 2 3} { MoveBlock $id } incr ::P(cnt) set DELAYS {100 80 200 60 300 40 400 30 500 20 0x7FFFffff 10} foreach {total delay} $DELAYS { if {$::P(cnt) < $total} break } if {[CheckCollisions]} Collide after $delay MoveAllBlocks } proc MoveBlock {who} { foreach {dx dy} $::P(speed,$who) break foreach {x0 y0 x1 y1} [.c bbox id,$who] break # Check for bouncing off the wall if {$x0 + $dx < 0 || $x1 + $dx > $::S(w)} { set dx [expr {-$dx + int(rand()*1.2)}] } if {$y0 + $dy < 0 || $y1 + $dy > $::S(h)} { set dy [expr {-$dy + int(rand()*1.2)}] } .c move id,$who $dx $dy set ::P(speed,$who) [list $dx $dy] } DoDisplay NewGame return ---- [uniquename] 2013jul29 In case the image above at 'external site' gmxhome.de goes dead, here is a 'locally stored' image at wiki.tcl.tk. [vetter_collidingBlocks_wiki15262_screenshot_568x589.jpg] (Thanks to 'gnome-screenshot', 'mtpaint', and ImageMagick 'convert' on Linux for, respectively, capturing the screen to a PNG file, cropping the image, and converting the resulting PNG file to a JPEG file that is less than one-fifteenth the size of the PNG file. Thanks to FOSS developers everywhere --- including Linux kernel and Gnu developers. I used the 'mv' command and the ImageMagick 'identify' command in a shell script to easily rename the cropped image file to contain the image dimensions in pixels.) This is an image of the GUI at full size as it initially appears on startup ---- on a monitor set at 1024x768 resolution --- and with a window manager from Ubuntu 9.10 ('Karmic Koala, 2009 October version). ---- [Category Games] | [Tcl/Tk Games]