lua_bindings.cpp: - Added new lua_renderer_text_scaled() function - Wraps renderer->draw_string_scaled() with proper scale support - Registered as renderer.text_scaled(x, y, text, on, scale) - Scale parameter defaults to 1 if omitted Updated all 4 games to use text_scaled(): - simon_says.lua: All text now uses text_scaled with scale=2 - tic_tac_toe.lua: All text now uses text_scaled with scale=2 - memory_match.lua: All text now uses text_scaled with scale=2 - 2048.lua: All text now uses text_scaled with scale=2 This properly uses the C++ renderer's scaled text rendering instead of workarounds in Lua, providing better performance and consistency.
399 lines
11 KiB
Lua
399 lines
11 KiB
Lua
-- NAME: 2048
|
|
-- DESC: Merge tiles to reach 2048
|
|
|
|
-- Game states
|
|
local STATE_MENU = 0
|
|
local STATE_PLAYING = 1
|
|
local STATE_GAME_OVER = 2
|
|
local STATE_WIN = 3
|
|
|
|
-- Game constants
|
|
local GRID_SIZE = 4
|
|
|
|
-- Calculate tile size based on screen size
|
|
local function get_tile_size()
|
|
-- Use smallest dimension for square grid
|
|
local min_dim = math.min(game.width(), game.height())
|
|
local padding = math.floor(min_dim / 8)
|
|
local available = min_dim - (padding * 2)
|
|
local tile_size = math.floor(available / GRID_SIZE)
|
|
return tile_size
|
|
end
|
|
|
|
local function get_grid_start_x()
|
|
local tile_size = get_tile_size()
|
|
local grid_width = tile_size * GRID_SIZE
|
|
return math.floor((game.width() - grid_width) / 2)
|
|
end
|
|
|
|
local function get_grid_start_y()
|
|
local tile_size = get_tile_size()
|
|
local grid_height = tile_size * GRID_SIZE
|
|
return math.floor((game.height() - grid_height) / 2)
|
|
end
|
|
|
|
function init()
|
|
game.vars.state = STATE_MENU
|
|
game.vars.score = 0
|
|
|
|
-- Grid (4x4, 0 = empty)
|
|
game.vars.grid = {}
|
|
for y = 1, GRID_SIZE do
|
|
game.vars.grid[y] = {}
|
|
for x = 1, GRID_SIZE do
|
|
game.vars.grid[y][x] = 0
|
|
end
|
|
end
|
|
|
|
game.vars.moved = false
|
|
game.vars.won = false
|
|
|
|
-- Enable continuous updates
|
|
game.set_frame_updates(true)
|
|
|
|
print("2048 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
|
|
if event.type == INPUT.TOUCH_DOWN then
|
|
-- Determine swipe direction
|
|
local direction = get_swipe_direction(event.x, event.y)
|
|
if direction then
|
|
game.vars.moved = false
|
|
move_tiles(direction)
|
|
|
|
if game.vars.moved then
|
|
spawn_tile()
|
|
|
|
-- Check win/lose
|
|
if has_tile(2048) then
|
|
if not game.vars.won then
|
|
game.vars.state = STATE_WIN
|
|
game.vars.won = true
|
|
end
|
|
end
|
|
|
|
if not can_move() then
|
|
game.vars.state = STATE_GAME_OVER
|
|
end
|
|
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
elseif state == STATE_WIN then
|
|
if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then
|
|
-- Can continue playing or go to menu
|
|
if event.y < game.height() / 2 then
|
|
game.vars.state = STATE_PLAYING
|
|
else
|
|
game.vars.state = STATE_MENU
|
|
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)
|
|
|
|
local state = game.vars.state
|
|
local tile_size = get_tile_size()
|
|
local start_x = get_grid_start_x()
|
|
local start_y = get_grid_start_y()
|
|
|
|
if state == STATE_MENU then
|
|
renderer.text_scaled(game.width() / 2 - 15, game.height() / 2 - 30, "2048", true, 2)
|
|
renderer.text_scaled(game.width() / 2 - 50, game.height() / 2, "Tap to Start", true, 2)
|
|
|
|
elseif state == STATE_PLAYING or state == STATE_WIN or state == STATE_GAME_OVER then
|
|
-- Draw grid
|
|
for y = 1, GRID_SIZE do
|
|
for x = 1, GRID_SIZE do
|
|
local tile_x = start_x + (x - 1) * tile_size
|
|
local tile_y = start_y + (y - 1) * tile_size
|
|
local value = game.vars.grid[y][x]
|
|
|
|
if value == 0 then
|
|
-- Empty tile
|
|
renderer.rect(tile_x, tile_y, tile_size, tile_size, true, false)
|
|
else
|
|
-- Filled tile
|
|
renderer.rect(tile_x, tile_y, tile_size, tile_size, true, true)
|
|
|
|
-- Draw value (simplified)
|
|
local text = tostring(value)
|
|
if string.len(text) <= 2 then
|
|
renderer.text_scaled(tile_x + 2, tile_y + 2, text, false, 2)
|
|
else
|
|
renderer.text_scaled(tile_x + 1, tile_y + 2, text, false, 2)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Draw score
|
|
renderer.text_scaled(10, 10, "Score: " .. tostring(game.vars.score), true, 2)
|
|
|
|
if state == STATE_WIN then
|
|
renderer.text_scaled(game.width() / 2 - 30, game.height() / 2 - 20, "YOU WIN!", true, 2)
|
|
renderer.text_scaled(game.width() / 2 - 60, game.height() / 2, "Tap up: Continue", true, 2)
|
|
renderer.text_scaled(game.width() / 2 - 50, game.height() / 2 + 15, "Tap down: Menu", true, 2)
|
|
end
|
|
|
|
if state == STATE_GAME_OVER then
|
|
renderer.text_scaled(game.width() / 2 - 40, game.height() / 2, "GAME OVER", true, 2)
|
|
renderer.text_scaled(game.width() / 2 - 30, game.height() / 2 + 15, "Score: " .. tostring(game.vars.score), true, 2)
|
|
renderer.text_scaled(game.width() / 2 - 60, game.height() / 2 + 30, "Tap to Menu", true, 2)
|
|
end
|
|
end
|
|
end
|
|
|
|
function get_swipe_direction(x, y)
|
|
-- Simple tap-based direction (could be enhanced with swipe tracking)
|
|
local mid_x = game.width() / 2
|
|
local mid_y = game.height() / 2
|
|
|
|
local dx = x - mid_x
|
|
local dy = y - mid_y
|
|
|
|
if math.abs(dx) > math.abs(dy) then
|
|
if dx > 0 then return "right" end
|
|
return "left"
|
|
else
|
|
if dy > 0 then return "down" end
|
|
return "up"
|
|
end
|
|
end
|
|
|
|
function move_tiles(direction)
|
|
local old_grid = {}
|
|
for y = 1, GRID_SIZE do
|
|
old_grid[y] = {}
|
|
for x = 1, GRID_SIZE do
|
|
old_grid[y][x] = game.vars.grid[y][x]
|
|
end
|
|
end
|
|
|
|
if direction == "left" then
|
|
move_left()
|
|
elseif direction == "right" then
|
|
move_right()
|
|
elseif direction == "up" then
|
|
move_up()
|
|
elseif direction == "down" then
|
|
move_down()
|
|
end
|
|
|
|
-- Check if grid changed
|
|
for y = 1, GRID_SIZE do
|
|
for x = 1, GRID_SIZE do
|
|
if old_grid[y][x] ~= game.vars.grid[y][x] then
|
|
game.vars.moved = true
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function move_left()
|
|
for y = 1, GRID_SIZE do
|
|
-- Compact
|
|
local row = {}
|
|
for x = 1, GRID_SIZE do
|
|
if game.vars.grid[y][x] ~= 0 then
|
|
table.insert(row, game.vars.grid[y][x])
|
|
end
|
|
end
|
|
|
|
-- Merge
|
|
local i = 1
|
|
while i < #row do
|
|
if row[i] == row[i + 1] then
|
|
row[i] = row[i] * 2
|
|
game.vars.score = game.vars.score + row[i]
|
|
table.remove(row, i + 1)
|
|
end
|
|
i = i + 1
|
|
end
|
|
|
|
-- Fill back
|
|
for x = 1, GRID_SIZE do
|
|
if x <= #row then
|
|
game.vars.grid[y][x] = row[x]
|
|
else
|
|
game.vars.grid[y][x] = 0
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function move_right()
|
|
for y = 1, GRID_SIZE do
|
|
local row = {}
|
|
for x = GRID_SIZE, 1, -1 do
|
|
if game.vars.grid[y][x] ~= 0 then
|
|
table.insert(row, game.vars.grid[y][x])
|
|
end
|
|
end
|
|
|
|
local i = 1
|
|
while i < #row do
|
|
if row[i] == row[i + 1] then
|
|
row[i] = row[i] * 2
|
|
game.vars.score = game.vars.score + row[i]
|
|
table.remove(row, i + 1)
|
|
end
|
|
i = i + 1
|
|
end
|
|
|
|
for x = GRID_SIZE, 1, -1 do
|
|
if GRID_SIZE - x + 1 <= #row then
|
|
game.vars.grid[y][x] = row[GRID_SIZE - x + 1]
|
|
else
|
|
game.vars.grid[y][x] = 0
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function move_up()
|
|
for x = 1, GRID_SIZE do
|
|
local col = {}
|
|
for y = 1, GRID_SIZE do
|
|
if game.vars.grid[y][x] ~= 0 then
|
|
table.insert(col, game.vars.grid[y][x])
|
|
end
|
|
end
|
|
|
|
local i = 1
|
|
while i < #col do
|
|
if col[i] == col[i + 1] then
|
|
col[i] = col[i] * 2
|
|
game.vars.score = game.vars.score + col[i]
|
|
table.remove(col, i + 1)
|
|
end
|
|
i = i + 1
|
|
end
|
|
|
|
for y = 1, GRID_SIZE do
|
|
if y <= #col then
|
|
game.vars.grid[y][x] = col[y]
|
|
else
|
|
game.vars.grid[y][x] = 0
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function move_down()
|
|
for x = 1, GRID_SIZE do
|
|
local col = {}
|
|
for y = GRID_SIZE, 1, -1 do
|
|
if game.vars.grid[y][x] ~= 0 then
|
|
table.insert(col, game.vars.grid[y][x])
|
|
end
|
|
end
|
|
|
|
local i = 1
|
|
while i < #col do
|
|
if col[i] == col[i + 1] then
|
|
col[i] = col[i] * 2
|
|
game.vars.score = game.vars.score + col[i]
|
|
table.remove(col, i + 1)
|
|
end
|
|
i = i + 1
|
|
end
|
|
|
|
for y = GRID_SIZE, 1, -1 do
|
|
if GRID_SIZE - y + 1 <= #col then
|
|
game.vars.grid[y][x] = col[GRID_SIZE - y + 1]
|
|
else
|
|
game.vars.grid[y][x] = 0
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function spawn_tile()
|
|
local empty = {}
|
|
for y = 1, GRID_SIZE do
|
|
for x = 1, GRID_SIZE do
|
|
if game.vars.grid[y][x] == 0 then
|
|
table.insert(empty, {x = x, y = y})
|
|
end
|
|
end
|
|
end
|
|
|
|
if #empty > 0 then
|
|
local pos = empty[math.random(1, #empty)]
|
|
game.vars.grid[pos.y][pos.x] = math.random() > 0.9 and 4 or 2
|
|
end
|
|
end
|
|
|
|
function has_tile(value)
|
|
for y = 1, GRID_SIZE do
|
|
for x = 1, GRID_SIZE do
|
|
if game.vars.grid[y][x] == value then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function can_move()
|
|
-- Check if any empty tiles
|
|
for y = 1, GRID_SIZE do
|
|
for x = 1, GRID_SIZE do
|
|
if game.vars.grid[y][x] == 0 then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Check if any merges possible
|
|
for y = 1, GRID_SIZE do
|
|
for x = 1, GRID_SIZE do
|
|
local val = game.vars.grid[y][x]
|
|
if x < GRID_SIZE and game.vars.grid[y][x + 1] == val then return true end
|
|
if y < GRID_SIZE and game.vars.grid[y + 1][x] == val then return true end
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function reset_game()
|
|
game.vars.score = 0
|
|
game.vars.won = false
|
|
|
|
for y = 1, GRID_SIZE do
|
|
for x = 1, GRID_SIZE do
|
|
game.vars.grid[y][x] = 0
|
|
end
|
|
end
|
|
|
|
spawn_tile()
|
|
spawn_tile()
|
|
end
|