Bugzilla – Bug 183259
autopilot and flight director for moon-lander-1.0-1023
Last modified: 2006-09-04 06:42:22 UTC
First submitted in 2002, I added a flight director and simplified autopilot to moon-lander-1.0-1023, one of the BSD-derived Amusements/Games/Action/Arcade X11 applications. Please find the following files inlined moon-lander.spec - new rpm script moon-lander-autopilot.dif - new code patch moon-lander-autopilot.tar.bz2.base64 - new images images/beacon1.png autopilot indicator images/beacon2.png images/crosshairs1.png flight director images/crosshairs2.png Note the new images are mimencoded (like mail attachments) b5f0594e685255f45735200704d61b76 /home/bob/tmp/moon-lander-autopilot.tar.bz2 ea91aca1106de618f1bf3d038ef506d5 /home/bob/tmp/moon-lander-autopilot.dif 30d3e65e12997f4b86b50499b4459fac /home/bob/tmp/moon-lander.spec ---- moon-lander.spec ---- # # spec file for package moon-lander (Version 1.0) # # Copyright (c) 2005 SUSE LINUX Products GmbH, Nuernberg, Germany. # This file and all modifications and additions to the pristine # package are under the same license as the package itself. # # Please submit bugfixes or comments via http://www.suse.de/feedback/ # # norootforbuild # neededforbuild SDL-devel-packages SDL_image SDL_image-devel SDL_mixer-packages gpp libgpp libjpeg libpng-devel-packages xf86 BuildRequires: aaa_base acl attr bash bind-utils bison bzip2 coreutils cpio cpp cracklib cvs cyrus-sasl db devs diffutils e2fsprogs file filesystem fillup findutils flex gawk gdbm-devel gettext-devel glibc glibc-devel glibc-locale gpm grep groff gzip info insserv klogd less libacl libattr libcom_err libgcc libnscd libselinux libstdc++ libxcrypt libzio m4 make man mktemp module-init-tools ncurses ncurses-devel net-tools netcfg openldap2-client openssl pam pam-modules patch permissions popt procinfo procps psmisc pwdutils rcs readline sed strace sysvinit tar tcpd texinfo timezone unzip util-linux vim zlib zlib-devel SDL SDL-devel SDL_image SDL_image-devel SDL_mixer SDL_mixer-devel aalib aalib-devel alsa alsa-devel arts arts-devel audiofile audiofile-devel autoconf automake binutils esound esound-devel expat fontconfig fontconfig-devel gcc gcc-c++ gdbm gettext glib2 glib2-devel gnome-filesystem libjpeg libjpeg-devel libmikmod libogg libogg-devel libpng libpng-devel libstdc++-devel libtool libvorbis libvorbis-devel perl resmgr rpm slang slang-devel xorg-x11 xorg-x11-devel xorg-x11-libs Name: moon-lander URL: http://magigames.org/moonlander.html License: BSD Group: Amusements/Games/Action/Arcade #Requires: xforms Autoreqprov: on Version: 1.0 Release: 1023af Summary: A 2D game of gravity Source0: %{name}-%{version}.tar.bz2 Source1: %{name}-autopilot.tar.bz2 Patch0: %{name}.dif Patch1: %{name}-destdir.patch Patch2: %{name}-overflow.patch Patch3: %{name}-autopilot.dif BuildRoot: %{_tmppath}/%{name}-%{version}-build %description Moon Lander is a 2D game of gravity. Land your ship on the landing pad. Don't go too fast or you will crash. Authors: -------- David J. Blood <geekd@yahoo.com> Mike Heckman <mike@heckman.net> Ryan Daniels <pacmanfever@hotmail.com> Brian "Mo" Degenhardt <bmd@mp3.com> Garrett Banuk <mongoose@wpi.edu> Robert Meier <robert.meier@computer.org> %debug_package %prep %setup -n %{name} %setup -a 1 -n %{name} %patch0 -p0 %patch1 -p1 %patch2 -p1 %patch3 -p1 %build export RPM_OPT_FLAGS make %install rm -rf $RPM_BUILD_ROOT export DESTDIR=$RPM_BUILD_ROOT make install pushd $RPM_BUILD_ROOT/usr/share/games/moon-lander for file in `ls -1d *`; do if test "$file" != moon-lander.bin && test -f $file; then rm $file fi done popd %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc README.txt /usr/share/games/moon-lander /usr/X11R6/bin/moon-lander %changelog -n moon-lander * Tue May 10 2005 - meissner@suse.de - fixed buffer overflow. * Mon Jan 12 2004 - adrian@suse.de - added %%defattr * Mon Jun 16 2003 - coolo@suse.de - use BuildRoot * Tue Apr 16 2002 - ro@suse.de - link using g++ (for SDL_mixer) * Fri Feb 01 2002 - ro@suse.de - changed neededforbuild <libpng> to <libpng-devel-packages> * Fri Oct 26 2001 - ro@suse.de - use neededforbuild aliases: SDL_devel-pakages, SDL_mixer-packages * Thu Aug 23 2001 - uli@suse.de - initial package ---- moon-lander.spec ---- ---- moon-lander=autopilot.dif ---- --- moon-lander/moon_lander.c 2006-06-09 06:11:51.000000000 -0400 +++ moon-lander/moon_lander.c 2006-06-09 06:09:19.000000000 -0400 @@ -14,6 +14,12 @@ * 08/17/2001 - cleaned up some of the messy code, fixed last of the memory leaks, * added ryan daniels' ship and thrusters * +* 03/17/2002 - Dr. Robert Meier improved the autopilot to use minimum fuel +* trajectory from current position and velocity. +* +* 05/06/2005 - Dr. Robert Meier improved the autopilot to act as a +* flight director. +* */ @@ -96,6 +102,7 @@ int small_font; int demo_mode; int autopilot; + int flightdirector; int state; int ActualTime, LastTime; int landing_pad; @@ -108,6 +115,10 @@ Sprite thrustb; Sprite thrust_left; Sprite thrust_right; + Sprite crosshairs; + Sprite crosshairsb; + Sprite beacon; + Sprite beaconb; Sprite miniship; Sprite logo; Sprite gameover_screen; @@ -195,7 +206,7 @@ } while (!done){ - if ( files[count] = readdir(dir) ){ + if ( (files[count] = readdir(dir)) ){ //printf("I see - %d %s\n", count, files[count]->d_name); count++; @@ -883,6 +894,7 @@ draw_score(game, 0); DT_DrawText("Arrow keys control the ship", game->screen, game->big_font, 100, 100 ); DT_DrawText("Q quit P pause ESC options", game->screen, game->big_font, 75, 125 ); + DT_DrawText("A autopilot F flight director", game->screen, game->big_font, 75, 150 ); DT_DrawText("Press ENTER to play", game->screen, game->big_font, 175, 170 ); DT_DrawText("Score for each round = landing pad score + remaining fuel.", game->screen, game->small_font, 150, 280 ); @@ -1256,6 +1268,42 @@ /************************************************/ +void gamefd( Game *game) +{ + /* ---------------------------------------------------------------- + Flight Directory - written by Dr. Robert Meier 06/05/2006 + + During powered descent from low-phi (nearly parallel to the + horizon) orbit, the lunar module analog computer presented the + pilot with two oscilloscope displays. + One presented the predicted rate of climb and crosstrack speed + at the time that downrange speed was zero. + The second predicted altitude and crosstrack error at the time + that downrange speed was zero. + The pilot's goal was to keep the blip on each oscilloscope + centered as the predictions were updated according to radar. + + As a similar presentation, use a point to indicate the lowest + altitude and further side motion if thrust is applied continously. + + ---------------------------------------------------------------- */ + const float G = game->gravity; + const float A = 0.10; + const float B = 0.07; + Sprite *ship = &game->ship; + float xi = ship->x + 0.5 * ship->w; + float yi = ship->y + ship->h; + float hi = ship->x_vel; + float vi = ship->y_vel; + float sgn = hi > 0 ? 1 : -1; + game->crosshairs.x = xi - 4 + sgn * hi * hi / (2 * B); + game->crosshairs.y = yi - 4 + vi * vi / (2 * (A-G)); + game->crosshairsb.x = game->crosshairs.x; + game->crosshairsb.y = game->crosshairs.y; +} + +/************************************************/ + void gameai( int *left, int *right, int *down, @@ -1275,7 +1323,203 @@ velocity. 4 => Freefall with minor course changes + Game AI -- improved by Dr. Robert Meier 03/17/2002 + + The lunar lander powered descent from low-phi orbit was a + nonlinear problem well beyond autopilots until the 1970s. + Landing with perfect attitude control on a flat surface is + easy. + + The minimum fuel course is called bang-bang control. + + No vertical thrust until continuous vertical thrust will zero + descent rate at the pad. + Accelerate horizontally the minimum necessary to reach the pad. + Coast horizontally until continuous deceleration is required. + Decelerate continuously to reach zero groundspeed over the pad. + + To avoid burning landing gear off with backblast, you should actually + shutdown and freefall when altitude and vertical speed are + low enough. + ------------------------------------------------------------- */ +#if 1 + // Find the nearest pad. + game->ai.pad = 0; + game->ai.distance = 9999; + float x = game->ship.x + game->ship.w/2; + for( count = 0; count < game->current_level.num_landings; count++ ) { + if( abs( x-game->current_level.landing_x[count] ) < game->ai.distance ) { + game->ai.distance = abs( x - game->current_level.landing_x[count] ); + game->ai.pad = count; + } + } + + // Find the target hovering point. (Allow .05 margin for error.) + int max_x = game->current_level.landing_x[game->ai.pad] + + game->current_level.landing_w[game->ai.pad]/2; + float max_v = game->current_level.landing_speed[game->ai.pad]-.05; + int max_y = game->current_level.landing_y[game->ai.pad]; + + // Let the user know which pad is in use + game->beacon.x = max_x; + game->beacon.y = max_y; + game->beaconb.x = max_x; + game->beaconb.y = max_y; + + // Determine the time to target. + // y(-i) - freefall altitude that would result in current descent rate + // (assumed freefall) + // y(-t) - altitude now + // v(-t) - descent rate now + // (actual freefall) + // y(0) - altitude at burn + // (continuous burn) + // y(f) - pad altitude + // + // Thanks to Galileo, we know + // g - gravity + // a - acceleration (thrust - gravity) + // y(-i) = y(0) - g i i / 2 + // y(-t) = y(-i) + g (i-t) (i-t) / 2 + // v(-t) = g (i-t) + // y(f) = y(0) + a f f / 2 + // a [y(f) - y(0)] = g [y(0) - y(-i)] + // a f = g i + // We can now rewrite + // y(-i) = y(-t) - v(-t) v(-t) / 2 g + // y(0) = [a y(f) + g y(-i)] / (a + g) + // i = sqrt(2 [y(0) - y(-i)] / g) + // f = sqrt(2 [y(f) - y(0)] / a) + // t = i - v(-t) / g + + float g = game->gravity; + float a = .10 - g; + float yt = game->ship.y + game->ship.h; + float vt = game->ship.y_vel; + float yf = max_y; + float yi = yt - vt * vt / (2 * g); + float y0 = (a * yf + g * yi) / (a + g); + float i = sqrt(2 * (y0 - yi) / g); + float f = sqrt(2 * (yf - y0) / a); + float t = i - vt / g; + + // Thrust upward if continuous thrust will be just enough. + // (Allow one frame margin for error.) + // (Dont thrust if we are climbing.) + // (Dont cancel pilot command.) + if( !*down && 0 < vt ) { + if( 2 > t ) { + *down = 1; + t = 0; + } + } + +// printf( "ai-y: pad: %3d ship: %3f %5.2f g: %4.2f d: %d\n", +// max_y, yt, vt, g, *down); + + // Bang-bang control has an eigenfunction and three states. + // + // The eigenfunction is the phase space (position vs speed) trajectory + // during continuous burn. + // w - acceleration + // x(-b) - position now + // u(-b) - groundspeed now + // C - position of zero groundspeed relative to speed direction + // T - time to coast and decelerate + // The eigenfunction, the position axis, and the time to target, + // divide the space into three pairs of regions. + // C = x(-b) sgn(u(-b)) + u(-b) u(-b) / 2 abs(w) + // T = abs(x(-b)) / abs(u(-b)) + abs(u(-b)) / 2 abs(w) + // + // x + // . accelerating : decelerating + // . : + // . <<<<: + // . <<< : + // . . .<< : + // . . . : + // .coast . : + // . . : + // . v . : + // . v : + // .v. : + // . . + . . --- v + // : . . + // : coast . + // : . . + // > : . . + // >> : . . + // >>> : . . . + // >>>>: . . . + // : . + // : . + // decelerating : accelerating . + // : . + // + // State I: decelerating + // C > 0 - condition + // w = -abs(w) sgn(u(-b)) + // State I transitions to state II if actual acceleration is greater than w. + // + // State II: coasting + // C < 0 & t+f > T - condition + // w = 0 + // State II transitions to state I as C increases. + // + // State III: accelerating + // C < 0 & t+f < T - condition + // w = abs(w) sgn(u(-b)) + // State III transition to state II if actual acceleration is greater than w. + // + + float xb = x - max_x; + float w = .065; + float ub = game->ship.x_vel; + float C = xb * (0 < ub ? 1 : 0 > ub ? -1 : 0) + ub * ub / (2 * fabs(w)); + float T = fabs(xb) / (fabs(ub) + .001) + fabs(ub) / (2 * fabs(w)); + + // Thrust if continuous thrust will be just enough. + // (Dont cancel pilot command.) + // (Dont thrust if close enough) + // (Shutdown if altitude is low enough) + if( !*left && !*right ) { + *left = 0; + *right = 0; + if( .1 < fabs(ub) || 1 < fabs(xb) ) { + if( 0 < C ) { /* State I: decelerating */ + if( 0 < ub ) { + *left = 1; /* confirmed */ + } + else{ + *right = 1; /* confirmed */ + } + } + else{ + if( t + f > T ) { /* State II: coasting */ + } + else{ /* State III: accelerating */ + if( 0 < ub ) { + *right = 1; + } + else{ + *left = 1; + } + } + } + } + else{ + float alt = game->current_level.landing_y[game->ai.pad] - yt; + if( 2 * g * alt + vt * vt < max_v * max_v ) { + *down = 0; /* shutdown */ + } + } + } + +// printf( "ai-x: pad: %3d ship: %3f %5.2f C: %5.2f t+f: %5.2f T: %5.2f l: %d r: %d\n", +// max_x, xb+max_x, ub, C, t+f, T, *left, *right); + +#else /* 1 */ *left = 0; *right = 0; @@ -1397,6 +1641,7 @@ //printf( "4: game->ship.x=%f state=%d target=%f x_vel=%f y_vel=%f vdiff=%f\n", game->ship.x, game->ai.state, game->ai.target, game->ship.x_vel, game->ship.y_vel, game->ai.vdiff ); } +#endif /* 1 */ return; } @@ -1423,6 +1668,7 @@ int pause = 0; int pressed = 0; int appressed = 0; + int fdpressed = 0; char display_string[100]; game->ai.state = 0; @@ -1474,7 +1720,7 @@ // toggle if( !appressed ) { game->autopilot = (game->autopilot)?0:1; - appressed++; + appressed = 1; if( game->autopilot == 1 ) { game->ai.state = 0; } @@ -1485,6 +1731,19 @@ appressed = 0; } } + + if (key_table[SDLK_f]){ + // toggle + if( !fdpressed ) { + game->flightdirector = (game->flightdirector)?0:1; + fdpressed = 1; + } + } + else{ + if( fdpressed ) { + fdpressed = 0; + } + } if (key_table[SDLK_q]){ exit(0); @@ -1522,10 +1781,19 @@ if( !pause ) { - if( game->demo_mode || game->autopilot ) { + if( game->demo_mode ) { game->gravity = 0.05; gameai( &left, &right, &down, game ); } + else{ + if( game->autopilot ) { + gameai( &left, &right, &down, game ); + } + } + + if( game->flightdirector ) { + gamefd( game ); + } if( game->fuel > 0 ) { if( right == 1 ) { @@ -1632,6 +1900,28 @@ draw_sprite(game->screen, game->thrust_left); } + /* display flight director */ + + if (game->flightdirector) { + if ( (odd_even%2) == 0) { + draw_sprite(game->screen, game->crosshairs); + } + else{ + draw_sprite(game->screen, game->crosshairsb); + } + } + + /* display autopilot */ + + if (game->autopilot || game->demo_mode) { + if ( (odd_even%2) == 0) { + draw_sprite(game->screen, game->beacon); + } + else{ + draw_sprite(game->screen, game->beaconb); + } + } + /* display fuel */ draw_score(game, 1); @@ -1801,6 +2091,18 @@ sprintf(filename, "%simages/thrust2.png", DATAPATH); new_sprite(&(game.thrustb), filename, 0, 0, 1, 0); + sprintf(filename, "%simages/crosshairs1.bmp", DATAPATH); + new_sprite(&(game.crosshairs), filename, 0, 0, 1, 0); + + sprintf(filename, "%simages/crosshairs2.bmp", DATAPATH); + new_sprite(&(game.crosshairsb), filename, 0, 0, 1, 0); + + sprintf(filename, "%simages/beacon1.bmp", DATAPATH); + new_sprite(&(game.beacon), filename, 0, 0, 1, 0); + + sprintf(filename, "%simages/beacon2.bmp", DATAPATH); + new_sprite(&(game.beaconb), filename, 0, 0, 1, 0); + sprintf(filename, "%simages/thrust_left.bmp", DATAPATH); new_sprite(&(game.thrust_left), filename, 0, 0, 1, 0); ---- moon-lander=autopilot.dif ---- ---- moon-lander=autopilot.tar.bz2.base64 ---- QlpoOTFBWSZTWUo27HgAAZv/jv+o9uBEQf+AEBMAEHrj3gAAAQABJgAADLABeAAwAAAAGgAA AAAwAAAAGgAAAAAKoiaJpMk8kAbU0YE00aHpPQh+VNpR1MzVIljSI7TebjLgTffTCYiFdba1 oo3KRCqikN0zmoR1koQ0tCiBplMSiIipEohGwkt09Kp1EbOyi4qRcOgkI55abKBYrCkRHNHM mKIKyhgeJQ1pOzGZ9pefTiCLz7O5QbZJtibDHheYxzpUL9XqaX3Y46NJgcWKMS4WmxJUuLWP XqTSZnc6GiKnGYceEzU/pLvJbEm94nB5nmeDwMDgq7nvPIuKM8ss7MjQakmTrbS8q5DBYoSz NbFQoZGZyIHa+pTv/ir8UpdWjK1y0x+bqRFoiE8N7OZzrWyM7r2c/8XckU4UJBKNux4A ---- moon-lander=autopilot.tar.bz2.base64 ----
Thanks! I would suggest to build a package for these applications using our build service on opensuse.org.
I'll reassign it to the maintainer.
(In reply to comment #0) > First submitted in 2002, I added a flight director and simplified autopilot to > moon-lander-1.0-1023, one of the BSD-derived Amusements/Games/Action/Arcade X11 > applications. > > Please find the following files inlined > moon-lander.spec - new rpm script > moon-lander-autopilot.dif - new code patch > moon-lander-autopilot.tar.bz2.base64 - new images > images/beacon1.png autopilot indicator > images/beacon2.png > images/crosshairs1.png flight director > images/crosshairs2.png > Note the new images are mimencoded (like mail attachments) > > b5f0594e685255f45735200704d61b76 /home/bob/tmp/moon-lander-autopilot.tar.bz2 > ea91aca1106de618f1bf3d038ef506d5 /home/bob/tmp/moon-lander-autopilot.dif > 30d3e65e12997f4b86b50499b4459fac /home/bob/tmp/moon-lander.spec > > ---- moon-lander.spec ---- > # > # spec file for package moon-lander (Version 1.0) > # > # Copyright (c) 2005 SUSE LINUX Products GmbH, Nuernberg, Germany. > # This file and all modifications and additions to the pristine > # package are under the same license as the package itself. > # > # Please submit bugfixes or comments via http://www.suse.de/feedback/ > # > > # norootforbuild > # neededforbuild SDL-devel-packages SDL_image SDL_image-devel > SDL_mixer-packages gpp libgpp libjpeg libpng-devel-packages xf86 > > BuildRequires: aaa_base acl attr bash bind-utils bison bzip2 coreutils cpio cpp > cracklib cvs cyrus-sasl db devs diffutils e2fsprogs file filesystem fillup > findutils flex gawk gdbm-devel gettext-devel glibc glibc-devel glibc-locale gpm > grep groff gzip info insserv klogd less libacl libattr libcom_err libgcc > libnscd libselinux libstdc++ libxcrypt libzio m4 make man mktemp > module-init-tools ncurses ncurses-devel net-tools netcfg openldap2-client > openssl pam pam-modules patch permissions popt procinfo procps psmisc pwdutils > rcs readline sed strace sysvinit tar tcpd texinfo timezone unzip util-linux vim > zlib zlib-devel SDL SDL-devel SDL_image SDL_image-devel SDL_mixer > SDL_mixer-devel aalib aalib-devel alsa alsa-devel arts arts-devel audiofile > audiofile-devel autoconf automake binutils esound esound-devel expat fontconfig > fontconfig-devel gcc gcc-c++ gdbm gettext glib2 glib2-devel gnome-filesystem > libjpeg libjpeg-devel libmikmod libogg libogg-devel libpng libpng-devel > libstdc++-devel libtool libvorbis libvorbis-devel perl resmgr rpm slang > slang-devel xorg-x11 xorg-x11-devel xorg-x11-libs > > Name: moon-lander > URL: http://magigames.org/moonlander.html > License: BSD > Group: Amusements/Games/Action/Arcade > #Requires: xforms > Autoreqprov: on > Version: 1.0 > Release: 1023af > Summary: A 2D game of gravity > Source0: %{name}-%{version}.tar.bz2 > Source1: %{name}-autopilot.tar.bz2 > Patch0: %{name}.dif > Patch1: %{name}-destdir.patch > Patch2: %{name}-overflow.patch > Patch3: %{name}-autopilot.dif > BuildRoot: %{_tmppath}/%{name}-%{version}-build > > %description > Moon Lander is a 2D game of gravity. Land your ship on the landing > pad. Don't go too fast or you will crash. > > > > Authors: > -------- > David J. Blood <geekd@yahoo.com> > Mike Heckman <mike@heckman.net> > Ryan Daniels <pacmanfever@hotmail.com> > Brian "Mo" Degenhardt <bmd@mp3.com> > Garrett Banuk <mongoose@wpi.edu> > Robert Meier <robert.meier@computer.org> > > %debug_package > %prep > %setup -n %{name} > %setup -a 1 -n %{name} > %patch0 -p0 > %patch1 -p1 > %patch2 -p1 > %patch3 -p1 > > > %build > export RPM_OPT_FLAGS > make > > %install > rm -rf $RPM_BUILD_ROOT > export DESTDIR=$RPM_BUILD_ROOT > make install > pushd $RPM_BUILD_ROOT/usr/share/games/moon-lander > for file in `ls -1d *`; do > if test "$file" != moon-lander.bin && test -f $file; then > rm $file > fi > done > popd > > %clean > rm -rf $RPM_BUILD_ROOT > > %files > %defattr(-,root,root) > %doc README.txt > /usr/share/games/moon-lander > /usr/X11R6/bin/moon-lander > > %changelog -n moon-lander > * Tue May 10 2005 - meissner@suse.de > - fixed buffer overflow. > * Mon Jan 12 2004 - adrian@suse.de > - added %%defattr > * Mon Jun 16 2003 - coolo@suse.de > - use BuildRoot > * Tue Apr 16 2002 - ro@suse.de > - link using g++ (for SDL_mixer) > * Fri Feb 01 2002 - ro@suse.de > - changed neededforbuild <libpng> to <libpng-devel-packages> > * Fri Oct 26 2001 - ro@suse.de > - use neededforbuild aliases: SDL_devel-pakages, SDL_mixer-packages > * Thu Aug 23 2001 - uli@suse.de > - initial package > ---- moon-lander.spec ---- > > ---- moon-lander=autopilot.dif ---- > --- moon-lander/moon_lander.c 2006-06-09 06:11:51.000000000 -0400 > +++ moon-lander/moon_lander.c 2006-06-09 06:09:19.000000000 -0400 > @@ -14,6 +14,12 @@ > * 08/17/2001 - cleaned up some of the messy code, fixed last of the memory > leaks, > * added ryan daniels' ship and thrusters > * > +* 03/17/2002 - Dr. Robert Meier improved the autopilot to use minimum fuel > +* trajectory from current position and velocity. > +* > +* 05/06/2005 - Dr. Robert Meier improved the autopilot to act as a > +* flight director. > +* > */ > > > @@ -96,6 +102,7 @@ > int small_font; > int demo_mode; > int autopilot; > + int flightdirector; > int state; > int ActualTime, LastTime; > int landing_pad; > @@ -108,6 +115,10 @@ > Sprite thrustb; > Sprite thrust_left; > Sprite thrust_right; > + Sprite crosshairs; > + Sprite crosshairsb; > + Sprite beacon; > + Sprite beaconb; > Sprite miniship; > Sprite logo; > Sprite gameover_screen; > @@ -195,7 +206,7 @@ > } > > while (!done){ > - if ( files[count] = readdir(dir) ){ > + if ( (files[count] = readdir(dir)) ){ > > //printf("I see - %d %s\n", count, files[count]->d_name); > count++; > @@ -883,6 +894,7 @@ > draw_score(game, 0); > DT_DrawText("Arrow keys control the ship", game->screen, game->big_font, > 100, 100 ); > DT_DrawText("Q quit P pause ESC options", game->screen, > game->big_font, 75, 125 ); > + DT_DrawText("A autopilot F flight director", game->screen, > game->big_font, 75, 150 ); > DT_DrawText("Press ENTER to play", game->screen, game->big_font, 175, 170 > ); > > DT_DrawText("Score for each round = landing pad score + remaining fuel.", > game->screen, game->small_font, 150, 280 ); > @@ -1256,6 +1268,42 @@ > > /************************************************/ > > +void gamefd( Game *game) > +{ > + /* ---------------------------------------------------------------- > + Flight Directory - written by Dr. Robert Meier 06/05/2006 > + > + During powered descent from low-phi (nearly parallel to the > + horizon) orbit, the lunar module analog computer presented the > + pilot with two oscilloscope displays. > + One presented the predicted rate of climb and crosstrack speed > + at the time that downrange speed was zero. > + The second predicted altitude and crosstrack error at the time > + that downrange speed was zero. > + The pilot's goal was to keep the blip on each oscilloscope > + centered as the predictions were updated according to radar. > + > + As a similar presentation, use a point to indicate the lowest > + altitude and further side motion if thrust is applied continously. > + > + ---------------------------------------------------------------- */ > + const float G = game->gravity; > + const float A = 0.10; > + const float B = 0.07; > + Sprite *ship = &game->ship; > + float xi = ship->x + 0.5 * ship->w; > + float yi = ship->y + ship->h; > + float hi = ship->x_vel; > + float vi = ship->y_vel; > + float sgn = hi > 0 ? 1 : -1; > + game->crosshairs.x = xi - 4 + sgn * hi * hi / (2 * B); > + game->crosshairs.y = yi - 4 + vi * vi / (2 * (A-G)); > + game->crosshairsb.x = game->crosshairs.x; > + game->crosshairsb.y = game->crosshairs.y; > +} > + > +/************************************************/ > + > void gameai( int *left, > int *right, > int *down, > @@ -1275,7 +1323,203 @@ > velocity. > 4 => Freefall with minor course changes > > + Game AI -- improved by Dr. Robert Meier 03/17/2002 > + > + The lunar lander powered descent from low-phi orbit was a > + nonlinear problem well beyond autopilots until the 1970s. > + Landing with perfect attitude control on a flat surface is > + easy. > + > + The minimum fuel course is called bang-bang control. > + > + No vertical thrust until continuous vertical thrust will zero > + descent rate at the pad. > + Accelerate horizontally the minimum necessary to reach the pad. > + Coast horizontally until continuous deceleration is required. > + Decelerate continuously to reach zero groundspeed over the pad. > + > + To avoid burning landing gear off with backblast, you should actually > + shutdown and freefall when altitude and vertical speed are > + low enough. > + > ------------------------------------------------------------- */ > +#if 1 > + // Find the nearest pad. > + game->ai.pad = 0; > + game->ai.distance = 9999; > + float x = game->ship.x + game->ship.w/2; > + for( count = 0; count < game->current_level.num_landings; count++ ) { > + if( abs( x-game->current_level.landing_x[count] ) < game->ai.distance ) { > + game->ai.distance = abs( x - game->current_level.landing_x[count] ); > + game->ai.pad = count; > + } > + } > + > + // Find the target hovering point. (Allow .05 margin for error.) > + int max_x = game->current_level.landing_x[game->ai.pad] > + + game->current_level.landing_w[game->ai.pad]/2; > + float max_v = game->current_level.landing_speed[game->ai.pad]-.05; > + int max_y = game->current_level.landing_y[game->ai.pad]; > + > + // Let the user know which pad is in use > + game->beacon.x = max_x; > + game->beacon.y = max_y; > + game->beaconb.x = max_x; > + game->beaconb.y = max_y; > + > + // Determine the time to target. > + // y(-i) - freefall altitude that would result in current descent rate > + // (assumed freefall) > + // y(-t) - altitude now > + // v(-t) - descent rate now > + // (actual freefall) > + // y(0) - altitude at burn > + // (continuous burn) > + // y(f) - pad altitude > + // > + // Thanks to Galileo, we know > + // g - gravity > + // a - acceleration (thrust - gravity) > + // y(-i) = y(0) - g i i / 2 > + // y(-t) = y(-i) + g (i-t) (i-t) / 2 > + // v(-t) = g (i-t) > + // y(f) = y(0) + a f f / 2 > + // a [y(f) - y(0)] = g [y(0) - y(-i)] > + // a f = g i > + // We can now rewrite > + // y(-i) = y(-t) - v(-t) v(-t) / 2 g > + // y(0) = [a y(f) + g y(-i)] / (a + g) > + // i = sqrt(2 [y(0) - y(-i)] / g) > + // f = sqrt(2 [y(f) - y(0)] / a) > + // t = i - v(-t) / g > + > + float g = game->gravity; > + float a = .10 - g; > + float yt = game->ship.y + game->ship.h; > + float vt = game->ship.y_vel; > + float yf = max_y; > + float yi = yt - vt * vt / (2 * g); > + float y0 = (a * yf + g * yi) / (a + g); > + float i = sqrt(2 * (y0 - yi) / g); > + float f = sqrt(2 * (yf - y0) / a); > + float t = i - vt / g; > + > + // Thrust upward if continuous thrust will be just enough. > + // (Allow one frame margin for error.) > + // (Dont thrust if we are climbing.) > + // (Dont cancel pilot command.) > + if( !*down && 0 < vt ) { > + if( 2 > t ) { > + *down = 1; > + t = 0; > + } > + } > + > +// printf( "ai-y: pad: %3d ship: %3f %5.2f g: %4.2f d: %d\n", > +// max_y, yt, vt, g, *down); > + > + // Bang-bang control has an eigenfunction and three states. > + // > + // The eigenfunction is the phase space (position vs speed) trajectory > + // during continuous burn. > + // w - acceleration > + // x(-b) - position now > + // u(-b) - groundspeed now > + // C - position of zero groundspeed relative to speed direction > + // T - time to coast and decelerate > + // The eigenfunction, the position axis, and the time to target, > + // divide the space into three pairs of regions. > + // C = x(-b) sgn(u(-b)) + u(-b) u(-b) / 2 abs(w) > + // T = abs(x(-b)) / abs(u(-b)) + abs(u(-b)) / 2 abs(w) > + // > + // x > + // . accelerating : decelerating > + // . : > + // . <<<<: > + // . <<< : > + // . . .<< : > + // . . . : > + // .coast . : > + // . . : > + // . v . : > + // . v : > + // .v. : > + // . . + . . --- v > + // : . . > + // : coast . > + // : . . > + // > : . . > + // >> : . . > + // >>> : . . . > + // >>>>: . . . > + // : . > + // : . > + // decelerating : accelerating . > + // : . > + // > + // State I: decelerating > + // C > 0 - condition > + // w = -abs(w) sgn(u(-b)) > + // State I transitions to state II if actual acceleration is greater than w. > + // > + // State II: coasting > + // C < 0 & t+f > T - condition > + // w = 0 > + // State II transitions to state I as C increases. > + // > + // State III: accelerating > + // C < 0 & t+f < T - condition > + // w = abs(w) sgn(u(-b)) > + // State III transition to state II if actual acceleration is greater than > w. > + // > + > + float xb = x - max_x; > + float w = .065; > + float ub = game->ship.x_vel; > + float C = xb * (0 < ub ? 1 : 0 > ub ? -1 : 0) + ub * ub / (2 * fabs(w)); > + float T = fabs(xb) / (fabs(ub) + .001) + fabs(ub) / (2 * fabs(w)); > + > + // Thrust if continuous thrust will be just enough. > + // (Dont cancel pilot command.) > + // (Dont thrust if close enough) > + // (Shutdown if altitude is low enough) > + if( !*left && !*right ) { > + *left = 0; > + *right = 0; > + if( .1 < fabs(ub) || 1 < fabs(xb) ) { > + if( 0 < C ) { /* State I: decelerating */ > + if( 0 < ub ) { > + *left = 1; /* confirmed */ > + } > + else{ > + *right = 1; /* confirmed */ > + } > + } > + else{ > + if( t + f > T ) { /* State II: coasting */ > + } > + else{ /* State III: accelerating */ > + if( 0 < ub ) { > + *right = 1; > + } > + else{ > + *left = 1; > + } > + } > + } > + } > + else{ > + float alt = game->current_level.landing_y[game->ai.pad] - yt; > + if( 2 * g * alt + vt * vt < max_v * max_v ) { > + *down = 0; /* shutdown */ > + } > + } > + } > + > +// printf( "ai-x: pad: %3d ship: %3f %5.2f C: %5.2f t+f: %5.2f T: %5.2f l: %d > r: %d\n", > +// max_x, xb+max_x, ub, C, t+f, T, *left, *right); > + > +#else /* 1 */ > *left = 0; > *right = 0; > > @@ -1397,6 +1641,7 @@ > > //printf( "4: game->ship.x=%f state=%d target=%f x_vel=%f y_vel=%f > vdiff=%f\n", game->ship.x, game->ai.state, game->ai.target, game->ship.x_vel, > game->ship.y_vel, game->ai.vdiff ); > } > +#endif /* 1 */ > > return; > } > @@ -1423,6 +1668,7 @@ > int pause = 0; > int pressed = 0; > int appressed = 0; > + int fdpressed = 0; > char display_string[100]; > > game->ai.state = 0; > @@ -1474,7 +1720,7 @@ > // toggle > if( !appressed ) { > game->autopilot = (game->autopilot)?0:1; > - appressed++; > + appressed = 1; > if( game->autopilot == 1 ) { > game->ai.state = 0; > } > @@ -1485,6 +1731,19 @@ > appressed = 0; > } > } > + > + if (key_table[SDLK_f]){ > + // toggle > + if( !fdpressed ) { > + game->flightdirector = (game->flightdirector)?0:1; > + fdpressed = 1; > + } > + } > + else{ > + if( fdpressed ) { > + fdpressed = 0; > + } > + } > > if (key_table[SDLK_q]){ > exit(0); > @@ -1522,10 +1781,19 @@ > > if( !pause ) { > > - if( game->demo_mode || game->autopilot ) { > + if( game->demo_mode ) { > game->gravity = 0.05; > gameai( &left, &right, &down, game ); > } > + else{ > + if( game->autopilot ) { > + gameai( &left, &right, &down, game ); > + } > + } > + > + if( game->flightdirector ) { > + gamefd( game ); > + } > > if( game->fuel > 0 ) { > if( right == 1 ) { > @@ -1632,6 +1900,28 @@ > draw_sprite(game->screen, game->thrust_left); > } > > + /* display flight director */ > + > + if (game->flightdirector) { > + if ( (odd_even%2) == 0) { > + draw_sprite(game->screen, game->crosshairs); > + } > + else{ > + draw_sprite(game->screen, game->crosshairsb); > + } > + } > + > + /* display autopilot */ > + > + if (game->autopilot || game->demo_mode) { > + if ( (odd_even%2) == 0) { > + draw_sprite(game->screen, game->beacon); > + } > + else{ > + draw_sprite(game->screen, game->beaconb); > + } > + } > + > /* display fuel */ > > draw_score(game, 1); > @@ -1801,6 +2091,18 @@ > sprintf(filename, "%simages/thrust2.png", DATAPATH); > new_sprite(&(game.thrustb), filename, 0, 0, 1, 0); > > + sprintf(filename, "%simages/crosshairs1.bmp", DATAPATH); > + new_sprite(&(game.crosshairs), filename, 0, 0, 1, 0); > + > + sprintf(filename, "%simages/crosshairs2.bmp", DATAPATH); > + new_sprite(&(game.crosshairsb), filename, 0, 0, 1, 0); > + > + sprintf(filename, "%simages/beacon1.bmp", DATAPATH); > + new_sprite(&(game.beacon), filename, 0, 0, 1, 0); > + > + sprintf(filename, "%simages/beacon2.bmp", DATAPATH); > + new_sprite(&(game.beaconb), filename, 0, 0, 1, 0); > + > sprintf(filename, "%simages/thrust_left.bmp", DATAPATH); > new_sprite(&(game.thrust_left), filename, 0, 0, 1, 0); > > ---- moon-lander=autopilot.dif ---- > > ---- moon-lander=autopilot.tar.bz2.base64 ---- > QlpoOTFBWSZTWUo27HgAAZv/jv+o9uBEQf+AEBMAEHrj3gAAAQABJgAADLABeAAwAAAAGgAA > AAAwAAAAGgAAAAAKoiaJpMk8kAbU0YE00aHpPQh+VNpR1MzVIljSI7TebjLgTffTCYiFdba1 > oo3KRCqikN0zmoR1koQ0tCiBplMSiIipEohGwkt09Kp1EbOyi4qRcOgkI55abKBYrCkRHNHM > mKIKyhgeJQ1pOzGZ9pefTiCLz7O5QbZJtibDHheYxzpUL9XqaX3Y46NJgcWKMS4WmxJUuLWP > XqTSZnc6GiKnGYceEzU/pLvJbEm94nB5nmeDwMDgq7nvPIuKM8ss7MjQakmTrbS8q5DBYoSz > NbFQoZGZyIHa+pTv/ir8UpdWjK1y0x+bqRFoiE8N7OZzrWyM7r2c/8XckU4UJBKNux4A > ---- moon-lander=autopilot.tar.bz2.base64 ---- >
I tried to copy the patch (moon-lander-autopilot.dif) from the web, but it is malformed. Please could you send it as an email attachment? The other files are OK. Thank you!
Thank you for autopilot and flight director. They will be included in Factory.