Faithful recreation of Atari Asteroids (1979) with vector wireframe aesthetic. Auto-detects Omarchy system theme and font on launch. Features: - Inertia physics (zero friction), rotate/thrust/fire/hyperspace controls - 3 asteroid sizes that split on destroy (large→medium→small) - Large and small UFO saucers with AI (random vs aimed shooting) - Screen wrapping for ship/asteroids/saucers, bullets expire at edges - Ship death fragments, explosion particles - Iconic heartbeat that speeds up as wave clears - Wave progression (4→11 asteroids, speed ramps) - 3 lives, extra life every 10k points - Persistent high scores with 3-letter initial entry - Procedural sound effects (beat, thrust, fire, explosions, saucer drone) - Full-screen scaling, system font detection Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
72 lines
1.7 KiB
Lua
72 lines
1.7 KiB
Lua
local World = require("game.world")
|
|
local Palette = require("rendering.palette")
|
|
|
|
local Bullets = {}
|
|
|
|
local active = {}
|
|
local BULLET_SPEED = 600
|
|
local BULLET_LIFETIME = 0.667
|
|
local MAX_PLAYER_BULLETS = 4
|
|
|
|
function Bullets.fire(x, y, angle, shipVx, shipVy, owner)
|
|
if owner == "player" then
|
|
local count = 0
|
|
for _, b in ipairs(active) do
|
|
if b.owner == "player" then count = count + 1 end
|
|
end
|
|
if count >= MAX_PLAYER_BULLETS then return false end
|
|
end
|
|
|
|
table.insert(active, {
|
|
x = x, y = y,
|
|
vx = shipVx + math.cos(angle) * BULLET_SPEED,
|
|
vy = shipVy + math.sin(angle) * BULLET_SPEED,
|
|
timer = BULLET_LIFETIME,
|
|
owner = owner or "player",
|
|
})
|
|
return true
|
|
end
|
|
|
|
function Bullets.update(dt)
|
|
for i = #active, 1, -1 do
|
|
local b = active[i]
|
|
b.x = b.x + b.vx * dt
|
|
b.y = b.y + b.vy * dt
|
|
b.timer = b.timer - dt
|
|
|
|
-- Bullets don't wrap — remove when out of bounds or expired
|
|
if b.timer <= 0 or b.x < -5 or b.x > World.GAME_W + 5 or
|
|
b.y < -5 or b.y > World.GAME_H + 5 then
|
|
table.remove(active, i)
|
|
end
|
|
end
|
|
end
|
|
|
|
function Bullets.getAll()
|
|
return active
|
|
end
|
|
|
|
function Bullets.remove(idx)
|
|
table.remove(active, idx)
|
|
end
|
|
|
|
function Bullets.clear()
|
|
active = {}
|
|
end
|
|
|
|
function Bullets.draw()
|
|
local p = Palette.get()
|
|
local lw = 1 / World.scale
|
|
|
|
for _, b in ipairs(active) do
|
|
if b.owner == "player" then
|
|
love.graphics.setColor(p.bullet)
|
|
else
|
|
love.graphics.setColor(p.saucer)
|
|
end
|
|
love.graphics.setLineWidth(lw * 2)
|
|
love.graphics.circle("fill", b.x, b.y, 1.5)
|
|
end
|
|
end
|
|
|
|
return Bullets
|