Lunarcy is a fun and simple lunar lander game written in Apple Logo and compatible with microM8’s microLogo, a vector-based OpenGL re-implementation. You control a lander with a joystick (or the keyboard’s arrow keys) and you can increase / decrease fuel to the main engine, and thrusters on the side of the craft as you try to land on the flat part of the moons surface. You need to avoid the hills or you will crash, but be careful – if you run out of fuel you will drop like a stone.
Once you’re inside Apple Logo, type LOAD “LUNARCY to load Lunacy from the disk image available at paleotronic.com/lunarcy.dsk or enter the listing by hand.
Type game to start. You can also find Lunarcy inside the microM8 Apple II emulator file catalog at /appleii/logo/lunarcy.lgo
Description of Logo procedures:
start.level is called to generate the terrain by calling generate.terrain, then calls draw.terrain to draw the terrain.
generate.terrain creates a terrain by generating random terrain heights across the screen, including a consecutive safe zone for landing. It builds a list of y values in the variable :tlevels, calling calc.terrain to calculate the level of the terrain in a given segment.
draw.terrain is called at the start of the level, and uses the data in the :tlevels variable to draw the moon surface. It does this by using setpos with the turtles pen in the down position which draws lines as it moves from point to point on the screen.
test.segment checks the landers horizontal and vertical position to determine if the lander is below the tip of the rocks. If so, the function returns 1, or 0 if the lander is safe. This function is called once per game.loop
game.loop is the main loop for the lander game. it draws the ship, waits for half a second (for the video to show), then checks the keyboard and the paddles for changes that will affect the crafts thrusters. It applies those changes by calling apply.forces, and updates the text display at the bottom of the screen with the remaining fuel, vertical velocity and horizontal velocity. It then calls test.segment, and if the craft has hit the mountains, it will call crash.terrain, otherwise it checks if the lander has reached the surface, and if so it calls eval.landing to test if the landing was safe. If none of those conditions were met, it calls itself (game.loop) again recursively to continue.
check.paddles checks the joystick/paddle controls. horizontal motion puts fuel to the side thrusters, vertical motion increases or decreases fuel to the main engine. check keys does the same, except rather than checking the stick, reads the state of the arrow keys. It calls one of thrust.up, thrust.down, thrust.left or thrust.right to alter the burn parameters.
apply.forces applies the current fuel settings, and adjusts the thrust levels and speed of the craft in the horizontal and vertical directions. It handles acceleration due to the moon’s gravity as well. To keep things fast, approximations are used.
eval.landing checks to make sure the craft is not too tilted, and that the horizontal and vertical speeds of the craft are below the safety threshold (1 m/s). If a safe landing is achieved, it reduces the width of the safe zone, and calls start.level to start a new level with a new terrain.
draw.ship moves the turtle (acting as our ship) to the correct position on the screen, and sets the “tilt” of the ship if it is moving horizontally.
abs returns the ‘absolute value’ of a number by changing a negative number into a positive one.
The four thrust procedures increase or decrease the fuel usage, or change the thrust balance between the two rockets as appropriate.
calc.terrain calculates the height of a segment in the terrain for generate.terrain.
crash.terrain outputs a message to let the player know they have crashed.
TO draw.ship
PU
SETX :SHIPX
SETY :SHIPY
MAKE “angle :FUELATTITUDETHRUSTER * 5
SETHEADING :ANGLE
PD
END
TO crash.terrain
PR [YOU CRASHED INTO THE ROCKY TERRAIN]
END
TO thrust.left
MAKE “fuelAttitudeThruster :FUELATTITUDETHRUSTER – :HDELTA
END
TO thrust.right
MAKE “fuelAttitudeThruster :FUELATTITUDETHRUSTER + :HDELTA
END
TO thrust.up
MAKE “fuelEngine :FUELENGINE + :VDELTA
END
TO check.keys
IF not KEYP [STOP]
LOCAL “CODE
MAKE “CODE ASCII READCHAR
IF :CODE = 21 [THRUST.RIGHT STOP]
IF :CODE = 8 [THRUST.LEFT STOP]
IF :CODE = 10 [THRUST.DOWN STOP]
IF :CODE = 11 [THRUST.UP STOP]
IF :CODE = 27 [THROW “toplevel]
END
TO thrust.down
MAKE “fuelEngine :FUELENGINE – :VDELTA
IF :FUELENGINE < 0 [MAKE “fuelEngine 0]
END
TO draw.terrain :SEGMENTS
HT
LOCAL “idx
MAKE “idx 1
PU
SETX -139
SETY -64
PD
LOCAL “x
LOCAL “y
MAKE “y -64
MAKE “x -139
SETPC 3
REPEAT :SEGMENTS [MAKE “y ITEM :IDX :TLEVELS MAKE “x :X + 279 / :SEGMENTS SETPOS LIST :X :Y MAKE “idx :IDX + 1]
SETPC 1
ST
END
TO setup
MAKE “totalFuel 3000
MAKE “fuelEngine 0
MAKE “fuelAttitudeThruster 0
MAKE “fuelThrustRatio 0.09
MAKE “shipX 0
MAKE “shipY 94
MAKE “thrustY 0
MAKE “thrustX 0
MAKE “speedX 0
MAKE “speedY 0
MAKE “moonGAccel 1.62
MAKE “landMaxSafeV 1
MAKE “hDelta 1
MAKE “vDelta 10
MAKE “angle 0
MAKE “segments 40
END
TO start.level
CS
SETUP
TEXTSCREEN
CLEARTEXT
PR [GENERATING THE MOON]
GENERATE.TERRAIN :SEGMENTS :SAFE
DRAW.TERRAIN :SEGMENTS
END
TO eval.landing
LOCAL “aa
MAKE “aa ABS :ANGLE
LOCAL “ay
MAKE “ay ABS :SPEEDY
LOCAL “ax
MAKE “ax ABS :SPEEDX
IF :AY > :LANDMAXSAFEV [MAKE “shipY -64 LT 80 DRAW.SHIP PR [CRASHED INTO SURFACE – UNSAFE DESCENT] THROW “toplevel]
IF :AX > :LANDMAXSAFEV [MAKE “shipY -64 LT 45 DRAW.SHIP PR [CRASHED INTO SURFACE – UNSAFE DESCENT] THROW “toplevel]
IF :AA > 10 [MAKE “shipY -64 DRAW.SHIP PR [CRASHED INTO SURFACE – UNSAFE ANGLE] THROW “toplevel]
PR [HOORAY YOU LANDED SAFELY]
WAIT 180
MAKE “safe :SAFE – 2
IF :SAFE < 4 [PR [NICE WORK – ACE LANDER] THROW “toplevel]
PR [LETS MAKE IT A BIT HARDER]
WAIT 60
START.LEVEL
END
TO game.loop
DRAW.SHIP
WAIT 30
CHECK.KEYS
CHECK.PADDLES
APPLY.FORCES
LOCAL “ay
LOCAL “ax
MAKE “ay ABS :SPEEDY
MAKE “ax ABS :SPEEDX
SETCURSOR [0 20]
PR SENTENCE “FUEL :TOTALFUEL
SETCURSOR [0 21]
PR SENTENCE “VY :AY
SETCURSOR [0 22]
PR SENTENCE “VX :AX
LOCAL “crash
MAKE “crash TEST.SEGMENT :SEGMENTS
IF :CRASH = 1 [CRASH.TERRAIN STOP]
IF :SHIPY < -64 [EVAL.LANDING]
IF :SHIPY > 100 [PR [FLUNG INTO SPACE] STOP]
GAME.LOOP
END
TO generate.terrain :SEGMENTS :SAFE
LOCAL “safestart
LOCAL “av
MAKE “av :SEGMENTS – :SAFE
MAKE “safestart RANDOM :AV
LOCAL “idx
MAKE “idx 1
LOCAL “rval
MAKE “tlevels []
REPEAT :SEGMENTS [MAKE “rval CALC.TERRAIN :IDX :SAFESTART :SAFE MAKE “tlevels LPUT :RVAL :TLEVELS MAKE “idx :IDX + 1]
END
TO apply.forces
LOCAL “fe
MAKE “fe :FUELENGINE
MAKE “fa :FUELATTITUDETHRUSTER
IF :FE > :TOTALFUEL [MAKE “fe :TOTALFUEL MAKE “fa 0]
MAKE “thrustX :FUELTHRUSTRATIO * :FA
MAKE “thrustY :FUELTHRUSTRATIO * :FE
MAKE “totalFuel :TOTALFUEL – :FE – ABS :FA
MAKE “speedY :SPEEDY – :MOONGACCEL + :THRUSTY
MAKE “speedX :SPEEDX + :THRUSTX
MAKE “shipX :SHIPX + :SPEEDX
MAKE “shipY :SHIPY + :SPEEDY
END
TO game
CS
SETHEADING 0
MAKE “SAFE 20
START.LEVEL
GAME.LOOP
END
TO check.paddles
LOCAL “v
MAKE “v 255 – PADDLE 1
LOCAL “f
MAKE “f :V / 255
IF :F < 0.167 [MAKE “f 0]
MAKE “fuelEngine 24 * :F
LOCAL “h
MAKE “h PADDLE 0
LOCAL “a
MAKE “a :H – 127
LOCAL “fa
MAKE “fa :A / 127
MAKE “fuelAttitudeThruster :FA * 5
END
TO TEST.SEGMENT :SEGMENTS
LOCAL “x
LOCAL “y
MAKE “x XCOR
MAKE “y YCOR
LOCAL “ssize
MAKE “ssize 280 / :SEGMENTS
LOCAL “seg
LOCAL “rseg
MAKE “rseg ROUND :SEG
IF :RSEG > :SEGMENTS [MAKE “rseg :SEGMENTS]
LOCAL “fl
MAKE “fl ITEM :RSEG :TLEVELS
IF :Y > :FL [OUTPUT 0]
IF :FL = -64 [OUTPUT 0]
OUTPUT 1
END
TO ABS :NUMBER
IF :NUMBER < 0 [OUTPUT 0 – :NUMBER]
OUTPUT :NUMBER
END
TO CALC.TERRAIN :IDX :SAFESTART :SAFE
IF :IDX < :SAFESTART [OUTPUT -64 + RANDOM 64 STOP]
IF :IDX > :SAFESTART + :SAFE [OUTPUT -64 + RANDOM 64 STOP]
OUTPUT -64
END
Be the first to comment