feat: add 6 lua games for basic1 console

- Pong: 2-player paddle and ball game with spin mechanics
- Flappy Bird: gravity physics, obstacle avoidance
- Breakout: paddle control, brick grid, collision detection
- Simon Says: sequence memory, animation timing
- Memory Match: pair matching, flip animations, grid layout
- Tetris: falling blocks, grid system, line clearing
- Asteroids: vector math, rotation, projectiles, enemy spawning

All games follow API conventions with state machines, touch input,
frame-based animation, and persistent game.vars state management.
This commit is contained in:
Adolfo Reyna
2026-02-12 19:18:51 -05:00
parent eacc03a38c
commit 53a2fb046b
7 changed files with 1582 additions and 0 deletions

View File

@@ -0,0 +1,284 @@
-- NAME: Asteroids
-- DESC: Destroy asteroids, avoid collisions
-- Game states
local STATE_MENU = 0
local STATE_PLAYING = 1
local STATE_GAME_OVER = 2
-- Game constants
local SHIP_SPEED = 2
local SHIP_ROTATION_SPEED = 8
local BULLET_SPEED = 5
local ASTEROID_SPAWN_RATE = 120
local ASTEROID_SPEEDS = {1.5, 2, 2.5, 3}
function init()
game.vars.state = STATE_MENU
game.vars.score = 0
game.vars.level = 1
-- Ship
game.vars.ship_x = game.width() / 2
game.vars.ship_y = game.height() / 2
game.vars.ship_angle = 0 -- Radians
game.vars.ship_vel_x = 0
game.vars.ship_vel_y = 0
game.vars.thrusting = false
-- Bullets
game.vars.bullets = {}
game.vars.bullet_cooldown = 0
-- Asteroids
game.vars.asteroids = {}
game.vars.frame_count = 0
-- Enable continuous updates
game.set_frame_updates(true)
print("Asteroids 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 input
if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.TOUCH_MOVE then
if event.x < game.width() / 2 then
-- Left side: rotate counter-clockwise
game.vars.ship_angle = game.vars.ship_angle - SHIP_ROTATION_SPEED * 0.017
else
-- Right side: rotate clockwise
game.vars.ship_angle = game.vars.ship_angle + SHIP_ROTATION_SPEED * 0.017
end
-- Thrust
game.vars.thrusting = true
else
game.vars.thrusting = false
end
-- Update physics on frame tick
if event.type == INPUT.FRAME_TICK then
update_ship()
update_bullets()
update_asteroids()
check_collisions()
-- Spawn asteroids
game.vars.frame_count = game.vars.frame_count + 1
if game.vars.frame_count >= ASTEROID_SPAWN_RATE then
spawn_asteroid(game.width() / 2, game.height() / 2, 3)
game.vars.frame_count = 0
end
return true
end
elseif state == STATE_GAME_OVER 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) -- Black background
local state = game.vars.state
if state == STATE_MENU then
renderer.text(game.width() / 2 - 35, game.height() / 2 - 30, "ASTEROIDS", true)
renderer.text(game.width() / 2 - 50, game.height() / 2, "Tap to Start", true)
elseif state == STATE_PLAYING or state == STATE_GAME_OVER then
-- Draw asteroids
for i = 1, #game.vars.asteroids do
local ast = game.vars.asteroids[i]
renderer.circle(ast.x, ast.y, ast.size, true, false)
end
-- Draw bullets
for i = 1, #game.vars.bullets do
local bullet = game.vars.bullets[i]
renderer.pixel(bullet.x, bullet.y, true)
end
-- Draw ship
local ship_size = 6
local nose_x = game.vars.ship_x + math.cos(game.vars.ship_angle) * ship_size
local nose_y = game.vars.ship_y + math.sin(game.vars.ship_angle) * ship_size
local back_x = game.vars.ship_x - math.cos(game.vars.ship_angle) * (ship_size / 2)
local back_y = game.vars.ship_y - math.sin(game.vars.ship_angle) * (ship_size / 2)
renderer.line(game.vars.ship_x, game.vars.ship_y, nose_x, nose_y, true, 1)
renderer.line(back_x, back_y, nose_x, nose_y, true, 1)
-- Draw thrust indicator
if game.vars.thrusting then
local flame_x = game.vars.ship_x - math.cos(game.vars.ship_angle) * ship_size
local flame_y = game.vars.ship_y - math.sin(game.vars.ship_angle) * ship_size
renderer.line(game.vars.ship_x, game.vars.ship_y, flame_x, flame_y, true, 1)
end
-- Draw score
renderer.text(10, 10, "Score: " .. tostring(game.vars.score), true)
renderer.text(10, 20, "Level: " .. tostring(game.vars.level), true)
if state == STATE_GAME_OVER then
renderer.text(game.width() / 2 - 40, game.height() / 2, "GAME OVER", true)
renderer.text(game.width() / 2 - 50, game.height() / 2 + 20, "Tap to Menu", true)
end
end
end
function update_ship()
if game.vars.thrusting then
game.vars.ship_vel_x = game.vars.ship_vel_x + math.cos(game.vars.ship_angle) * SHIP_SPEED
game.vars.ship_vel_y = game.vars.ship_vel_y + math.sin(game.vars.ship_angle) * SHIP_SPEED
end
-- Friction
game.vars.ship_vel_x = game.vars.ship_vel_x * 0.98
game.vars.ship_vel_y = game.vars.ship_vel_y * 0.98
-- Move ship
game.vars.ship_x = game.vars.ship_x + game.vars.ship_vel_x
game.vars.ship_y = game.vars.ship_y + game.vars.ship_vel_y
-- Wrap around screen
if game.vars.ship_x < 0 then game.vars.ship_x = game.width() end
if game.vars.ship_x > game.width() then game.vars.ship_x = 0 end
if game.vars.ship_y < 0 then game.vars.ship_y = game.height() end
if game.vars.ship_y > game.height() then game.vars.ship_y = 0 end
end
function update_bullets()
-- Update existing bullets
for i = #game.vars.bullets, 1, -1 do
local bullet = game.vars.bullets[i]
bullet.x = bullet.x + bullet.vel_x
bullet.y = bullet.y + bullet.vel_y
-- Remove if off-screen
if bullet.x < 0 or bullet.x > game.width() or bullet.y < 0 or bullet.y > game.height() then
table.remove(game.vars.bullets, i)
end
end
-- Fire bullet
game.vars.bullet_cooldown = math.max(0, game.vars.bullet_cooldown - 1)
if game.vars.thrusting and game.vars.bullet_cooldown == 0 then
local bullet_x = game.vars.ship_x + math.cos(game.vars.ship_angle) * 8
local bullet_y = game.vars.ship_y + math.sin(game.vars.ship_angle) * 8
table.insert(game.vars.bullets, {
x = bullet_x,
y = bullet_y,
vel_x = math.cos(game.vars.ship_angle) * BULLET_SPEED + game.vars.ship_vel_x,
vel_y = math.sin(game.vars.ship_angle) * BULLET_SPEED + game.vars.ship_vel_y
})
game.vars.bullet_cooldown = 5
end
end
function update_asteroids()
for i = 1, #game.vars.asteroids do
local ast = game.vars.asteroids[i]
ast.x = ast.x + ast.vel_x
ast.y = ast.y + ast.vel_y
-- Wrap around screen
if ast.x < -ast.size then ast.x = game.width() + ast.size end
if ast.x > game.width() + ast.size then ast.x = -ast.size end
if ast.y < -ast.size then ast.y = game.height() + ast.size end
if ast.y > game.height() + ast.size then ast.y = -ast.size end
end
end
function check_collisions()
-- Bullet-asteroid collisions
for b = #game.vars.bullets, 1, -1 do
local bullet = game.vars.bullets[b]
for a = #game.vars.asteroids, 1, -1 do
local ast = game.vars.asteroids[a]
local dx = bullet.x - ast.x
local dy = bullet.y - ast.y
local dist = math.sqrt(dx * dx + dy * dy)
if dist < ast.size then
-- Hit!
table.remove(game.vars.bullets, b)
table.remove(game.vars.asteroids, a)
game.vars.score = game.vars.score + (4 - ast.size) * 50
-- Spawn smaller asteroids
if ast.size > 1 then
for _ = 1, 2 do
spawn_asteroid(ast.x, ast.y, ast.size - 1)
end
end
break
end
end
end
-- Ship-asteroid collisions
for i = 1, #game.vars.asteroids do
local ast = game.vars.asteroids[i]
local dx = game.vars.ship_x - ast.x
local dy = game.vars.ship_y - ast.y
local dist = math.sqrt(dx * dx + dy * dy)
if dist < ast.size + 6 then
game.vars.state = STATE_GAME_OVER
end
end
end
function spawn_asteroid(x, y, size)
if size < 1 then return end
local speed = ASTEROID_SPEEDS[size]
local angle = math.random() * math.pi * 2
table.insert(game.vars.asteroids, {
x = x,
y = y,
size = size,
vel_x = math.cos(angle) * speed,
vel_y = math.sin(angle) * speed
})
end
function reset_game()
game.vars.score = 0
game.vars.level = 1
game.vars.ship_x = game.width() / 2
game.vars.ship_y = game.height() / 2
game.vars.ship_angle = 0
game.vars.ship_vel_x = 0
game.vars.ship_vel_y = 0
game.vars.bullets = {}
game.vars.asteroids = {}
game.vars.frame_count = 0
spawn_asteroid(game.width() / 2 - 40, game.height() / 2 - 40, 3)
spawn_asteroid(game.width() / 2 + 40, game.height() / 2 + 40, 3)
end