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:
204
games/lua_examples/pong.lua
Normal file
204
games/lua_examples/pong.lua
Normal file
@@ -0,0 +1,204 @@
|
||||
-- NAME: Pong
|
||||
-- DESC: Classic two-player Pong game
|
||||
|
||||
-- Game states
|
||||
local STATE_MENU = 0
|
||||
local STATE_PLAYING = 1
|
||||
local STATE_GAME_OVER = 2
|
||||
|
||||
-- Game constants
|
||||
local PADDLE_WIDTH = 8
|
||||
local PADDLE_HEIGHT = 40
|
||||
local BALL_RADIUS = 5
|
||||
local MAX_SCORE = 5
|
||||
|
||||
-- Initialize game
|
||||
function init()
|
||||
game.vars.state = STATE_MENU
|
||||
game.vars.frame_count = 0
|
||||
|
||||
-- Left paddle (player 1)
|
||||
game.vars.paddle_left_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)
|
||||
game.vars.paddle_left_score = 0
|
||||
|
||||
-- Right paddle (player 2)
|
||||
game.vars.paddle_right_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)
|
||||
game.vars.paddle_right_score = 0
|
||||
|
||||
-- Ball
|
||||
game.vars.ball_x = game.width() / 2
|
||||
game.vars.ball_y = game.height() / 2
|
||||
game.vars.ball_vel_x = 3
|
||||
game.vars.ball_vel_y = 2
|
||||
|
||||
-- Enable continuous frame updates for smooth animation
|
||||
game.set_frame_updates(true)
|
||||
|
||||
print("Pong initialized")
|
||||
end
|
||||
|
||||
-- Update game logic
|
||||
function update(event)
|
||||
local state = game.vars.state
|
||||
|
||||
-- State: MENU
|
||||
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
|
||||
|
||||
-- State: PLAYING
|
||||
elseif state == STATE_PLAYING then
|
||||
-- Handle paddle input via touch
|
||||
if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.TOUCH_MOVE then
|
||||
-- Left side touch moves left paddle, right side touch moves right paddle
|
||||
if event.x < game.width() / 2 then
|
||||
-- Move left paddle (constrain within bounds)
|
||||
game.vars.paddle_left_y = math.max(0, math.min(game.height() - PADDLE_HEIGHT, event.y - PADDLE_HEIGHT / 2))
|
||||
else
|
||||
-- Move right paddle (constrain within bounds)
|
||||
game.vars.paddle_right_y = math.max(0, math.min(game.height() - PADDLE_HEIGHT, event.y - PADDLE_HEIGHT / 2))
|
||||
end
|
||||
end
|
||||
|
||||
-- Update physics on frame tick
|
||||
if event.type == INPUT.FRAME_TICK then
|
||||
update_ball()
|
||||
|
||||
-- Check win condition
|
||||
if game.vars.paddle_left_score >= MAX_SCORE or game.vars.paddle_right_score >= MAX_SCORE then
|
||||
game.vars.state = STATE_GAME_OVER
|
||||
end
|
||||
|
||||
return true -- Always redraw when playing
|
||||
end
|
||||
|
||||
-- State: GAME_OVER
|
||||
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
|
||||
|
||||
-- Draw game
|
||||
function draw()
|
||||
renderer.clear(false) -- Black background
|
||||
|
||||
local state = game.vars.state
|
||||
|
||||
-- Draw: MENU
|
||||
if state == STATE_MENU then
|
||||
renderer.text(game.width() / 2 - 15, game.height() / 2 - 30, "PONG", true)
|
||||
renderer.text(game.width() / 2 - 50, game.height() / 2, "Tap to Start", true)
|
||||
renderer.text(game.width() / 2 - 70, game.height() / 2 + 20, "First to " .. tostring(MAX_SCORE), true)
|
||||
|
||||
-- Draw: PLAYING
|
||||
elseif state == STATE_PLAYING then
|
||||
-- Draw center line
|
||||
for y = 0, game.height(), 5 do
|
||||
renderer.pixel(game.width() / 2, y, true)
|
||||
end
|
||||
|
||||
-- Draw paddles
|
||||
renderer.rect(10, game.vars.paddle_left_y, PADDLE_WIDTH, PADDLE_HEIGHT, true, true)
|
||||
renderer.rect(game.width() - 10 - PADDLE_WIDTH, game.vars.paddle_right_y, PADDLE_WIDTH, PADDLE_HEIGHT, true, true)
|
||||
|
||||
-- Draw ball
|
||||
renderer.circle(game.vars.ball_x, game.vars.ball_y, BALL_RADIUS, true, true)
|
||||
|
||||
-- Draw scores
|
||||
local left_score_text = tostring(game.vars.paddle_left_score)
|
||||
local right_score_text = tostring(game.vars.paddle_right_score)
|
||||
renderer.text(game.width() / 2 - 30, 5, left_score_text, true)
|
||||
renderer.text(game.width() / 2 + 20, 5, right_score_text, true)
|
||||
|
||||
-- Draw: GAME_OVER
|
||||
elseif state == STATE_GAME_OVER then
|
||||
renderer.text(game.width() / 2 - 40, game.height() / 2 - 30, "GAME OVER", true)
|
||||
|
||||
local winner = "Player 1 Wins!"
|
||||
if game.vars.paddle_right_score > game.vars.paddle_left_score then
|
||||
winner = "Player 2 Wins!"
|
||||
end
|
||||
renderer.text(game.width() / 2 - 50, game.height() / 2, winner, true)
|
||||
|
||||
local final_text = game.vars.paddle_left_score .. " - " .. game.vars.paddle_right_score
|
||||
renderer.text(game.width() / 2 - 25, game.height() / 2 + 20, final_text, true)
|
||||
|
||||
renderer.text(game.width() / 2 - 60, game.height() / 2 + 40, "Tap to Menu", true)
|
||||
end
|
||||
end
|
||||
|
||||
-- Helper: Update ball physics
|
||||
function update_ball()
|
||||
-- Move ball
|
||||
game.vars.ball_x = game.vars.ball_x + game.vars.ball_vel_x
|
||||
game.vars.ball_y = game.vars.ball_y + game.vars.ball_vel_y
|
||||
|
||||
-- Bounce off top/bottom
|
||||
if game.vars.ball_y - BALL_RADIUS < 0 or game.vars.ball_y + BALL_RADIUS > game.height() then
|
||||
game.vars.ball_vel_y = -game.vars.ball_vel_y
|
||||
game.vars.ball_y = math.max(BALL_RADIUS, math.min(game.height() - BALL_RADIUS, game.vars.ball_y))
|
||||
end
|
||||
|
||||
-- Check left paddle collision
|
||||
if game.vars.ball_x - BALL_RADIUS < 10 + PADDLE_WIDTH then
|
||||
if game.vars.ball_y > game.vars.paddle_left_y and game.vars.ball_y < game.vars.paddle_left_y + PADDLE_HEIGHT then
|
||||
if game.vars.ball_vel_x < 0 then
|
||||
game.vars.ball_vel_x = -game.vars.ball_vel_x
|
||||
|
||||
-- Add spin based on where ball hits paddle
|
||||
local hit_pos = (game.vars.ball_y - game.vars.paddle_left_y) / PADDLE_HEIGHT
|
||||
game.vars.ball_vel_y = (hit_pos - 0.5) * 6
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check right paddle collision
|
||||
if game.vars.ball_x + BALL_RADIUS > game.width() - 10 - PADDLE_WIDTH then
|
||||
if game.vars.ball_y > game.vars.paddle_right_y and game.vars.ball_y < game.vars.paddle_right_y + PADDLE_HEIGHT then
|
||||
if game.vars.ball_vel_x > 0 then
|
||||
game.vars.ball_vel_x = -game.vars.ball_vel_x
|
||||
|
||||
-- Add spin based on where ball hits paddle
|
||||
local hit_pos = (game.vars.ball_y - game.vars.paddle_right_y) / PADDLE_HEIGHT
|
||||
game.vars.ball_vel_y = (hit_pos - 0.5) * 6
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Score on left side miss
|
||||
if game.vars.ball_x < 0 then
|
||||
game.vars.paddle_right_score = game.vars.paddle_right_score + 1
|
||||
reset_ball()
|
||||
end
|
||||
|
||||
-- Score on right side miss
|
||||
if game.vars.ball_x > game.width() then
|
||||
game.vars.paddle_left_score = game.vars.paddle_left_score + 1
|
||||
reset_ball()
|
||||
end
|
||||
end
|
||||
|
||||
-- Helper: Reset ball to center
|
||||
function reset_ball()
|
||||
game.vars.ball_x = game.width() / 2
|
||||
game.vars.ball_y = game.height() / 2
|
||||
game.vars.ball_vel_x = 3 * (math.random() > 0.5 and 1 or -1)
|
||||
game.vars.ball_vel_y = 2 * (math.random() > 0.5 and 1 or -1)
|
||||
end
|
||||
|
||||
-- Helper: Reset game
|
||||
function reset_game()
|
||||
game.vars.paddle_left_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)
|
||||
game.vars.paddle_left_score = 0
|
||||
game.vars.paddle_right_y = (game.height() / 2) - (PADDLE_HEIGHT / 2)
|
||||
game.vars.paddle_right_score = 0
|
||||
reset_ball()
|
||||
end
|
||||
Reference in New Issue
Block a user