- 2048: Grid merging, directional movement, score tracking, win/draw detection - Tic-Tac-Toe: Minimax AI opponent, perfect play, win detection - Lunar Lander: Gravity + thrust physics, fuel management, landing validation - Air Hockey: Refined paddle physics, puck acceleration, goal detection All games tested for state transitions, collision logic, and win conditions. Suite now complete with 10 classic games ready for SD card deployment.
174 lines
6.0 KiB
Lua
174 lines
6.0 KiB
Lua
-- NAME: Lunar Lander
|
|
-- DESC: Land safely with limited fuel
|
|
|
|
-- Game states
|
|
local STATE_MENU = 0
|
|
local STATE_PLAYING = 1
|
|
local STATE_LANDED = 2
|
|
local STATE_CRASHED = 3
|
|
|
|
-- Game constants
|
|
local GRAVITY = 0.15
|
|
local THRUST_POWER = 0.3
|
|
local MAX_FUEL = 100
|
|
local SAFE_LANDING_SPEED = 1.5
|
|
|
|
function init()
|
|
game.vars.state = STATE_MENU
|
|
game.vars.score = 0
|
|
|
|
-- Lander
|
|
game.vars.lander_x = game.width() / 2
|
|
game.vars.lander_y = 10
|
|
game.vars.lander_vel_y = 0
|
|
game.vars.fuel = MAX_FUEL
|
|
game.vars.thrusting = false
|
|
|
|
-- Terrain
|
|
game.vars.landing_zone_x = game.width() / 2 - 20
|
|
game.vars.landing_zone_w = 40
|
|
game.vars.terrain_y = game.height() - 15
|
|
|
|
-- Enable continuous updates
|
|
game.set_frame_updates(true)
|
|
|
|
print("Lunar Lander initialized")
|
|
end
|
|
|
|
function update(event)
|
|
local state = game.vars.state
|
|
|
|
if state == STATE_MENU then
|
|
if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then
|
|
reset_game()
|
|
game.vars.state = STATE_PLAYING
|
|
return true
|
|
end
|
|
|
|
elseif state == STATE_PLAYING then
|
|
-- Handle thrust input
|
|
if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.TOUCH_MOVE then
|
|
if game.vars.fuel > 0 then
|
|
game.vars.thrusting = true
|
|
game.vars.fuel = game.vars.fuel - 1
|
|
else
|
|
game.vars.thrusting = false
|
|
end
|
|
else
|
|
game.vars.thrusting = false
|
|
end
|
|
|
|
-- Update physics on frame tick
|
|
if event.type == INPUT.FRAME_TICK then
|
|
update_lander()
|
|
check_landing()
|
|
return true
|
|
end
|
|
|
|
elseif state == STATE_LANDED or state == STATE_CRASHED then
|
|
if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then
|
|
game.vars.state = STATE_MENU
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function draw()
|
|
renderer.clear(false)
|
|
|
|
local state = game.vars.state
|
|
|
|
if state == STATE_MENU then
|
|
renderer.text(game.width() / 2 - 50, game.height() / 2 - 30, "LUNAR LANDER", true)
|
|
renderer.text(game.width() / 2 - 70, game.height() / 2 - 5, "Land in the zone safely", true)
|
|
renderer.text(game.width() / 2 - 50, game.height() / 2 + 20, "Tap to Start", true)
|
|
|
|
elseif state == STATE_PLAYING or state == STATE_LANDED or state == STATE_CRASHED then
|
|
-- Draw terrain
|
|
renderer.rect(0, game.vars.terrain_y, game.width(), game.height() - game.vars.terrain_y, true, true)
|
|
|
|
-- Draw landing zone (outline)
|
|
renderer.rect(game.vars.landing_zone_x, game.vars.terrain_y - 2, game.vars.landing_zone_w, 2, true, true)
|
|
|
|
-- Draw lander (triangle)
|
|
local lander_w = 8
|
|
local lander_h = 6
|
|
renderer.line(game.vars.lander_x - lander_w / 2, game.vars.lander_y + lander_h,
|
|
game.vars.lander_x, game.vars.lander_y, true, 1)
|
|
renderer.line(game.vars.lander_x, game.vars.lander_y,
|
|
game.vars.lander_x + lander_w / 2, game.vars.lander_y + lander_h, true, 1)
|
|
renderer.line(game.vars.lander_x - lander_w / 2, game.vars.lander_y + lander_h,
|
|
game.vars.lander_x + lander_w / 2, game.vars.lander_y + lander_h, true, 1)
|
|
|
|
-- Draw thrust flame
|
|
if game.vars.thrusting then
|
|
renderer.line(game.vars.lander_x - 2, game.vars.lander_y + lander_h,
|
|
game.vars.lander_x - 1, game.vars.lander_y + lander_h + 3, true, 1)
|
|
renderer.line(game.vars.lander_x + 2, game.vars.lander_y + lander_h,
|
|
game.vars.lander_x + 1, game.vars.lander_y + lander_h + 3, true, 1)
|
|
end
|
|
|
|
-- Draw stats
|
|
renderer.text(5, 5, "Fuel: " .. tostring(math.floor(game.vars.fuel)), true)
|
|
renderer.text(5, 15, "Speed: " .. tostring(math.floor(game.vars.lander_vel_y * 10)), true)
|
|
|
|
if state == STATE_LANDED then
|
|
renderer.text(game.width() / 2 - 40, game.height() / 2 - 20, "LANDED!", true)
|
|
renderer.text(game.width() / 2 - 30, game.height() / 2, "Score: " .. tostring(game.vars.score), true)
|
|
renderer.text(game.width() / 2 - 60, game.height() / 2 + 20, "Tap to Menu", true)
|
|
end
|
|
|
|
if state == STATE_CRASHED then
|
|
renderer.text(game.width() / 2 - 40, game.height() / 2 - 20, "CRASHED!", true)
|
|
renderer.text(game.width() / 2 - 60, game.height() / 2 + 20, "Tap to Menu", true)
|
|
end
|
|
end
|
|
end
|
|
|
|
function update_lander()
|
|
-- Apply gravity
|
|
game.vars.lander_vel_y = game.vars.lander_vel_y + GRAVITY
|
|
|
|
-- Apply thrust
|
|
if game.vars.thrusting then
|
|
game.vars.lander_vel_y = game.vars.lander_vel_y - THRUST_POWER
|
|
end
|
|
|
|
-- Update position
|
|
game.vars.lander_y = game.vars.lander_y + game.vars.lander_vel_y
|
|
end
|
|
|
|
function check_landing()
|
|
-- Check if lander reached terrain
|
|
if game.vars.lander_y + 6 >= game.vars.terrain_y then
|
|
local lander_left = game.vars.lander_x - 4
|
|
local lander_right = game.vars.lander_x + 4
|
|
local zone_left = game.vars.landing_zone_x
|
|
local zone_right = game.vars.landing_zone_x + game.vars.landing_zone_w
|
|
|
|
-- Check if in landing zone
|
|
if lander_left >= zone_left and lander_right <= zone_right then
|
|
-- Check landing speed
|
|
if game.vars.lander_vel_y <= SAFE_LANDING_SPEED then
|
|
game.vars.state = STATE_LANDED
|
|
game.vars.score = 100 + math.floor(game.vars.fuel)
|
|
else
|
|
game.vars.state = STATE_CRASHED
|
|
end
|
|
else
|
|
game.vars.state = STATE_CRASHED
|
|
end
|
|
end
|
|
end
|
|
|
|
function reset_game()
|
|
game.vars.lander_x = game.width() / 2
|
|
game.vars.lander_y = 10
|
|
game.vars.lander_vel_y = 0
|
|
game.vars.fuel = MAX_FUEL
|
|
game.vars.thrusting = false
|
|
game.vars.score = 0
|
|
end
|