Files
basic1/games/lua_examples/flappy_bird.lua
T
Adolfo Reyna b26f3bf775 Update all remaining games to use text_scaled with scale=2
Updated games:
- pong.lua: All text now uses text_scaled with scale=2
- air_hockey.lua: All text now uses text_scaled with scale=2
- asteroids.lua: All text now uses text_scaled with scale=2
- ball.lua: All text now uses text_scaled with scale=2
- breakout.lua: All text now uses text_scaled with scale=2
- counter.lua: All text now uses text_scaled with scale=2
- flappy_bird.lua: All text now uses text_scaled with scale=2
- lunar_lander.lua: All text now uses text_scaled with scale=2
- snake.lua: All text now uses text_scaled with scale=2
- tetris.lua: All text now uses text_scaled with scale=2

All 14 games now have consistent 2x text scaling for better readability.
2026-02-12 21:33:00 -05:00

169 lines
5.1 KiB
Lua

-- NAME: Flappy Bird
-- DESC: Tap to flap, avoid pipes
-- Game states
local STATE_MENU = 0
local STATE_PLAYING = 1
local STATE_GAME_OVER = 2
-- Game constants
local BIRD_SIZE = 8
local BIRD_GRAVITY = 0.3
local BIRD_FLAP_POWER = -7
local PIPE_WIDTH = 20
local PIPE_GAP = 50
local PIPE_SPEED = 3
local SPAWN_RATE = 80 -- Frames between pipe spawns
function init()
game.vars.state = STATE_MENU
game.vars.score = 0
game.vars.frame_count = 0
-- Bird
game.vars.bird_y = game.height() / 2
game.vars.bird_vel = 0
-- Pipes (array of {x, gap_y})
game.vars.pipes = {}
game.vars.last_pipe_frame = 0
-- Enable continuous updates
game.set_frame_updates(true)
print("Flappy Bird 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 flap input
if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.BUTTON_0 or event.type == INPUT.BUTTON_1 then
game.vars.bird_vel = BIRD_FLAP_POWER
end
-- Update physics on frame tick
if event.type == INPUT.FRAME_TICK then
update_bird()
update_pipes()
check_collisions()
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_scaled(game.width(, 2) / 2 - 40, game.height() / 2 - 30, "FLAPPY BIRD", true)
renderer.text_scaled(game.width(, 2) / 2 - 50, game.height() / 2, "Tap to Start", true)
elseif state == STATE_PLAYING then
-- Draw bird (convert to integer)
renderer.circle(20, math.floor(game.vars.bird_y + 0.5), BIRD_SIZE, true, true)
-- Draw pipes
for i = 1, #game.vars.pipes do
local pipe = game.vars.pipes[i]
-- Top pipe
renderer.rect(pipe.x, 0, PIPE_WIDTH, pipe.gap_y, true, true)
-- Bottom pipe
local bottom_start = pipe.gap_y + PIPE_GAP
renderer.rect(pipe.x, bottom_start, PIPE_WIDTH, game.height() - bottom_start, true, true)
end
-- Draw score
renderer.text_scaled(10, 10, "Score: " .. tostring(game.vars.score, 2), true)
elseif state == STATE_GAME_OVER then
renderer.text_scaled(game.width(, 2) / 2 - 40, game.height() / 2 - 30, "GAME OVER", true)
renderer.text_scaled(game.width(, 2) / 2 - 30, game.height() / 2, "Score: " .. tostring(game.vars.score), true)
renderer.text_scaled(game.width(, 2) / 2 - 60, game.height() / 2 + 20, "Tap to Restart", true)
end
end
function update_bird()
-- Apply gravity
game.vars.bird_vel = game.vars.bird_vel + BIRD_GRAVITY
game.vars.bird_y = game.vars.bird_y + game.vars.bird_vel
-- Clamp to screen (game over if hit top/bottom)
if game.vars.bird_y - BIRD_SIZE < 0 or game.vars.bird_y + BIRD_SIZE > game.height() then
game.vars.state = STATE_GAME_OVER
end
end
function update_pipes()
game.vars.frame_count = game.vars.frame_count + 1
-- Spawn new pipe
if game.vars.frame_count - game.vars.last_pipe_frame >= SPAWN_RATE then
local gap_y = math.random(30, game.height() - PIPE_GAP - 30)
table.insert(game.vars.pipes, {x = game.width(), gap_y = gap_y})
game.vars.last_pipe_frame = game.vars.frame_count
end
-- Move and remove off-screen pipes
for i = #game.vars.pipes, 1, -1 do
local pipe = game.vars.pipes[i]
pipe.x = pipe.x - PIPE_SPEED
-- Score when pipe passes bird
if pipe.x == 20 then
game.vars.score = game.vars.score + 1
end
-- Remove if off-screen
if pipe.x < -PIPE_WIDTH then
table.remove(game.vars.pipes, i)
end
end
end
function check_collisions()
-- Check collision with pipes
for i = 1, #game.vars.pipes do
local pipe = game.vars.pipes[i]
-- Bird hitbox: circle at (20, bird_y) with radius BIRD_SIZE
-- Check if within pipe's X range
if 20 + BIRD_SIZE > pipe.x and 20 - BIRD_SIZE < pipe.x + PIPE_WIDTH then
-- Check Y collision
if game.vars.bird_y - BIRD_SIZE < pipe.gap_y or
game.vars.bird_y + BIRD_SIZE > pipe.gap_y + PIPE_GAP then
game.vars.state = STATE_GAME_OVER
end
end
end
end
function reset_game()
game.vars.score = 0
game.vars.bird_y = game.height() / 2
game.vars.bird_vel = 0
game.vars.pipes = {}
game.vars.frame_count = 0
game.vars.last_pipe_frame = 0
end