FF - 2008-01-17 - I'm just playing with speed and acceleration.... I also added a collision check at bounds. I wanted to add multiple objects and collision check between every object, but I figured it would have been a pain...
In the beginning I was working with vectors in polar coordinates, but I figured that also was a pain, so I switched to rect coords, but here and there there in the code could be some wastes of polar stuff :-)

set PI [expr atan(1)*4]
set x 50.0 ; set y 50.0
set vec_x 0.0 ; set vec_y 0.0
set timediv 50.0
array set input {
joy_sz 64
target null
dragging 0
dx 0.0
dy 0.0
}
set cnv [canvas .c -width 640 -height 400 -background white]
set joy [canvas .j -width $::input(joy_sz) -height $::input(joy_sz) -background gray]
grid $cnv -column 0 -row 0 -columnspan 2 -sticky news
grid columnconfigure . 0 -weight 10
grid rowconfigure . 0 -weight 10
grid [label .l1 -textvar ::lab1] -column 0 -row 1
grid [checkbutton .cb1 -text Spring -variable ::spring] -column 0 -row 2
grid [checkbutton .cb2 -text Control_accel -variable ::mode] -column 0 -row 3
grid $joy -column 1 -row 1 -rowspan 3 -sticky news
proc init_vect {cnv {bdot 1}} {
if $bdot {
$cnv create rectangle 0 0 10 10 -tags {dot} -fill blue
} else {
$cnv create line [expr $::input(joy_sz)*0.5] 0 [expr $::input(joy_sz)*0.5] $::input(joy_sz)
$cnv create line 0 [expr $::input(joy_sz)*0.5] $::input(joy_sz) [expr $::input(joy_sz)*0.5]
}
$cnv create line 0 0 10 10 -tags {vector vector_line} -fill red
$cnv create polygon 0 0 10 10 20 20 -tags {vector vector_arrow} -fill red
}
proc rec2pol {dx dy} {
if {$dx == 0} {set angle [expr $::PI*(($dy>0)?0.5:1.5)]} \
{set angle [expr fmod($::PI*(($dx>=0)?2:3)+atan(+1.0*$dy/$dx), $::PI*2)]}
set length [expr sqrt(pow($dx,2)+pow($dy,2))]
return [list $angle $length]
}
proc upd_vect_pol {cnv x y lx ly} {
$cnv coords dot [expr $x-5] [expr $y-5] [expr $x+5] [expr $y+5]
set ex [expr $x+$lx] ; set ey [expr $y+$ly]
$cnv coords vector_line $x $y $ex $ey
set angle [lindex [rec2pol $lx $ly] 0]
set Al [expr fmod($::PI*1.25+$angle, $::PI*2)]
set Ar [expr fmod($::PI*2.75+$angle, $::PI*2)]
if {$lx != 0 || $ly != 0} {
$cnv coords vector_arrow \
[expr $ex+cos($Al)*6] [expr $ey+sin($Al)*6] \
$ex $ey [expr $ex+cos($Ar)*6] [expr $ey+sin($Ar)*6]
} else {
$cnv coords vector_arrow \
[expr $x-3] $y $x [expr $y-3] [expr $x+3] $y $x [expr $y+3]
}
}
proc upd {__cnv st {ex_ 0} {ey_ 0}} {
if {$st == 0 && $::input(dragging)} {
set ::input(dx) [expr $ex_-$::input(joy_sz)*0.5]
set ::input(dy) [expr $ey_-$::input(joy_sz)*0.5]
upd_vect_pol $::joy [expr $::input(joy_sz)*0.5] [expr $::input(joy_sz)*0.5] $::input(dx) $::input(dy)
upd_vect_pol $::cnv $::x $::y $::vec_x $::vec_y
} elseif {$st > 0} {
set ::input(dragging) 1
} elseif {$st < 0} {
set ::input(dragging) 0
if $::spring {
set ::input(dx) 0 ; set ::input(dy) 0 ; upd_vect_pol $::joy [expr $::input(joy_sz)*0.5] [expr $::input(joy_sz)*0.5] $::input(dx) $::input(dy)
}
}
}
proc go {cnv} {
set amt 0.1
# handle speed vector / acceleration
if {$::mode == 0} {
set ::vec_x $::input(dx)
set ::vec_y $::input(dy)
} elseif {$::mode == 1} {
set ::vec_x [expr $::vec_x+$::input(dx)*$amt]
set ::vec_y [expr $::vec_y+$::input(dy)*$amt]
}
set ::x [expr $::x+$::vec_x*$amt]
set ::y [expr $::y+$::vec_y*$amt]
# handle collisions
set cnvw [expr ([winfo width $cnv]-[winfo reqwidth $cnv]+[$cnv cget -width])]
set cnvh [expr ([winfo height $cnv]-[winfo reqheight $cnv]+[$cnv cget -height])]
if {$::x < 0} {
set ::x [expr 0-$::x]
set ::vec_x [expr 0-$::vec_x]
} elseif {$::x > $cnvw} {
set ::x [expr $cnvw*2-$::x]
set ::vec_x [expr 0-$::vec_x]
}
if {$::y < 0} {
set ::y [expr 0-$::y]
set ::vec_y [expr 0-$::vec_y]
} elseif {$::y > $cnvh} {
set ::y [expr $cnvh*2-$::y]
set ::vec_y [expr 0-$::vec_y]
}
set ::lab1 "D(joy)=(${::input(dx)},${::input(dy)}) Vec=(${::vec_x},${::vec_y}) w=$cnvw h=$cnvh"
upd_vect_pol $cnv $::x $::y $::vec_x $::vec_y
after [expr int(1000/$::timediv)] [list go $cnv]
}
init_vect $cnv
init_vect $joy 0
upd $joy 1; upd $joy 0 [expr $::input(joy_sz)*0.5] [expr $::input(joy_sz)*0.5]; upd $joy -1
bind $cnv <ButtonPress-1> {set ::x %x ; set ::y %y}
bind $joy <ButtonPress-1> {upd %W 1}
bind $joy <ButtonRelease-1> {upd %W -1}
bind $joy <ButtonPress-3> {upd %W 1; upd %W 0 %x %y; upd %W -1}
bind $joy <Motion> {upd %W 0 %x %y}
go $cnv