Version 18 of Sailplane Flying Game

Updated 2003-06-10 20:54:59

Sailplane Flying Game

http://www.psnw.com/~alcald/screensh.jpg


This is a project I started while trying to teach myself Tcl/Tk. It is a moving map using an aviation sectional chart. You can fly sailplanes over the map after selecting a set of goals, usually a triangular course. You can launch multiple sailplanes. Give each one a unique "contest ID". You must "stop flying" in order to launch a new sailplane. You can control the sailplane who's ID is in the box with the arrow keys. Left and Right arrow steer left and right. Up arrow speeds up the sailplane. Down arrow slows it down. Your sailplane starts with 5000 ft. of altitude. There is a polar performance curve similar to a real sailplane, so if you try to fly faster to get ahead, you will lose altitude faster and risk "landing out" or running out of altitude. You can regain lost altitude by slowing down and lingering in randomly generated thermals of varying strength that appear on the map as brown smoke stack like images. Flying faster does not make you win. The pilot that makes the best judgement of how fast or slow to fly, given the lift conditions, will win. In general, if the lift conditions are strong and lots of thermals can be reached, it will pay to fly fast. If the lift conditions are weak, it will take much longer to regain lost altitude, so it will pay you to fly slower between thermals and conserve your altitude. If you run out of altitude, you "land out" and the game is over for you. There is one consolation not available in a real sailplane race, if you can maneuver your glider behind an opponent, and line up your course in his or her direction, pressing the space bar will launch a cruise missle in his or her direction. If it hits within the bounding box of the opponents glider, he or she will disintegrate and be removed from competition.

Alex Caldwell M.D.


Problems

  • The steering is wierd. A real sailplane circles in thermals. These can only slow down and make kind of "S" turns. The steering input is not linear, as you add input, the glider starts flying off course in a sort of exponentially faster rate, so you have to keep the inputs small.
  • The distance calculations for this particular map are all hard coded in the program. Need to develop ability to import any map and calibrate flexibly, so the distances can be calculated.
  • The code violates a lot of good Tcl coding practices, which I did not know when I started out, so it may be sort of

obfuscated.


Goals

  • I have a preliminary network game version that connects to a server, so two clients can play each other from remote network computers, but it has a few problems.
  • Use Tcl's new serial connection abilities to connect directly to a GPS receiver and plot courses in real time. Possibly on a PDA. The program is able now to read a Garmin .trk file and plot the positions on the map.
  • A 3-D version using Tkogl, the Tcl extension to OpenGL.

RS: Thanks for showing this to us! Next question would be, whether it can be downloaded at some place?


Here's the code. You also need these two files saved in the same directory for the images:

 # program for Tcl/Tk (free standing version - not for plug-in)
 # By Alex Caldwell M.D.
 # [email protected]
 # Jan 5, 1997
 # Feb 11, 1999
 # Feb 16, 1999
 # Feb 21, 1999

 global i              ;# variable that stores background image data for sectional map
 global g              ;# variable that stores background image data for little gliders
 global bmp            ;# variable that stores bitmap image

 global IC             ;# used in great circle distance calculation
 global COURSE         ;# compass course calculated from the course leg selected 
 global HEADING        ;# an array that holds the currently selected contestant's heading
 global TURNPOINT1     ;# variable that stores the name of turnpoint1
 global TURNPOINT2     ;# variable that stores the name of turnpoint2
 global turnpoints     ;# list that stores the list of turnpoint names
 global latdegrees     ;# list that stores a list of the turnpoint latitude degrees with the minutes truncated.
 global latmin
 global londegrees
 global lonmin
 global latdeg1
 global latmin1
 global londeg1
 global lonmin1
 global latdeg2
 global latmin2
 global londeg2
 global lonmin2
 global XAXIS          ;# variable that stores the difference between the x coordinates of the two turnpoints.
 global YAXIS          ;# variable that stores the difference between the y coordinates of the two turnpoints.
 global X1             ;# the x coordinate of the first turnpoint.
 global X2             ;# the x coordinate of the second turnpoint.
 global Y1             ;# the y coordinate of the first turnpoint.
 global Y2             ;# the y coordinate of teh second turnpoint.
 global SPEED          ;# an array that stores the value of each contestant's current speed
 global ALTITUDE       ;# an array that stores the value of each contestant's current altitude
 global text           ;# an array that stores the value of each contestant's contest no.
 global ID             ;# an array that stores the id of each contestant's small altitude text display 
 global shadow         ;# an array that stores the id of each contestant's shadow so it can be moved closer as altitude decreases
 global fileposition  
 global filecounter
 global filelinenumber
 global fileid
 global glider         ;# an array that stores the canvas id no.'s of the glider images.
 global contestno       ;# a variable that stores the current contest no.
 global yfraction       ;# I can't remember what this was supposed to do but I was afraid to delete it
 global xfraction       ;# I can't remember what this was supposed to do but I was afraid to delete it
 global combatants      ;# a list of the players by their contest no.
 global thermals        ;# a list of the thermals by no.
 global thermalstrength ;# an array that stores the strength of each thermal
 global daystrength     ;# a variable that sets the ramndom range for the average thermal strength
 global autoscroll      ;# stores value of variable that controls whether the map scrolls along with the glider 
 global tracking        ;# variable that controls whether tracking is on or off
 global distanceflown   ;# array storing the value of distance flown for each glider

 set contestno IB
 set yfraction 0
 set xfraction 0
 set TURNPOINT1 "Avenal"
 set TURNPOINT2 "Delano"
 set SPEED(IB) 60
 set ALTITUDE(IB) 5000
 set HEADING(IB) 0
 set fileposition 332
 set filecounter 0
 set filelinenumber 0
 set daystrength 6
 set autoscroll on
 set tracking on


 ###################################################################


 set turnpoints {Avenal Corcoran Delano Porterville "New Cuyama"}
 set latdegrees  {36 36 35 36 34}
 set latmin {0 6.15 44.74 1.78 57}
 set londegrees {120 119 119 119 119}
 set lonmin {8 35.69 14.19 3.76 42}

 ####################################################################

 proc RandomInit { seed } {
     global randomSeed
     set randomSeed $seed
 }

 proc Random {} {
     global randomSeed
     set randomSeed [expr ($randomSeed*9301 + 49297) % 233280]
     return [expr $randomSeed/double(233280)]
 }


 proc RandomRange { range } {
     expr int([Random]*$range)
 }



 RandomInit [pid]


 #****************************************************************************************
 proc getturnpoint {} {

 global TURNPOINT1
 global TURNPOINT2
 global X1 X2 Y1 Y2
 global contestno
 global SPEED
 global HEADING
 global daystrength

 frame .turnpointframe
 frame .turnpointframe.turnpointframe1
 frame .turnpointframe.turnpointframe2
 label .turnpointframe.turnpointframe1.label1 -text {Select Turnpoint 1} -relief groove
 label .turnpointframe.turnpointframe2.label2 -text {Select Turnpoint2 } -relief groove 
 menubutton .turnpointframe.turnpointframe1.menu1 -text $TURNPOINT1 \
 -menu .turnpointframe.turnpointframe1.menu1.sub1 -relief raised
 set men1 [menu .turnpointframe.turnpointframe1.menu1.sub1]
 $men1 add radio -label Avenal -variable TURNPOINT1 -value Avenal \
 -command ".turnpointframe.turnpointframe1.menu1 configure -text Avenal"
 $men1 add radio -label Corcoran -variable TURNPOINT1 -value Corcoran \
 -command ".turnpointframe.turnpointframe1.menu1 configure -text Corcoran"
 $men1 add radio -label Delano -variable TURNPOINT1 -value Delano \
 -command ".turnpointframe.turnpointframe1.menu1 configure -text Delano"
 $men1 add radio -label Porterville -variable TURNPOINT1 -value Porterville \
 -command ".turnpointframe.turnpointframe1.menu1 configure -text Porterville" 
 $men1 add radio -label {New Cuyama} -variable TURNPOINT1 -value {New Cuyama} \
 -command ".turnpointframe.turnpointframe1.menu1 configure -text {New Cuyama}"
  menubutton .turnpointframe.turnpointframe2.menu2 -text $TURNPOINT2 \
 -menu .turnpointframe.turnpointframe2.menu2.sub1 -relief raised
 set men2 [menu .turnpointframe.turnpointframe2.menu2.sub1]
 $men2 add radio -label Avenal -variable TURNPOINT2 -value Avenal \
 -command ".turnpointframe.turnpointframe2.menu2 configure -text Avenal"
 $men2 add radio -label Corcoran -variable TURNPOINT2 -value Corcoran \
 -command ".turnpointframe.turnpointframe2.menu2 configure -text Corcoran"
 $men2 add radio -label Delano -variable TURNPOINT2 -value Delano \
 -command ".turnpointframe.turnpointframe2.menu2 configure -text Delano"
 $men2 add radio -label Porterville -variable TURNPOINT2 -value Porterville \
 -command ".turnpointframe.turnpointframe2.menu2  configure -text Porterville"
 $men2 add radio -label {New Cuyama} -variable TURNPOINT2 -value {New Cuyama} \
 -command ".turnpointframe.turnpointframe2.menu2 configure -text {New Cuyama}"

 label .turnpointframe.turnpointframe1.contestnolabel -text {Enter Contest No.}
 label .turnpointframe.turnpointframe1.daystrength -text {Thermal Strength}
 entry .turnpointframe.turnpointframe2.contestnoentry -textvariable contestno -width 5 
 menubutton .turnpointframe.turnpointframe2.daystrength -text weak \
 -menu .turnpointframe.turnpointframe2.daystrength.m -relief raised
 menu .turnpointframe.turnpointframe2.daystrength.m
 .turnpointframe.turnpointframe2.daystrength.m add radio -label weak -variable daystrength -value 6
 .turnpointframe.turnpointframe2.daystrength.m add radio -label medium  -variable daystrength -value 11
 .turnpointframe.turnpointframe2.daystrength.m add radio -label strong -variable daystrength -value 18 

 button .turnpointframe.updatebutton  -text "Start New Leg" -command {destroybuttons
 getcoord
 calcdist $latdeg1 $latmin1 $londeg1 $lonmin1 $latdeg2 $latmin2 $londeg2 $lonmin2
 calcheading $latdeg1 $latmin1 $londeg1 $lonmin1 $latdeg2 $latmin2 $londeg2 $lonmin2
 plotline $latdeg1 $latmin1 $londeg1 $lonmin1 $latdeg2 $latmin2 $londeg2 $lonmin2
 showdist}    

 button .turnpointframe.launchglider -text "Launch Glider" -command {launchGlider;destroybuttons;showdist}
 button .turnpointframe.flybutton -text {Start Flying} -command {displayInfo}  

 scale .turnpointframe.speedscale -from 40 -to 200 -length 250 -variable SPEED($contestno) -orient horizontal \
 -label "Speed $contestno - kts" -tickinterval 50 -showvalue true
 bind . <KeyPress-Down> {set SPEED($contestno) [expr $SPEED($contestno) - 1]}
 bind . <KeyPress-Up> {set SPEED($contestno) [expr $SPEED($contestno) + 1]}
 scale .turnpointframe.headingscale -from -75  -to 75  -length 250  -variable HEADING($contestno) -orient horizontal \
 -label "Steer  $contestno - L/R" -tickinterval 15 -showvalue true
 bind . <KeyPress-Left> {set HEADING($contestno) [expr $HEADING($contestno) -1]}
 bind . <KeyPress-Right> {set HEADING($contestno) [expr $HEADING($contestno) +1]}
 button .turnpointframe.gpsbutton1 -text {last GPS fix} -command {gpsdisplay1}
 button .turnpointframe.gpsbutton2 -text {plot all GPS fixes} -command {gpsdisplay2}
 pack .frame .turnpointframe -side left
 pack .turnpointframe.turnpointframe1 .turnpointframe.turnpointframe2 -side left                                 
 pack .turnpointframe.turnpointframe1.label1
 pack .turnpointframe.turnpointframe1.menu1 -padx 5 -pady 5

 pack .turnpointframe.turnpointframe2.label2
 pack .turnpointframe.turnpointframe2.menu2 -padx 5 -pady 5
 pack .turnpointframe.turnpointframe1.contestnolabel
 pack .turnpointframe.turnpointframe1.daystrength
 pack .turnpointframe.turnpointframe2.contestnoentry
 pack .turnpointframe.turnpointframe2.daystrength      

pack .turnpointframe.updatebutton .turnpointframe.launchglider \ .turnpointframe.flybutton .turnpointframe.gpsbutton1 \ .turnpointframe.gpsbutton2 \ .turnpointframe.speedscale .turnpointframe.headingscale

}

#*********************************************************************************************