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:
198
games/lua_examples/memory_match.lua
Normal file
198
games/lua_examples/memory_match.lua
Normal file
@@ -0,0 +1,198 @@
|
||||
-- NAME: Memory Match
|
||||
-- DESC: Find matching pairs
|
||||
|
||||
-- Game states
|
||||
local STATE_MENU = 0
|
||||
local STATE_PLAYING = 1
|
||||
local STATE_GAME_OVER = 2
|
||||
|
||||
-- Game constants
|
||||
local GRID_COLS = 4
|
||||
local GRID_ROWS = 4
|
||||
local CARD_SIZE = 28
|
||||
local CARD_SPACING = 4
|
||||
local FLIP_DURATION = 15 -- Frames to show flip animation
|
||||
|
||||
function init()
|
||||
game.vars.state = STATE_MENU
|
||||
game.vars.score = 0
|
||||
game.vars.moves = 0
|
||||
|
||||
-- Card grid
|
||||
game.vars.cards = {} -- {id, face_up, matched}
|
||||
game.vars.selected = {} -- Indices of selected cards
|
||||
game.vars.flip_frame = 0
|
||||
game.vars.waiting = false -- Waiting to flip back incorrect pair
|
||||
|
||||
-- Enable continuous updates
|
||||
game.set_frame_updates(true)
|
||||
|
||||
print("Memory Match 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 card selection
|
||||
if event.type == INPUT.TOUCH_DOWN and not game.vars.waiting then
|
||||
local card_idx = get_card_at(event.x, event.y)
|
||||
if card_idx and not game.vars.cards[card_idx].matched and not game.vars.cards[card_idx].face_up then
|
||||
-- Select card
|
||||
game.vars.cards[card_idx].face_up = true
|
||||
table.insert(game.vars.selected, card_idx)
|
||||
|
||||
if #game.vars.selected == 2 then
|
||||
game.vars.moves = game.vars.moves + 1
|
||||
|
||||
-- Check for match
|
||||
if game.vars.cards[game.vars.selected[1]].id == game.vars.cards[game.vars.selected[2]].id then
|
||||
-- Match!
|
||||
game.vars.cards[game.vars.selected[1]].matched = true
|
||||
game.vars.cards[game.vars.selected[2]].matched = true
|
||||
game.vars.score = game.vars.score + 1
|
||||
game.vars.selected = {}
|
||||
|
||||
-- Check win
|
||||
if game.vars.score == (GRID_COLS * GRID_ROWS) / 2 then
|
||||
game.vars.state = STATE_GAME_OVER
|
||||
end
|
||||
else
|
||||
-- No match, wait then flip back
|
||||
game.vars.waiting = true
|
||||
game.vars.flip_frame = 0
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Handle flip-back animation
|
||||
if game.vars.waiting and event.type == INPUT.FRAME_TICK then
|
||||
game.vars.flip_frame = game.vars.flip_frame + 1
|
||||
|
||||
if game.vars.flip_frame >= FLIP_DURATION then
|
||||
-- Flip cards back
|
||||
game.vars.cards[game.vars.selected[1]].face_up = false
|
||||
game.vars.cards[game.vars.selected[2]].face_up = false
|
||||
game.vars.selected = {}
|
||||
game.vars.waiting = false
|
||||
game.vars.flip_frame = 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 - 40, game.height() / 2 - 40, "MEMORY MATCH", true)
|
||||
renderer.text(game.width() / 2 - 50, game.height() / 2 - 10, "Find all pairs", true)
|
||||
renderer.text(game.width() / 2 - 50, game.height() / 2 + 20, "Tap to Start", true)
|
||||
|
||||
elseif state == STATE_PLAYING or state == STATE_GAME_OVER then
|
||||
-- Draw grid
|
||||
local start_x = (game.width() - (GRID_COLS * (CARD_SIZE + CARD_SPACING))) / 2
|
||||
local start_y = 30
|
||||
|
||||
for row = 0, GRID_ROWS - 1 do
|
||||
for col = 0, GRID_COLS - 1 do
|
||||
local idx = row * GRID_COLS + col + 1
|
||||
local card = game.vars.cards[idx]
|
||||
local x = start_x + col * (CARD_SIZE + CARD_SPACING)
|
||||
local y = start_y + row * (CARD_SIZE + CARD_SPACING)
|
||||
|
||||
if card.face_up or card.matched then
|
||||
-- Show card value
|
||||
renderer.rect(x, y, CARD_SIZE, CARD_SIZE, true, true)
|
||||
local text = tostring(card.id)
|
||||
renderer.text(x + CARD_SIZE / 2 - 2, y + CARD_SIZE / 2 - 2, text, false)
|
||||
else
|
||||
-- Face down (outline)
|
||||
renderer.rect(x, y, CARD_SIZE, CARD_SIZE, true, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Draw stats
|
||||
renderer.text(10, 10, "Pairs: " .. tostring(game.vars.score) .. "/" .. tostring((GRID_COLS * GRID_ROWS) / 2), true)
|
||||
renderer.text(10, 20, "Moves: " .. tostring(game.vars.moves), true)
|
||||
|
||||
if state == STATE_GAME_OVER then
|
||||
renderer.text(game.width() / 2 - 40, 5, "YOU WIN!", true)
|
||||
renderer.text(game.width() / 2 - 50, game.height() - 20, "Tap to Menu", true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function get_card_at(x, y)
|
||||
local start_x = (game.width() - (GRID_COLS * (CARD_SIZE + CARD_SPACING))) / 2
|
||||
local start_y = 30
|
||||
|
||||
for row = 0, GRID_ROWS - 1 do
|
||||
for col = 0, GRID_COLS - 1 do
|
||||
local card_x = start_x + col * (CARD_SIZE + CARD_SPACING)
|
||||
local card_y = start_y + row * (CARD_SIZE + CARD_SPACING)
|
||||
|
||||
if x >= card_x and x < card_x + CARD_SIZE and
|
||||
y >= card_y and y < card_y + CARD_SIZE then
|
||||
return row * GRID_COLS + col + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function reset_game()
|
||||
game.vars.score = 0
|
||||
game.vars.moves = 0
|
||||
game.vars.selected = {}
|
||||
game.vars.flip_frame = 0
|
||||
game.vars.waiting = false
|
||||
|
||||
-- Create shuffled card pairs
|
||||
local card_ids = {}
|
||||
local num_pairs = (GRID_COLS * GRID_ROWS) / 2
|
||||
for i = 1, num_pairs do
|
||||
table.insert(card_ids, i)
|
||||
table.insert(card_ids, i)
|
||||
end
|
||||
|
||||
-- Shuffle
|
||||
for i = #card_ids, 2, -1 do
|
||||
local j = math.random(1, i)
|
||||
card_ids[i], card_ids[j] = card_ids[j], card_ids[i]
|
||||
end
|
||||
|
||||
-- Create card objects
|
||||
game.vars.cards = {}
|
||||
for i = 1, #card_ids do
|
||||
game.vars.cards[i] = {
|
||||
id = card_ids[i],
|
||||
face_up = false,
|
||||
matched = false
|
||||
}
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user