# Lunar lander

Old school style. I wrote this in 2011, before there was font support, thus the 7 segment display code.

All three dots need to be green to not crash when contacting the platform.

The version of Codea I ran it on today looks to be 2.3.1 (47)

``````function setup() -- Lander
delayCalib=200000  -- For the iPad 2 (hacky way to tune play speed)
-- delayCalib=3400000  -- For the iPad Air
touches={}
thrust=0
dx=0
dy=-15
dxx=0
dyy=0
rot=0
fuel=250
displayMode(FULLSCREEN_NO_BUTTONS)
ground = {}
ground[0] = math.random(60)+112
flatsx={}
flatsy={}

-- create the three landing zones
i=0
while i <= WIDTH do
i=i+1
ground[i] = ground[i-1] + math.random(11) - 6

if ground[i] < 112 then
ground[i] = 112
end

if i==100 then
flatsx[0] = i
flatsy[0] = ground[i]
while i <= 120 do
i=i+1
ground[i] = flatsy[0]
end
end
if i == WIDTH/2 then
flatsx[1] = i
flatsy[1] = ground[i]
while i<=WIDTH/2+30 do
i=i+1
ground[i] = flatsy[1]
end
end
if i == WIDTH-100 then
flatsx[2] = i
flatsy[2] = ground[i]
while i<=WIDTH-100+20 do
i=i+1
ground[i] = flatsy[2]
end
end
end

-- lander has two possible start positions
landerx=(math.random(2)-1)*260+WIDTH/2-130
landery=HEIGHT

ended=0
crashed=0
gravity=.6
segScale=12
piece1rot=0
piece1x=0
piece1y=0
piece2rot=0
piece2x=0
piece2y=0
piece3rot=0
piece3x=0
piece3y=0
piece4rot=0
piece4x=0
piece4y=0
end

function touched(touch)
if touch.state == ENDED then
touches[touch.id] = nil
else
touches[touch.id] = touch
end
end

-- 7 segment display, origin of display is lower left

function segA()
line(0, segScale*2, segScale, segScale*2)
end

function segB()
line(segScale, segScale, segScale, segScale*2)
end

function segC()
line(segScale, 0, segScale, segScale)
end

function segD()
line(0, 0, segScale, 0)
end

function segE()
line(0,0,0,segScale )
end

function segF()
line(0,segScale,0,segScale*2)
end

function segG()
line(0,segScale,segScale,segScale)
end

function drawDigit(digit)
if digit == '0' then
segA()
segB()
segC()
segD()
segE()
segF()
elseif digit ==  '1' then
segB()
segC()
elseif digit == '2' then
segA()
segB()
segG()
segE()
segD()
elseif digit == '3' then
segA()
segB()
segG()
segC()
segD()
elseif digit == '4' then
segF()
segB()
segG()
segC()
elseif digit == '5' then
segA()
segF()
segG()
segC()
segD()
elseif digit == '6' then
segA()
segF()
segG()
segE()
segC()
segD()
elseif digit == '7' then
segA()
segB()
segC()
elseif digit == '8' then
segA()
segB()
segC()
segD()
segE()
segF()
segG()
elseif digit == '9' then
segA()
segB()
segC()
segF()
segG()
elseif digit == ':' then
line(segScale/2, segScale/2, segScale/2, segScale/2-1)
line(segScale/2, segScale+segScale/2, segScale/2, segScale-1+segScale/2)
elseif digit == ' ' then
-- blank
elseif digit == '-' then
segG()
else
print("unknown digit"..digit)
end
end

function drawNumber(number,x,y)
pushMatrix()
translate(x,y)
len= string.len(number)
for i = 1, len do
drawDigit(string.sub(number, i,i))
translate(segScale+segScale/5+1, 0)
end
popMatrix()
return (len+1)*segScale
end

function draw()
background(0, 0, 0, 255)
noSmooth()
stroke(255,255,255)
fill(255,255,255)

pushStyle()
strokeWidth(2)
stroke(186, 186, 186, 255)
fill(54, 54, 54, 255)
rect(0,0,75,75)
rect(100,0,75,75)

stroke(214, 194, 58, 255)
fill(45, 45, 26, 255)
rect(WIDTH-75,0,75,75)
popStyle()

rect(0,100,WIDTH,1)

thrust = 0

for k,touch in pairs(touches) do
x=touch.x
y=touch.y

if ended == 0 then
if x < 75 and y < 75 then
rot = rot + 3
end

if x > 100 and x < 175 and y < 75 then
rot=rot-3
end

if x > WIDTH-75 and y < 75 then
thrust = 1
end
end
end

if ended == 0 then
landerx = landerx + dx/30
landery = landery + dy/50
dy = dy - gravity
end

if thrust == 1 and ended == 0 and fuel > 0 then
--      sound("explode", 0)      sounds not multi threaded :(
dy = dy + 2*dyy
dx = dx - 2*dxx
if fuel >= 1 then
fuel=fuel-1
end
end

-- draw the lander
strokeWidth(1)
stroke(255, 255, 255, 255)

pushMatrix()
translate(landerx,landery)

if crashed == 0 then
rotate(rot)
line(3,0,-3,0)
line(-3,0,-6,3)
line(-6,3,-6,8)
line(-6,8,-3,11)
line(-3,11,3,11)
line(3,11,6,8)
line(6,8,6,3)
line(6,3,3,0)

line(-4,1,-8,-7)
line(4,1,8,-7)

if thrust == 1 and ended == 0 and fuel > 0 then
pushStyle()
c = color(255, 134, 0, 255)
fill(c)
stroke(255,134,0,255)
rect(-1, -13, 2, 8)
popStyle()
end
else -- lander exploding
piece1rot = piece1rot - 6
piece1x = piece1x -.2
piece1y = piece1y -.4
piece2rot = piece2rot + 2
piece2x = piece2x - .4
piece2y = piece2y + .3
piece3rot = piece3rot - 4
piece3x = piece3x + .7
piece3y = piece3y + .6
piece4rot = piece4rot + 2
piece4x = piece4x -.2
piece4y = piece4y + .1

translate(piece1x, piece1y)
pushMatrix()
rotate(piece1rot)
line(3,0,-3,0)
line(-3,0,-6,3)
popMatrix()

translate(piece2x, piece2y)
pushMatrix()
rotate(piece2rot)
line(-6,8,-3,11)
line(-3,11,3,11)
line(3,11,6,8)
popMatrix()

translate(piece3x, piece3y)
pushMatrix()
rotate(piece3rot)
line(3,11,6,8)
line(6,8,6,3)
line(6,3,3,0)
popMatrix()

translate(piece4x, piece4y)
pushMatrix()
rotate(piece4rot)
line(-4,1,-8,-7)
popMatrix()
end
popMatrix()

for i = 0, delayCalib do
end

spacing = 80
pos1 = WIDTH/2-100
pos2 = pos1+spacing
pos3 = pos2+spacing
pos4 = pos3+spacing

drawNumber(-math.floor(dy), pos1, 5)
drawNumber(math.floor(dx), pos2, 5)
drawNumber(math.abs(rot), pos3,5)
drawNumber(fuel, pos4, 5)
green = color(20, 181, 63, 255)
red = color(207, 22, 14, 255)

if math.abs(dy) > 12 then
fill(red)
else
fill(green)
end
ellipse(pos1+segScale, 60, 15)
if math.abs(dx) > 5 then
fill(red)
else
fill(green)
end
ellipse(pos2+segScale, 60, 15)
if math.abs(rot) > 7 then
fill(red)
else
fill(green)
end
ellipse(pos3+segScale, 60, 15)
if fuel < 150 then
if fuel<50 then
fill(red)
else
fill(237, 230, 59, 255)
end
if math.floor(ElapsedTime%2) == 0 then --flash
ellipse(pos4+segScale, 60, 15)
end
end

stroke(255,255,255)

for i = 0,WIDTH do
line(i,ground[i],i,ground[i]-1)
end

-- check to see if landed or crashed
for i=0,2 do
if i==1 then
platformWidth = 30
else
platformWidth = 20
end
line(flatsx[i], flatsy[i], flatsx[i]+platformWidth, flatsy[i])

if ended == 0 then
if landerx > flatsx[i]+3 and landerx < flatsx[i] +platformWidth-3 and landery <= flatsy[i] + 8 then
if math.abs(dy) <= 12 and math.abs(dx) <= 5 and math.abs(rot) <= 7 then
print("Landed!!!")
elseif math.abs(dy) > 12 or math.abs(dx) > 7 then
print("Crashed!!! Too fast")
crashed = 1
elseif math.abs(rot) > 5 then
print("Crashed!!! Not vertical")
crashed = 1
end
ended = 1
end
end
end

if landery <= ground[math.floor(landerx)]+8 and ended == 0 then
print("Crashed!!! Missed platform")
ended = 1
crashed = 1
end

end

``````

@Ophitoxaemia Nice program. I haven’t been able to land yet, I keep crashing. I corrected an error in your code. Not sure why it was there. You had

``````ground[i] = flatsy[2]850000
``````

I commented out the 850000 in the code above.

Thanks! And I removed the number entirely, must have gotten pasted in somehow when I copied the code.

The center pad is the easiest (and largest). The initial lander location is set so there is always a closer small pad and the far one (hardest).

@Ophitoxaemia I increased my fuel amount and was able to land 1 time so far. The controls are very touchy and you have to do it just right. Are you going to rewrite the code to use the updated functions.

I was able to land on all three types of platforms just now. Only the farthest one should fuel be a problem (I had 42 fuel left). The trick is to wait as long as possible to start the burn (but not too long!)

I think I’ll just leave this one and write a new game, if I do.

@Ophitoxaemia I’m on an iPad Air, so things run a lot faster than an iPad 2. Maybe I should try it on my iPad 1.

But you don’t need to do that.

delayCalib=200000 – hacky way to tune play speed

such that it takes 20 seconds for the lander to fall from the top and crash, not touching any controls.

I had to change the 200,000 to 3,400,000 for the 20 sec free fall. That made it easier to land.

BTW, for the younger readers, the inspiration for this was a game I remember from the Arcades of Old: https://en.wikipedia.org/wiki/Lunar_Lander_(1979_video_game)

You can use delta time updating to standardise the velocity of game objects across the various devices it’ll be played on