Files
basic1/games/lua_examples/simon_says.lua
T
Adolfo Reyna 62716c7dc4 Scale Simon Says and Tic-Tac-Toe to fill screen
simon_says.lua:
- Removed hardcoded button positions
- Added get_buttons() function that calculates button size and position based on screen dimensions
- Buttons now use 10% screen padding and scale to fill available width
- 2x2 grid automatically scales with screen size

tic_tac_toe.lua:
- Replaced hardcoded CELL_SIZE with dynamic calculation
- Added get_cell_size() to compute size based on screen width
- Added get_grid_start_x/y() to center grid both horizontally and vertically
- Grid now scales to fill available space while maintaining 3x3 layout
- All cell positions updated to use dynamic functions

Both games now work on any screen size and scale proportionally.
2026-02-12 21:06:54 -05:00

200 lines
6.6 KiB
Lua

-- NAME: Simon Says
-- DESC: Repeat the color sequence
-- Game states
local STATE_MENU = 0
local STATE_PLAYING = 1
local STATE_SHOWING = 2
local STATE_GAME_OVER = 3
-- Game constants
local SHOW_DURATION = 30 -- Frames to show each button
local WAIT_DURATION = 20 -- Frames between shows
-- Button positions (calculated dynamically based on screen size)
local function get_buttons()
local padding = math.floor(game.width() / 10)
local button_size = math.floor((game.width() - padding * 3) / 2)
local spacing = padding
return {
{x = padding, y = padding, size = button_size, color = 1}, -- Top-left
{x = padding + button_size + spacing, y = padding, size = button_size, color = 2}, -- Top-right
{x = padding, y = padding + button_size + spacing, size = button_size, color = 3}, -- Bottom-left
{x = padding + button_size + spacing, y = padding + button_size + spacing, size = button_size, color = 4} -- Bottom-right
}
end
function init()
game.vars.state = STATE_MENU
game.vars.score = 0
-- Sequence of button presses
game.vars.sequence = {}
game.vars.player_seq = {}
-- Animation state
game.vars.showing_idx = 0
game.vars.show_frame = 0
game.vars.show_button = nil
-- Input state
game.vars.waiting_for_input = false
game.vars.input_idx = 0
-- Enable continuous updates
game.set_frame_updates(true)
print("Simon Says 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
-- Start showing sequence
if event.type == INPUT.FRAME_TICK then
game.vars.show_frame = game.vars.show_frame + 1
return true
end
return false
elseif state == STATE_SHOWING then
-- Animate sequence
if event.type == INPUT.FRAME_TICK then
game.vars.show_frame = game.vars.show_frame + 1
-- Move to next button in sequence
if game.vars.show_frame > SHOW_DURATION + WAIT_DURATION then
game.vars.showing_idx = game.vars.showing_idx + 1
game.vars.show_frame = 0
game.vars.show_button = nil
-- Done showing sequence, wait for player input
if game.vars.showing_idx > #game.vars.sequence then
game.vars.state = STATE_PLAYING
game.vars.waiting_for_input = true
game.vars.input_idx = 0
end
else
-- Highlight button during show duration
if game.vars.show_frame <= SHOW_DURATION then
game.vars.show_button = game.vars.sequence[game.vars.showing_idx]
else
game.vars.show_button = nil
end
end
return true
end
return false
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
-- Handle player input
if game.vars.waiting_for_input and event.type == INPUT.TOUCH_DOWN then
local button = get_button_at(event.x, event.y)
if button then
game.vars.player_seq[#game.vars.player_seq + 1] = button
game.vars.input_idx = game.vars.input_idx + 1
-- Check if correct
if game.vars.sequence[game.vars.input_idx] ~= button then
-- Wrong! Game over
game.vars.state = STATE_GAME_OVER
return true
end
-- Check if completed sequence
if game.vars.input_idx == #game.vars.sequence then
-- Advance to next round
game.vars.sequence[#game.vars.sequence + 1] = math.random(1, 4)
game.vars.player_seq = {}
game.vars.waiting_for_input = false
game.vars.showing_idx = 0
game.vars.show_frame = 0
game.vars.show_button = nil
game.vars.state = STATE_SHOWING
game.vars.score = game.vars.score + 1
return true
end
return true
end
end
return false
end
function draw()
renderer.clear(false) -- Black background
local state = game.vars.state
local buttons = get_buttons()
if state == STATE_MENU then
renderer.text(game.width() / 2 - 40, game.height() / 2 - 40, "SIMON SAYS", true)
renderer.text(game.width() / 2 - 50, game.height() / 2 - 10, "Repeat the sequence", true)
renderer.text(game.width() / 2 - 50, game.height() / 2 + 20, "Tap to Start", true)
else
-- Draw buttons with highlight
for i = 1, 4 do
local btn = buttons[i]
local filled = (game.vars.show_button == i)
renderer.rect(btn.x, btn.y, btn.size, btn.size, true, filled)
end
-- Draw score
renderer.text(10, 10, "Level: " .. tostring(game.vars.score + 1), true)
if state == STATE_PLAYING and game.vars.waiting_for_input then
renderer.text(game.width() / 2 - 40, game.height() - 20, "Your turn!", true)
end
if state == STATE_GAME_OVER then
renderer.text(game.width() / 2 - 40, game.height() / 2 - 20, "GAME OVER", true)
renderer.text(game.width() / 2 - 30, game.height() / 2, "Level: " .. tostring(game.vars.score + 1), true)
renderer.text(game.width() / 2 - 60, game.height() / 2 + 20, "Tap to Restart", true)
end
end
end
function get_button_at(x, y)
local buttons = get_buttons()
for i = 1, 4 do
local btn = buttons[i]
if x >= btn.x and x < btn.x + btn.size and
y >= btn.y and y < btn.y + btn.size then
return i
end
end
return nil
end
function reset_game()
game.vars.score = 0
game.vars.sequence = {math.random(1, 4)}
game.vars.player_seq = {}
game.vars.showing_idx = 0
game.vars.show_frame = 0
game.vars.show_button = nil
game.vars.waiting_for_input = false
game.vars.input_idx = 0
game.vars.state = STATE_SHOWING
end