PhysicsPlayground

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 :-)

http://dev.gentoo.org/~mescalinum/tclwiki-img/PhysicsPlayground.png


 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