-- NAME: Asteroids -- DESC: Destroy asteroids, avoid collisions -- Game states local STATE_MENU = 0 local STATE_PLAYING = 1 local STATE_GAME_OVER = 2 -- Game constants local SHIP_SPEED = 2 local SHIP_ROTATION_SPEED = 8 local BULLET_SPEED = 5 local ASTEROID_SPAWN_RATE = 120 local ASTEROID_SPEEDS = {1.5, 2, 2.5, 3} function init() game.vars.state = STATE_MENU game.vars.score = 0 game.vars.level = 1 -- Ship game.vars.ship_x = game.width() / 2 game.vars.ship_y = game.height() / 2 game.vars.ship_angle = 0 -- Radians game.vars.ship_vel_x = 0 game.vars.ship_vel_y = 0 game.vars.thrusting = false -- Bullets game.vars.bullets = {} game.vars.bullet_cooldown = 0 -- Asteroids game.vars.asteroids = {} game.vars.frame_count = 0 -- Enable continuous updates game.set_frame_updates(true) print("Asteroids 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 input if event.type == INPUT.TOUCH_DOWN or event.type == INPUT.TOUCH_MOVE then if event.x < game.width() / 2 then -- Left side: rotate counter-clockwise game.vars.ship_angle = game.vars.ship_angle - SHIP_ROTATION_SPEED * 0.017 else -- Right side: rotate clockwise game.vars.ship_angle = game.vars.ship_angle + SHIP_ROTATION_SPEED * 0.017 end -- Thrust game.vars.thrusting = true else game.vars.thrusting = false end -- Update physics on frame tick if event.type == INPUT.FRAME_TICK then update_ship() update_bullets() update_asteroids() check_collisions() -- Spawn asteroids game.vars.frame_count = game.vars.frame_count + 1 if game.vars.frame_count >= ASTEROID_SPAWN_RATE then spawn_asteroid(game.width() / 2, game.height() / 2, 3) game.vars.frame_count = 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_scaled(game.width() / 2 - 35, game.height() / 2 - 30, "ASTEROIDS", true, 2) renderer.text_scaled(game.width() / 2 - 50, game.height() / 2, "Tap to Start", true, 2) elseif state == STATE_PLAYING or state == STATE_GAME_OVER then -- Draw asteroids (convert to integers) for i = 1, #game.vars.asteroids do local ast = game.vars.asteroids[i] renderer.circle(math.floor(ast.x + 0.5), math.floor(ast.y + 0.5), ast.size, true, false) end -- Draw bullets for i = 1, #game.vars.bullets do local bullet = game.vars.bullets[i] renderer.pixel(bullet.x, bullet.y, true) end -- Draw ship local ship_size = 6 local nose_x = game.vars.ship_x + math.cos(game.vars.ship_angle) * ship_size local nose_y = game.vars.ship_y + math.sin(game.vars.ship_angle) * ship_size local back_x = game.vars.ship_x - math.cos(game.vars.ship_angle) * (ship_size / 2) local back_y = game.vars.ship_y - math.sin(game.vars.ship_angle) * (ship_size / 2) renderer.line(game.vars.ship_x, game.vars.ship_y, nose_x, nose_y, true, 1) renderer.line(back_x, back_y, nose_x, nose_y, true, 1) -- Draw thrust indicator if game.vars.thrusting then local flame_x = game.vars.ship_x - math.cos(game.vars.ship_angle) * ship_size local flame_y = game.vars.ship_y - math.sin(game.vars.ship_angle) * ship_size renderer.line(game.vars.ship_x, game.vars.ship_y, flame_x, flame_y, true, 1) end -- Draw score renderer.text_scaled(10, 10, "Score: " .. tostring(game.vars.score), true, 2) renderer.text_scaled(10, 20, "Level: " .. tostring(game.vars.level), true, 2) 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 - 50, game.height() / 2 + 20, "Tap to Menu", true, 2) end end end function update_ship() if game.vars.thrusting then game.vars.ship_vel_x = game.vars.ship_vel_x + math.cos(game.vars.ship_angle) * SHIP_SPEED game.vars.ship_vel_y = game.vars.ship_vel_y + math.sin(game.vars.ship_angle) * SHIP_SPEED end -- Friction game.vars.ship_vel_x = game.vars.ship_vel_x * 0.98 game.vars.ship_vel_y = game.vars.ship_vel_y * 0.98 -- Move ship game.vars.ship_x = game.vars.ship_x + game.vars.ship_vel_x game.vars.ship_y = game.vars.ship_y + game.vars.ship_vel_y -- Wrap around screen if game.vars.ship_x < 0 then game.vars.ship_x = game.width() end if game.vars.ship_x > game.width() then game.vars.ship_x = 0 end if game.vars.ship_y < 0 then game.vars.ship_y = game.height() end if game.vars.ship_y > game.height() then game.vars.ship_y = 0 end end function update_bullets() -- Update existing bullets for i = #game.vars.bullets, 1, -1 do local bullet = game.vars.bullets[i] bullet.x = bullet.x + bullet.vel_x bullet.y = bullet.y + bullet.vel_y -- Remove if off-screen if bullet.x < 0 or bullet.x > game.width() or bullet.y < 0 or bullet.y > game.height() then table.remove(game.vars.bullets, i) end end -- Fire bullet game.vars.bullet_cooldown = math.max(0, game.vars.bullet_cooldown - 1) if game.vars.thrusting and game.vars.bullet_cooldown == 0 then local bullet_x = game.vars.ship_x + math.cos(game.vars.ship_angle) * 8 local bullet_y = game.vars.ship_y + math.sin(game.vars.ship_angle) * 8 table.insert(game.vars.bullets, { x = bullet_x, y = bullet_y, vel_x = math.cos(game.vars.ship_angle) * BULLET_SPEED + game.vars.ship_vel_x, vel_y = math.sin(game.vars.ship_angle) * BULLET_SPEED + game.vars.ship_vel_y }) game.vars.bullet_cooldown = 5 end end function update_asteroids() for i = 1, #game.vars.asteroids do local ast = game.vars.asteroids[i] ast.x = ast.x + ast.vel_x ast.y = ast.y + ast.vel_y -- Wrap around screen if ast.x < -ast.size then ast.x = game.width() + ast.size end if ast.x > game.width() + ast.size then ast.x = -ast.size end if ast.y < -ast.size then ast.y = game.height() + ast.size end if ast.y > game.height() + ast.size then ast.y = -ast.size end end end function check_collisions() -- Bullet-asteroid collisions for b = #game.vars.bullets, 1, -1 do local bullet = game.vars.bullets[b] for a = #game.vars.asteroids, 1, -1 do local ast = game.vars.asteroids[a] local dx = bullet.x - ast.x local dy = bullet.y - ast.y local dist = math.sqrt(dx * dx + dy * dy) if dist < ast.size then -- Hit! table.remove(game.vars.bullets, b) table.remove(game.vars.asteroids, a) game.vars.score = game.vars.score + (4 - ast.size) * 50 -- Spawn smaller asteroids if ast.size > 1 then for _ = 1, 2 do spawn_asteroid(ast.x, ast.y, ast.size - 1) end end break end end end -- Ship-asteroid collisions for i = 1, #game.vars.asteroids do local ast = game.vars.asteroids[i] local dx = game.vars.ship_x - ast.x local dy = game.vars.ship_y - ast.y local dist = math.sqrt(dx * dx + dy * dy) if dist < ast.size + 6 then game.vars.state = STATE_GAME_OVER end end end function spawn_asteroid(x, y, size) if size < 1 then return end local speed = ASTEROID_SPEEDS[size] local angle = math.random() * math.pi * 2 table.insert(game.vars.asteroids, { x = x, y = y, size = size, vel_x = math.cos(angle) * speed, vel_y = math.sin(angle) * speed }) end function reset_game() game.vars.score = 0 game.vars.level = 1 game.vars.ship_x = game.width() / 2 game.vars.ship_y = game.height() / 2 game.vars.ship_angle = 0 game.vars.ship_vel_x = 0 game.vars.ship_vel_y = 0 game.vars.bullets = {} game.vars.asteroids = {} game.vars.frame_count = 0 spawn_asteroid(game.width() / 2 - 40, game.height() / 2 - 40, 3) spawn_asteroid(game.width() / 2 + 40, game.height() / 2 + 40, 3) end