|
Post by Carl Gundel on Aug 13, 2018 11:21:55 GMT -5
Add a mode to the lander.bas example that comes with Liberty BASIC which automatically controls the rotation and thrust of the lander to automatically land it safely.
|
|
|
Post by Carl Gundel on Aug 16, 2018 9:09:07 GMT -5
Add a mode to the lander.bas example that comes with Liberty BASIC which automatically controls the rotation and thrust of the lander to automatically land it safely. I realize that this is a hard one, and I think we can agree it is an excellent problem solving exercise. Here's an abstract of one solution 1) add a keystroke that turns on/off an autopilot more 2) figure out where a landing spot is 3) to be safe, figure out what the tallest hill is 4) increase altitude so we can fly over the tallest hill 5) fly left/right until directly over the pad 6) descend slowly to land safely I'm sure there are several interesting approaches to this problem. I will try my hand at one of them and I hope to see other attempts. ;-)
|
|
|
Post by David Drake on Feb 28, 2020 12:03:55 GMT -5
This doesn't exactly add autonavigation, but I added two modes: hover (press H) and auto-descend (press D). I enabled fuel consumption. I also display thrust, x and y speed, remaining fuel and auto-mode on the screen. Enjoy!
'Auto Hover mode added 'Auto Descend mode added
nomainwin
notice "Instructions 1/2"+chr$(13)+_ "-Use [ and ] to rotate lander"+chr$(13)+_ "-Use 0-9 to select thrust"+chr$(13)+_ "-H activates auto-hover mode"+_ chr$(13)+"-D activates auto-descent mode" notice "Instructions 2/2"+chr$(13)+_ "-Land on flat regions"+chr$(13)+_ "-Max safe landing speed (vertical"+chr$(13)+_ " and horizontal) is 200"+chr$(13)+_ "-Don't run out of fuel!"
UpperLeftX = 50 UpperLeftY = 50 WindowWidth = 500 WindowHeight = 340 dim terrain(500) open "Lunar Lander" for graphics_nsb as #lander print #lander, "when characterInput [userInput]" print #lander, "trapclose [quit]" print #lander, "font Courier 8"
WindowWidth = 640 call makeSprites call setBackground print #lander, "spritexy lem 50 50"
[startGame] 'initialize print #lander, "setfocus" speed=350 hoverMode=1 descendMode=1 fuel = 15000 altitude = 0 attitude = 0 longitude = 70 thrust = 0 call setHorizSpeed 8 call setVertSpeed 0 call gravityAccelerate timer speed, [timerTicked] startTime = time$("milliseconds") wait
[timerTicked] 'This is the main simulation routine! frames = frames + 1 fuel=fuel-thrust*100
'auto-hover mode if hoverMode=-1 then if getHorizSpeed()>=-.5 and getHorizSpeed()<=.5 then attitude = 90 if getHorizSpeed()<-.5 then attitude = 135 if getHorizSpeed()>.5 then attitude=45 if getVertSpeed()<0 then thrustInput=thrustInput-1:if thrustInput<1 then thrustInput=1 if getVertSpeed()>0 then thrustInput=thrustInput+1:if thrustInput>10 then thrustInput=10 thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 end if
if descendMode=-1 then attitude=90 if getHorizSpeed()>=-.5 and getHorizSpeed()<=.5 then attitude = 90 if getHorizSpeed()<-.5 then attitude = 90+22.5 if getHorizSpeed()>.5 then attitude=90-22.5 if getVertSpeed()<0 then thrustInput=thrustInput-1:if thrustInput<1 then thrustInput=1 if getVertSpeed()>1.5 then thrustInput=thrustInput+1:if thrustInput>7 then thrustInput=7 thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 end if
if altitude <= terrain(longitude+15) - 24 then if fuel<=0 then thrust=0 call setAttitude attitude call applyThrust thrust, attitude call gravityAccelerate altitude = altitude + getVertSpeed() longitude = max(0, min(485, longitude + getHorizSpeed())) print #lander, "spritexy lem "; longitude; " "; altitude print #lander, "drawsprites" else timer 0 if landerCrashed(longitude, attitude) then notice "You crashed!" else notice "Successful landing!" end if confirm "Try again?"; answer if answer then [startGame] else [quit] end if
'status updates vclr$="green" if getVertSpeed()>=2 then vclr$="red" hclr$="green" if getHorizSpeed()>=2 then hclr$="red" fclr$="green" if fuel<5000 then fclr$="yellow" if fuel<1000 then fclr$="red" if fuel<1 then fclr$="pink" #lander "backcolor black;color white;place 1 15;\Thrust: ";int(thrust*10) #lander "color ";vclr$;";place 1 30;\V: ";int(getVertSpeed()*100) #lander "color ";hclr$;";place 1 45;\H: ";int(getHorizSpeed()*100) if fuel<=0 then fl$="Empty" else fl$=str$(int(fuel)) #lander "color ";fclr$;";place 1 60;\F: ";fl$ if hoverMode=-1 then #lander "color white;place 1 75;\Hover mode active" if descendMode=-1 then #lander "color cyan;place 1 75;\Descent mode active"
wait
[quit] timer 0 close #lander end
[userInput]
char$ = Inkey$ if char$ ="h" then hoverMode=hoverMode*(-1):descendMode=1 if char$ ="d" then descendMode=descendMode*(-1):hoverMode=1 if char$ = "[" and hoverMode=1 then attitude = attitude - 22.5 if attitude < -0.01 then attitude = 337.5 wait end if if char$ = "]" and hoverMode=1 then attitude = attitude + 22.5 if attitude > 337.51 then attitude = 0 wait end if thrustInput = instr("0123456789", char$) if thrustInput then thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 wait
function landerCrashed(xPosition, attitude)
landerCrashed = int(attitude+0.1) <> 90 landerCrashed = landerCrashed or getVertSpeed() > 2 landerCrashed = landerCrashed or getHorizSpeed() > 2 landerCrashed = landerCrashed or terrain(xPosition) <> terrain(xPosition+30) landerCrashed = landerCrashed or terrain(xPosition) <> terrain(xPosition+15)
end function
sub makeSprites
open "lem" for graphics as #makeSprites print #makeSprites, "down" print #makeSprites, "place 0 31 ; backColor black ; boxfilled 640 73" for x = 0 to 15 y = 1 call drawLEM x, y, 270 + x * 22.5, 2, "black" y = 2 call drawLEM x, y, 270 + x * 22.5, 2, "darkgray" call drawLEM x, y, 270 + x * 22.5, 1, "lightgray" call getSprite x next x close #makeSprites print #lander, "addsprite lem lem0 lem1 lem2 lem3 lem4 lem5 lem6 lem7 lem8 lem9 lem10 lem11 lem12 lem13 lem14 lem15"
end sub
sub drawLEM xPosition, yPosition, uncorrectedAngle, penSize, color$ angle = uncorrectedAngle print #makeSprites, "north ; color "; color$; " ; up ; turn "; angle print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "size "; penSize print #makeSprites, "up ; go 4 ; down ; circle 8" print #makeSprites, "turn 75 ; go 4 ; turn 180 ; go 4" print #makeSprites, "turn 30 ; go 4 ; turn 180 ; go 4 ; turn 255" print #makeSprites, "up ; turn 160 ; go 8" print #makeSprites, "down ; go 4 ; turn 110" print #makeSprites, "go 8 ; turn 110 ; go 4" print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "north ; up ; turn "; angle print #makeSprites, "go 4 ; turn 125 ; go 8 ; down ; turn 45 ; go 8" print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "north ; up ; turn "; angle print #makeSprites, "go 4 ; turn 235 ; go 8 ; down ; turn -45 ; go 8"
end sub
sub setBackground 'loadbmp "stars", "bmp\stars.bmp" print #lander, "down ; fill black" call drawTerrain print #lander, "getbmp stars 0 0 490 315" print #lander, "background stars" end sub
sub getSprite spritNum spriteX = spritNum * 30 print #makeSprites, "getbmp lem"; spritNum; " "; spriteX; " 1 30 60" end sub
sub setHorizSpeed xSpeed vars(0) = xSpeed end sub
sub setVertSpeed ySpeed vars(1) = ySpeed end sub
function getHorizSpeed() getHorizSpeed = vars(0) end function
function getVertSpeed() getVertSpeed = vars(1) end function
sub setAttitude degrees print #lander, "spriteimage lem lem"; int(degrees / 22.5) end sub
sub gravityAccelerate call setVertSpeed getVertSpeed() + 0.3'(6/18) end sub
sub applyThrust qtyFuel, angle angleXform = angle / 180 * 3.141592 call setHorizSpeed getHorizSpeed() - (qtyFuel/2) * cos(angleXform) call setVertSpeed getVertSpeed() - (qtyFuel/2) * sin(angleXform) end sub
sub drawTerrain
rate1 = rnd(1) / (rnd(1) * 17 + 10) rate2 = rnd(1) / (rnd(1) * 10 + 10) print #lander, "down ; size 1 ; color white"
for x = 0 to 499 step 1 if rnd(1) < 0.015 then gosub [makeLandingZone] holder1 = holder1+rate1 holder2 = holder2+rate2 holder3 = holder3+sin(holder2)/20 y = 200+int(sin(holder1)*50)+int(cos(holder2)*50)+int(cos(holder3)*15) terrain(x) = y print #lander, "goto "; x; " "; y next x goto [endSub]
[makeLandingZone]
width = int((rnd(1)*4+2)/3) for lz = x to min(499, x + 34 * width) terrain(lz) = y print #lander, "goto "; lz; " "; y next lz x = lz return
[endSub]
end sub
|
|
|
Post by David Drake on Mar 6, 2020 14:11:42 GMT -5
Took another swing at it. This does have a mode to "seek" a landing spot and automatically descend and land. It kind of cheats... It doesn't look at terrain elevation, but if it's trying to land and drifts off course, thrusters kick in to raise the lander (hopefully) above the terrain. Anyway, it's fun. I set it up to automatically do several thousand simulations. I found that if you set the fuel variable at around 100,000, it will land successfully in "seek" mode more than 85% of the time.
To reiterate, there are four modes: fully manual (no modes enabled), hover (press "h"), auto-descend (press "d"), and fully automatic (seek mode - press "s").
I have no doubt that this could be done with prettier, tighter, better code. Enjoy!
'Lander.bas 'written by Carl Gundel 'carlg@world.std.com 'Needs at least Liberty BASIC v2.0 'This file is contributed to the public domain 'At this stage it is merely a prototype. 'Use the keys 0 through 9 to control thrust 'Use the [ and ] keys to rotate the ship!
'You must make a VERY gentle and level landing 'on one of the flat areas!
'[s] Auto Seek mode added (finds landing site) '[h] Auto Hover mode added (maintains altitude and longitude) '[d] Auto Descend mode added (controls descent speed)
'open game window nomainwin
notice "Instructions 1/2"+chr$(13)+_ "-Use [ and ] to rotate lander"+chr$(13)+_ "-Use 0-9 to select thrust"+chr$(13)+_ "-S activates auto-seek (fuel eater)"+chr$(13)+_ "-H activates auto-hover mode (fuel eater)"+chr$(13)+_ "-D activates auto-descent mode"+chr$(13)+_ "-Land on flat regions"+chr$(13)+_ "-Max safe landing speed (vertical and horizontal) is 200"+chr$(13)+_ "-Don't run out of fuel!"
UpperLeftX = 50 UpperLeftY = 50 WindowWidth = 500 WindowHeight = 340 dim terrain(500) open "Lunar Lander" for graphics_nsb as #lander print #lander, "when characterInput [userInput]" print #lander, "trapclose [quit]" print #lander, "font Courier 8"
WindowWidth = 640 call makeSprites print #lander, "spritexy lem 50 50"
[startGame] 'initialize call setBackground print #lander, "setfocus" speed=150 ' for game play, set to 150 hoverMode=1 descendMode=1 autoMode=1 fuel = 20000' for game play, set to 15000-25000 altitude = 0 attitude = 0 longitude = 70 thrust = 0 call setHorizSpeed 2 call setVertSpeed 0 call gravityAccelerate timer speed, [timerTicked] startTime = time$("milliseconds") wait
[timerTicked] 'This is the main simulation routine! fuel=fuel-thrust*100
'automatically seek a landing site, then try to land if autoMode=-1 then 'maintains horizontal speed while seek is active if longitude >470 then if getHorizSpeed()>.05 then attitude=90-22.5-22.5 end if if longitude <10 then if getHorizSpeed()<-.05 then attitude = 90+22.5+22.5 end if if longitude<470 and longitude>10 then attitude=90 if getHorizSpeed()>=0 and getHorizSpeed()<.75 then attitude = 90+22.5+22.5 if getHorizSpeed()>=0 and getHorizSpeed()>1.25 then attitude = 90-22.5-22.5 if getHorizSpeed()<0 and getHorizSpeed()>-.75 then attitude = 90+22.5+22.5 if getHorizSpeed()<0 and getHorizSpeed()<-1.25 then attitude = 90-22.5-22.5 end if
'maintains altitude while seek is active if descendMode=1 then if getVertSpeed()<0 then thrustInput=thrustInput-1:if thrustInput<1 then thrustInput=1 if getVertSpeed()>0 then thrustInput=thrustInput+1:if thrustInput>10 then thrustInput=10 if altitude<0 then thrustInput=1 thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 end if
'determines whether lander is over a possible landing site 'if so, activate auto-descent mode if landerOverSite(longitude)=0 then landingPadLongitude=longitude:descendMode=-1 end if
'if you are not over a landing site, turn off auto-descent mode if landerOverSite(longitude) then if descendMode=-1 then descendMode=1:recoverMode=-1 end if end if
'recover mode activated when auto-seek misses a landing site if recoverMode=-1 then thrustInput=9:attitude=90 if getVertSpeed()<-2 then thrustInput=thrustInput+1:if thrustInput>7 then thrustInput=7 if altitude<30 then thrustInput=1:recoverMode=1 thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 end if
'auto-hover mode if hoverMode=-1 then 'reduces horizontal speed to close to zero if getHorizSpeed()>=-.1 and getHorizSpeed()<=.1 then attitude = 90 if getHorizSpeed()<-.1 then attitude = 90+22.5+22.5 if getHorizSpeed()>.1 then attitude=90-22.5-22.5
'maintains current altitude if getVertSpeed()<0 then thrustInput=thrustInput-1:if thrustInput<1 then thrustInput=1 if getVertSpeed()>0 then thrustInput=thrustInput+1:if thrustInput>10 then thrustInput=10 thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 end if
'auto-descent mode if descendMode=-1 then
'reduce horizontal speed to around zero attitude=90 if getHorizSpeed()>=-.05 and getHorizSpeed()<=.05 then attitude = 90 if getHorizSpeed()<-.05 then attitude = 90+22.5 if getHorizSpeed()>.05 then attitude=90-22.5 if getHorizSpeed()>.75 then attitude=90-22.5-22.5
'keep vertical speed between 1.3 and 1.9 (crashes at 2.0) if getVertSpeed()<1.3 then thrustInput=thrustInput-1:if thrustInput<1 then thrustInput=1 if getVertSpeed()>1.9 then thrustInput=thrustInput+1:if thrustInput>7 then thrustInput=7 thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 end if
'if lander altitude is above the terrain, apply thrust (if fuel=0 then no thrust applied), animate the lander if altitude <= terrain(longitude+15) - 24 then if fuel<=0 then thrust=0 call setAttitude attitude call applyThrust thrust, attitude call gravityAccelerate altitude = altitude + getVertSpeed() longitude = max(0, min(485, longitude + getHorizSpeed())) print #lander, "spritexy lem "; longitude; " "; altitude print #lander, "drawsprites" else 'otherwise, check to see if lander has crashed or landed timer 0 if landerCrashed(longitude, attitude) then #lander "place ";longitude+15;" ";altitude+15;";down;backcolor yellow;circlefilled 20;place 0 0;" notice "You crashed!" else notice "Successful landing!" end if confirm "Try again?"; answer if answer then [startGame] else [quit] end if
'display status updates on the window vclr$="green" if getVertSpeed()>=2 then vclr$="red" hclr$="green" if getHorizSpeed()>=2 then hclr$="red" fclr$="green" if fuel<5000 then fclr$="yellow" if fuel<1000 then fclr$="red" if fuel<1 then fclr$="pink" #lander "backcolor black;color white;place 1 15;\T: ";int(thrust*10) #lander "color ";vclr$;";place 1 30;\V: ";int(getVertSpeed()*100) #lander "color ";hclr$;";place 1 45;\H: ";int(getHorizSpeed()*100) if fuel<=0 then fl$="Empty" else fl$=str$(int(fuel)) #lander "color ";fclr$;";place 1 60;\F: ";fl$ if hoverMode=-1 then #lander "color white;place 1 75;\Hover" if descendMode=-1 then #lander "color cyan;place 1 75;\Descent" if autoMode=-1 then #lander "color yellow;place 1 90;\Seek" wait
[quit] timer 0 close #lander end
[userInput] char$ = Inkey$ if char$ ="h" then hoverMode=hoverMode*(-1):descendMode=1:autoMode=1 if char$ ="d" then descendMode=descendMode*(-1):hoverMode=1:autoMode=1 if char$ ="a" then autoMode=autoMode*(-1):descendMode=1:hoverMode=1 if char$ = "[" and hoverMode=1 then attitude = attitude - 22.5 if attitude < -0.01 then attitude = 337.5 wait end if if char$ = "]" and hoverMode=1 then attitude = attitude + 22.5 if attitude > 337.51 then attitude = 0 wait end if thrustInput = instr("0123456789", char$) if thrustInput then thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 wait
function landerCrashed(xPosition, attitude) landerCrashed = int(attitude+0.1) <> 90 landerCrashed = landerCrashed or getVertSpeed() > 2 landerCrashed = landerCrashed or getHorizSpeed() > 2 landerCrashed = landerCrashed or terrain(xPosition) <> terrain(xPosition+30) landerCrashed = landerCrashed or terrain(xPosition) <> terrain(xPosition+15) end function
function landerOverSite(xPosition) 'returns a 0 if over a site landerOverSite = landerOverSite or terrain(xPosition) <> terrain(xPosition+30) landerOverSite = landerOverSite or terrain(xPosition) <> terrain(xPosition+15) end function
sub makeSprites open "lem" for graphics as #makeSprites print #makeSprites, "down" print #makeSprites, "place 0 31 ; backColor black ; boxfilled 640 73" for x = 0 to 15 y = 1 call drawLEM x, y, 270 + x * 22.5, 2, "black" y = 2 call drawLEM x, y, 270 + x * 22.5, 2, "darkgray" call drawLEM x, y, 270 + x * 22.5, 1, "lightgray" call getSprite x next x close #makeSprites print #lander, "addsprite lem lem0 lem1 lem2 lem3 lem4 lem5 lem6 lem7 lem8 lem9 lem10 lem11 lem12 lem13 lem14 lem15" end sub
sub drawLEM xPosition, yPosition, uncorrectedAngle, penSize, color$ angle = uncorrectedAngle print #makeSprites, "north ; color "; color$; " ; up ; turn "; angle print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "size "; penSize print #makeSprites, "up ; go 4 ; down ; circle 8" print #makeSprites, "turn 75 ; go 4 ; turn 180 ; go 4" print #makeSprites, "turn 30 ; go 4 ; turn 180 ; go 4 ; turn 255" print #makeSprites, "up ; turn 160 ; go 8" print #makeSprites, "down ; go 4 ; turn 110" print #makeSprites, "go 8 ; turn 110 ; go 4" print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "north ; up ; turn "; angle print #makeSprites, "go 4 ; turn 125 ; go 8 ; down ; turn 45 ; go 8" print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "north ; up ; turn "; angle print #makeSprites, "go 4 ; turn 235 ; go 8 ; down ; turn -45 ; go 8"
end sub
sub setBackground print #lander, "down ; fill black" call drawTerrain print #lander, "getbmp stars 0 0 490 315" print #lander, "background stars" end sub
sub getSprite spritNum spriteX = spritNum * 30 print #makeSprites, "getbmp lem"; spritNum; " "; spriteX; " 1 30 60" end sub
sub setHorizSpeed xSpeed vars(0) = xSpeed end sub
sub setVertSpeed ySpeed vars(1) = ySpeed end sub
function getHorizSpeed() getHorizSpeed = vars(0) end function
function getVertSpeed() getVertSpeed = vars(1) end function
sub setAttitude degrees print #lander, "spriteimage lem lem"; int(degrees / 22.5) end sub
sub gravityAccelerate call setVertSpeed getVertSpeed() + 0.3'(6/18) end sub
sub applyThrust qtyFuel, angle angleXform = angle / 180 * 3.141592 call setHorizSpeed getHorizSpeed() - (qtyFuel/2) * cos(angleXform) call setVertSpeed getVertSpeed() - (qtyFuel/2) * sin(angleXform) end sub
sub drawTerrain rate1 = rnd(1) / (rnd(1) * 17 + 10) rate2 = rnd(1) / (rnd(1) * 10 + 10) print #lander, "down ; size 1 ; color white"
for x = 0 to 499 step 1 if rnd(1) < 0.015 then gosub [makeLandingZone] holder1 = holder1+rate1 holder2 = holder2+rate2 holder3 = holder3+sin(holder2)/20 y = 200+int(sin(holder1)*50)+int(cos(holder2)*50)+int(cos(holder3)*15) terrain(x) = y print #lander, "goto "; x; " "; y next x goto [endSub]
[makeLandingZone] width = int((rnd(1)*4+2)/3) for lz = x to min(499, x + 34 * width) terrain(lz) = y print #lander, "goto "; lz; " "; y next lz x = lz return
[endSub] end sub
|
|
|
Post by tsh73 on Mar 6, 2020 14:40:14 GMT -5
I spent a few minutes trying to activate auto-landing with S button, as program says. I died that frequently only in Tomb Rider
|
|
|
Post by David Drake on Mar 7, 2020 4:06:25 GMT -5
Took another swing at it. This does have a mode to "seek" a landing spot and automatically descend and land. It kind of cheats... It doesn't look at terrain elevation, but if it's trying to land and drifts off course, thrusters kick in to raise the lander (hopefully) above the terrain. Anyway, it's fun. I set it up to automatically do several thousand simulations. I found that if you set the fuel variable at around 100,000, it will land successfully in "seek" mode more than 85% of the time. To reiterate, there are four modes: fully manual (no modes enabled), hover (press "h"), auto-descend (press "d"), and fully automatic (seek mode - press "s"). I have no doubt that this could be done with prettier, tighter, better code. Enjoy! 'Lander.bas 'written by Carl Gundel 'carlg@world.std.com 'Needs at least Liberty BASIC v2.0 'This file is contributed to the public domain 'At this stage it is merely a prototype. 'Use the keys 0 through 9 to control thrust 'Use the [ and ] keys to rotate the ship!
'You must make a VERY gentle and level landing 'on one of the flat areas!
'[s] Auto Seek mode added (finds landing site) '[h] Auto Hover mode added (maintains altitude and longitude) '[d] Auto Descend mode added (controls descent speed)
'open game window nomainwin
notice "Instructions 1/2"+chr$(13)+_ "-Use [ and ] to rotate lander"+chr$(13)+_ "-Use 0-9 to select thrust"+chr$(13)+_ "-S activates auto-seek (fuel eater)"+chr$(13)+_ "-H activates auto-hover mode (fuel eater)"+chr$(13)+_ "-D activates auto-descent mode"+chr$(13)+_ "-Land on flat regions"+chr$(13)+_ "-Max safe landing speed (vertical and horizontal) is 200"+chr$(13)+_ "-Don't run out of fuel!"
UpperLeftX = 50 UpperLeftY = 50 WindowWidth = 500 WindowHeight = 340 dim terrain(500) open "Lunar Lander" for graphics_nsb as #lander print #lander, "when characterInput [userInput]" print #lander, "trapclose [quit]" print #lander, "font Courier 8"
WindowWidth = 640 call makeSprites print #lander, "spritexy lem 50 50"
[startGame] 'initialize call setBackground print #lander, "setfocus" speed=150 ' for game play, set to 150 hoverMode=1 descendMode=1 autoMode=1 fuel = 20000' for game play, set to 15000-25000 altitude = 0 attitude = 0 longitude = 70 thrust = 0 call setHorizSpeed 2 call setVertSpeed 0 call gravityAccelerate timer speed, [timerTicked] startTime = time$("milliseconds") wait
[timerTicked] 'This is the main simulation routine! fuel=fuel-thrust*100
'automatically seek a landing site, then try to land if autoMode=-1 then 'maintains horizontal speed while seek is active if longitude >470 then if getHorizSpeed()>.05 then attitude=90-22.5-22.5 end if if longitude <10 then if getHorizSpeed()<-.05 then attitude = 90+22.5+22.5 end if if longitude<470 and longitude>10 then attitude=90 if getHorizSpeed()>=0 and getHorizSpeed()<.75 then attitude = 90+22.5+22.5 if getHorizSpeed()>=0 and getHorizSpeed()>1.25 then attitude = 90-22.5-22.5 if getHorizSpeed()<0 and getHorizSpeed()>-.75 then attitude = 90+22.5+22.5 if getHorizSpeed()<0 and getHorizSpeed()<-1.25 then attitude = 90-22.5-22.5 end if
'maintains altitude while seek is active if descendMode=1 then if getVertSpeed()<0 then thrustInput=thrustInput-1:if thrustInput<1 then thrustInput=1 if getVertSpeed()>0 then thrustInput=thrustInput+1:if thrustInput>10 then thrustInput=10 if altitude<0 then thrustInput=1 thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 end if
'determines whether lander is over a possible landing site 'if so, activate auto-descent mode if landerOverSite(longitude)=0 then landingPadLongitude=longitude:descendMode=-1 end if
'if you are not over a landing site, turn off auto-descent mode if landerOverSite(longitude) then if descendMode=-1 then descendMode=1:recoverMode=-1 end if end if
'recover mode activated when auto-seek misses a landing site if recoverMode=-1 then thrustInput=9:attitude=90 if getVertSpeed()<-2 then thrustInput=thrustInput+1:if thrustInput>7 then thrustInput=7 if altitude<30 then thrustInput=1:recoverMode=1 thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 end if
'auto-hover mode if hoverMode=-1 then 'reduces horizontal speed to close to zero if getHorizSpeed()>=-.1 and getHorizSpeed()<=.1 then attitude = 90 if getHorizSpeed()<-.1 then attitude = 90+22.5+22.5 if getHorizSpeed()>.1 then attitude=90-22.5-22.5
'maintains current altitude if getVertSpeed()<0 then thrustInput=thrustInput-1:if thrustInput<1 then thrustInput=1 if getVertSpeed()>0 then thrustInput=thrustInput+1:if thrustInput>10 then thrustInput=10 thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 end if
'auto-descent mode if descendMode=-1 then
'reduce horizontal speed to around zero attitude=90 if getHorizSpeed()>=-.05 and getHorizSpeed()<=.05 then attitude = 90 if getHorizSpeed()<-.05 then attitude = 90+22.5 if getHorizSpeed()>.05 then attitude=90-22.5 if getHorizSpeed()>.75 then attitude=90-22.5-22.5
'keep vertical speed between 1.3 and 1.9 (crashes at 2.0) if getVertSpeed()<1.3 then thrustInput=thrustInput-1:if thrustInput<1 then thrustInput=1 if getVertSpeed()>1.9 then thrustInput=thrustInput+1:if thrustInput>7 then thrustInput=7 thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 end if
'if lander altitude is above the terrain, apply thrust (if fuel=0 then no thrust applied), animate the lander if altitude <= terrain(longitude+15) - 24 then if fuel<=0 then thrust=0 call setAttitude attitude call applyThrust thrust, attitude call gravityAccelerate altitude = altitude + getVertSpeed() longitude = max(0, min(485, longitude + getHorizSpeed())) print #lander, "spritexy lem "; longitude; " "; altitude print #lander, "drawsprites" else 'otherwise, check to see if lander has crashed or landed timer 0 if landerCrashed(longitude, attitude) then #lander "place ";longitude+15;" ";altitude+15;";down;backcolor yellow;circlefilled 20;place 0 0;" notice "You crashed!" else notice "Successful landing!" end if confirm "Try again?"; answer if answer then [startGame] else [quit] end if
'display status updates on the window vclr$="green" if getVertSpeed()>=2 then vclr$="red" hclr$="green" if getHorizSpeed()>=2 then hclr$="red" fclr$="green" if fuel<5000 then fclr$="yellow" if fuel<1000 then fclr$="red" if fuel<1 then fclr$="pink" #lander "backcolor black;color white;place 1 15;\T: ";int(thrust*10) #lander "color ";vclr$;";place 1 30;\V: ";int(getVertSpeed()*100) #lander "color ";hclr$;";place 1 45;\H: ";int(getHorizSpeed()*100) if fuel<=0 then fl$="Empty" else fl$=str$(int(fuel)) #lander "color ";fclr$;";place 1 60;\F: ";fl$ if hoverMode=-1 then #lander "color white;place 1 75;\Hover" if descendMode=-1 then #lander "color cyan;place 1 75;\Descent" if autoMode=-1 then #lander "color yellow;place 1 90;\Seek" wait
[quit] timer 0 close #lander end
[userInput] char$ = Inkey$ if char$ ="h" then hoverMode=hoverMode*(-1):descendMode=1:autoMode=1 if char$ ="d" then descendMode=descendMode*(-1):hoverMode=1:autoMode=1 if char$ ="s" then autoMode=autoMode*(-1):descendMode=1:hoverMode=1 if char$ = "[" and hoverMode=1 then attitude = attitude - 22.5 if attitude < -0.01 then attitude = 337.5 wait end if if char$ = "]" and hoverMode=1 then attitude = attitude + 22.5 if attitude > 337.51 then attitude = 0 wait end if thrustInput = instr("0123456789", char$) if thrustInput then thrust = (thrustInput - 1) / 8 * 0.55 + 0.333 wait
function landerCrashed(xPosition, attitude) landerCrashed = int(attitude+0.1) <> 90 landerCrashed = landerCrashed or getVertSpeed() > 2 landerCrashed = landerCrashed or getHorizSpeed() > 2 landerCrashed = landerCrashed or terrain(xPosition) <> terrain(xPosition+30) landerCrashed = landerCrashed or terrain(xPosition) <> terrain(xPosition+15) end function
function landerOverSite(xPosition) 'returns a 0 if over a site landerOverSite = landerOverSite or terrain(xPosition) <> terrain(xPosition+30) landerOverSite = landerOverSite or terrain(xPosition) <> terrain(xPosition+15) end function
sub makeSprites open "lem" for graphics as #makeSprites print #makeSprites, "down" print #makeSprites, "place 0 31 ; backColor black ; boxfilled 640 73" for x = 0 to 15 y = 1 call drawLEM x, y, 270 + x * 22.5, 2, "black" y = 2 call drawLEM x, y, 270 + x * 22.5, 2, "darkgray" call drawLEM x, y, 270 + x * 22.5, 1, "lightgray" call getSprite x next x close #makeSprites print #lander, "addsprite lem lem0 lem1 lem2 lem3 lem4 lem5 lem6 lem7 lem8 lem9 lem10 lem11 lem12 lem13 lem14 lem15" end sub
sub drawLEM xPosition, yPosition, uncorrectedAngle, penSize, color$ angle = uncorrectedAngle print #makeSprites, "north ; color "; color$; " ; up ; turn "; angle print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "size "; penSize print #makeSprites, "up ; go 4 ; down ; circle 8" print #makeSprites, "turn 75 ; go 4 ; turn 180 ; go 4" print #makeSprites, "turn 30 ; go 4 ; turn 180 ; go 4 ; turn 255" print #makeSprites, "up ; turn 160 ; go 8" print #makeSprites, "down ; go 4 ; turn 110" print #makeSprites, "go 8 ; turn 110 ; go 4" print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "north ; up ; turn "; angle print #makeSprites, "go 4 ; turn 125 ; go 8 ; down ; turn 45 ; go 8" print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "north ; up ; turn "; angle print #makeSprites, "go 4 ; turn 235 ; go 8 ; down ; turn -45 ; go 8"
end sub
sub setBackground print #lander, "down ; fill black" call drawTerrain print #lander, "getbmp stars 0 0 490 315" print #lander, "background stars" end sub
sub getSprite spritNum spriteX = spritNum * 30 print #makeSprites, "getbmp lem"; spritNum; " "; spriteX; " 1 30 60" end sub
sub setHorizSpeed xSpeed vars(0) = xSpeed end sub
sub setVertSpeed ySpeed vars(1) = ySpeed end sub
function getHorizSpeed() getHorizSpeed = vars(0) end function
function getVertSpeed() getVertSpeed = vars(1) end function
sub setAttitude degrees print #lander, "spriteimage lem lem"; int(degrees / 22.5) end sub
sub gravityAccelerate call setVertSpeed getVertSpeed() + 0.3'(6/18) end sub
sub applyThrust qtyFuel, angle angleXform = angle / 180 * 3.141592 call setHorizSpeed getHorizSpeed() - (qtyFuel/2) * cos(angleXform) call setVertSpeed getVertSpeed() - (qtyFuel/2) * sin(angleXform) end sub
sub drawTerrain rate1 = rnd(1) / (rnd(1) * 17 + 10) rate2 = rnd(1) / (rnd(1) * 10 + 10) print #lander, "down ; size 1 ; color white"
for x = 0 to 499 step 1 if rnd(1) < 0.015 then gosub [makeLandingZone] holder1 = holder1+rate1 holder2 = holder2+rate2 holder3 = holder3+sin(holder2)/20 y = 200+int(sin(holder1)*50)+int(cos(holder2)*50)+int(cos(holder3)*15) terrain(x) = y print #lander, "goto "; x; " "; y next x goto [endSub]
[makeLandingZone] width = int((rnd(1)*4+2)/3) for lz = x to min(499, x + 34 * width) terrain(lz) = y print #lander, "goto "; lz; " "; y next lz x = lz return
[endSub] end sub
|
|
|
Post by David Drake on Mar 7, 2020 4:07:40 GMT -5
I spent a few minutes trying to activate auto-landing with S button, as program says. I died that frequently only in Tomb Rider Oops. Edited post. Try again.
|
|
|
Post by David Drake on Mar 13, 2020 6:24:41 GMT -5
Next pass at this. Improved algorithm. Now lands safely in Seek mode 96% of the time (as long as starting fuel level >= 20,000).
'Lander.bas 'written by Carl Gundel 'carlg@world.std.com 'Needs at least Liberty BASIC v2.0 'This file is contributed to the public domain 'At this stage it is merely a prototype. 'Use the keys 0 through 9 to control thrust 'Use the [ and ] keys to rotate the ship!
'You must make a VERY gentle and level landing on one of the flat areas!
'[s] Auto Seek mode added (finds landing site and attempts landing) '[h] Auto Hover mode added (maintains altitude and longitude) '[d] Auto Descend mode added (controls descent speed) 'Hint:Set fuel=20000 or higher to land in Seek mode 90+% of the time
'open game window nomainwin notice "Instructions 1/2"+chr$(13)+_ "-Land on flat regions"+chr$(13)+_ "-Max safe landing speed (vertical and horizontal) is 200"+chr$(13)+_ "-Don't run out of fuel!"+chr$(13)+chr$(13)+_ "-Use [ and ] to rotate lander"+chr$(13)+_ "-Use 0-9 to select thrust"+chr$(13)+_ "-s activates auto-seek (fuel eater)"+chr$(13)+_ "-h activates auto-hover mode (fuel eater)"+chr$(13)+_ "-d activates auto-descent mode" UpperLeftX = 50 UpperLeftY = 50 WindowWidth = 500 WindowHeight = 340 dim terrain(5000) open "Lunar Lander" for graphics_nf_nsb as #lander print #lander, "when characterInput [userInput]" print #lander, "trapclose [quit]" print #lander, "font Courier 6;backcolor black;color white" call makeSprites print #lander, "spritexy lem 50 50"
[startGame] 'initialize call setBackground print #lander, "setfocus" speed=150 ' for game play, set to 150 hoverMode=1 descendMode=1 autoMode=1 fuel = 20000' for game play, set to 15000-25000 altitude = 0 attitude = 90 longitude = 10 thrust = 0 call setHorizSpeed 1.75 call setVertSpeed 0 call gravityAccelerate timer speed, [timerTicked] startTime = time$("milliseconds") wait
[timerTicked] 'This is the main simulation routine! fuel=fuel-thrust*100
'AUTOMATIC HOVER/DESCEND/SEEK FUNCTIONS START HERE 'automatically seek a landing site, then try to land if autoMode=-1 then 'maintains postive or negative horizontal speed while seek is active if longitude >470 then if getHorizSpeed()>.05 then attitude=45 end if if longitude <10 then if getHorizSpeed()<-.05 then attitude = 135 end if if longitude<470 and longitude>10 then attitude=90 if getHorizSpeed()>=0 and getHorizSpeed()<1.5 then attitude = 135 if getHorizSpeed()>=0 and getHorizSpeed()>2.0 then attitude = 45 if getHorizSpeed()<0 and getHorizSpeed()>-1.5 then attitude = 135 if getHorizSpeed()<0 and getHorizSpeed()<-2.0 then attitude = 45 end if
'maintains altitude while seek is active if descendMode=1 then if getVertSpeed()<0 then thrustInput=thrustInput-1:if thrustInput<1 then thrustInput=1 if getVertSpeed()>0 then thrustInput=thrustInput+1:if thrustInput>10 then thrustInput=10 if altitude<0 then thrustInput=1 thrust=setThrust(thrustInput) end if
'determines whether lander is over a possible landing site 'if so, activate auto-descent mode if landerOverSite(longitude)=0 then landingPadLongitude=longitude:descendMode=-1 end if
'if you are not over a landing site, turn off auto-descent mode if landerOverSite(longitude) then if descendMode=-1 then descendMode=1:recoverMode=-1:print "Recover mode triggered" end if end if
'auto-recover mode activated when auto-seek misses a landing site if recoverMode=-1 then thrustInput=8:attitude=90 if getVertSpeed()<-2 then thrustInput=thrustInput+1:if thrustInput>6 then thrustInput=6 if altitude<30 then thrustInput=1:recoverMode=1 thrust=setThrust(thrustInput) end if
'auto-hover mode maintains constant altitude and longitude if hoverMode=-1 then 'reduces horizontal speed to close to zero if getHorizSpeed()>=-.1 and getHorizSpeed()<=.1 then attitude = 90 if getHorizSpeed()<-.1 then attitude = 135 if getHorizSpeed()>.1 then attitude=45
'maintains current altitude if getVertSpeed()<0 then thrustInput=thrustInput-1:if thrustInput<1 then thrustInput=1 if getVertSpeed()>0 then thrustInput=thrustInput+1:if thrustInput>10 then thrustInput=10 thrust=setThrust(thrustInput) end if
'auto-descent mode maintains constant longitude and keeps vertical speed below 2 (crash velocity) if descendMode=-1 then 'reduce horizontal speed to around zero attitude=90 if getHorizSpeed()<-1.5 then attitude=180:thrustInput=9 if getHorizSpeed()<-.25 then attitude=135:thrusInput=8 if getHorizSpeed()<-.01 then attitude = 112.5:thrustInput=7 if getHorizSpeed()>.01 then attitude=67.5:thrustInput=9 if getHorizSpeed()>.25 then attitude=45:thrusInput=8 if getHorizSpeed()>1.5 then attitude=0:thrustInput=7 if getHorizSpeed()>=-.01 and getHorizSpeed()<=.01 then attitude = 90
'keep vertical speed between 1.3 and 1.9 (crashes at 2.0) if getVertSpeed()<1.7 then thrustInput=thrustInput-1:if thrustInput<1 then thrustInput=1 if getVertSpeed()>1.85 then thrustInput=thrustInput+1:if thrustInput>7 then thrustInput=7 thrust=setThrust(thrustInput) end if 'AUTOMATIC HOVER/DESCEND/SEEK FUNCTIONS END HERE
'if lander altitude is above the terrain, apply thrust (if fuel=0 then no thrust applied), animate the lander if altitude <= terrain(longitude+15) - 24 then if fuel<=0 then thrust=0 call setAttitude attitude call applyThrust thrust, attitude call gravityAccelerate altitude = altitude + getVertSpeed() longitude = max(0, min(485, longitude + getHorizSpeed())) print #lander, "spritexy lem "; longitude; " "; altitude print #lander, "drawsprites" else 'otherwise, check to see if lander has crashed or landed timer 0 if landerCrashed(longitude, attitude) then #lander "place ";longitude+15;" ";altitude+15;";down;backcolor yellow;circlefilled 20;place 0 0;backcolor black" notice "You crashed!" else notice "Successful landing!" end if confirm "Try again?"; answer if answer then [startGame] else [quit] end if
'display status updates on the window #lander "place 1 13;\Thr: ";int(thrust*100) #lander "place 80 13;\Ver: ";int(getVertSpeed()*1000) #lander "place 160 13;\Hor: ";int(getHorizSpeed()*1000) #lander "place 240 13;\Fuel: ";str$(int(fuel)) if hoverMode=-1 then #lander "place 340 13;\Hover" if descendMode=-1 then #lander "place 340 13;\Descend" if autoMode=-1 then #lander "place 420 13;\Seek" #lander "place 0 500" wait
[quit] timer 0 close #lander end
[userInput] char$ = lower$(Inkey$) if char$ ="h" then hoverMode=hoverMode*(-1):descendMode=1:autoMode=1 if char$ ="d" then descendMode=descendMode*(-1):hoverMode=1:autoMode=1 if char$ ="s" then autoMode=autoMode*(-1):descendMode=1:hoverMode=1 if char$ = "[" and hoverMode=1 then attitude = attitude - 22.5 if attitude < -0.01 then attitude = 337.5 wait end if if char$ = "]" and hoverMode=1 then attitude = attitude + 22.5 if attitude > 337.51 then attitude = 0 wait end if thrustInput = instr("0123456789", char$) if thrustInput then thrust=setThrust(thrustInput) wait
function landerCrashed(xPosition, attitude) landerCrashed = int(attitude+0.1) <> 90 landerCrashed = landerCrashed or getVertSpeed() > 2 landerCrashed = landerCrashed or getHorizSpeed() > 2 landerCrashed = landerCrashed or terrain(xPosition) <> terrain(xPosition+30) landerCrashed = landerCrashed or terrain(xPosition) <> terrain(xPosition+15) end function
function landerOverSite(xPosition) 'returns a 0 if over a site landerOverSite = landerOverSite or terrain(xPosition) <> terrain(xPosition+30) landerOverSite = landerOverSite or terrain(xPosition) <> terrain(xPosition+15) end function
sub makeSprites open "lem" for graphics as #makeSprites print #makeSprites, "down" print #makeSprites, "place 0 31 ; backColor black ; boxfilled 640 73" for x = 0 to 15 y = 1 call drawLEM x, y, 270 + x * 22.5, 2, "black" y = 2 call drawLEM x, y, 270 + x * 22.5, 2, "darkgray" call drawLEM x, y, 270 + x * 22.5, 1, "lightgray" call getSprite x next x close #makeSprites print #lander, "addsprite lem lem0 lem1 lem2 lem3 lem4 lem5 lem6 lem7 lem8 lem9 lem10 lem11 lem12 lem13 lem14 lem15" end sub
sub drawLEM xPosition, yPosition, uncorrectedAngle, penSize, color$ angle = uncorrectedAngle print #makeSprites, "north ; color "; color$; " ; up ; turn "; angle print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "size "; penSize print #makeSprites, "up ; go 4 ; down ; circle 8" print #makeSprites, "turn 75 ; go 4 ; turn 180 ; go 4" print #makeSprites, "turn 30 ; go 4 ; turn 180 ; go 4 ; turn 255" print #makeSprites, "up ; turn 160 ; go 8" print #makeSprites, "down ; go 4 ; turn 110" print #makeSprites, "go 8 ; turn 110 ; go 4" print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "north ; up ; turn "; angle print #makeSprites, "go 4 ; turn 125 ; go 8 ; down ; turn 45 ; go 8" print #makeSprites, "place "; (xPosition)*30+15; " "; (yPosition-1)*30+15 print #makeSprites, "north ; up ; turn "; angle print #makeSprites, "go 4 ; turn 235 ; go 8 ; down ; turn -45 ; go 8"
end sub
sub setBackground print #lander, "down ; fill black" call drawTerrain print #lander, "getbmp stars 0 0 490 315" print #lander, "background stars" end sub
sub getSprite spritNum spriteX = spritNum * 30 print #makeSprites, "getbmp lem"; spritNum; " "; spriteX; " 1 30 60" end sub
sub setHorizSpeed xSpeed vars(0) = xSpeed end sub
sub setVertSpeed ySpeed vars(1) = ySpeed end sub
function getHorizSpeed() getHorizSpeed = vars(0) end function
function getVertSpeed() getVertSpeed = vars(1) end function
function setThrust(t) setThrust=(t-1)/8*0.55+0.333 end function
sub setAttitude degrees print #lander, "spriteimage lem lem"; int(degrees / 22.5) end sub
sub gravityAccelerate call setVertSpeed getVertSpeed() + 0.3'(6/18) end sub
sub applyThrust qtyFuel, angle angleXform = angle / 180 * 3.141592 call setHorizSpeed getHorizSpeed() - (qtyFuel/2) * cos(angleXform) call setVertSpeed getVertSpeed() - (qtyFuel/2) * sin(angleXform) end sub
sub drawTerrain rate1 = rnd(1) / (rnd(1) * 17 + 10) rate2 = rnd(1) / (rnd(1) * 10 + 10) print #lander, "down ; size 1 ; color white"
for x = 0 to 499 step 1 if rnd(1) < 0.015 then gosub [makeLandingZone] holder1 = holder1+rate1 holder2 = holder2+rate2 holder3 = holder3+sin(holder2)/20 y = 200+int(sin(holder1)*50)+int(cos(holder2)*50)+int(cos(holder3)*15) terrain(x) = y print #lander, "goto "; x; " "; y next x goto [endSub]
[makeLandingZone] width = int((rnd(1)*4+2)/3) for lz = x to min(499, x + 34 * width) terrain(lz) = y print #lander, "goto "; lz; " "; y next lz x = lz return
[endSub] end sub
|
|