oma-roids/game/world.lua
28allday bc88613e07 Asteroids: complete Love2D game with Omarchy integration
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>
2026-04-13 12:58:03 +01:00

85 lines
2 KiB
Lua

local World = {
GAME_W = 1024,
GAME_H = 768,
visibleH = 768,
scale = 1,
offsetX = 0,
offsetY = 0,
state = "title",
wave = 1,
score = 0,
highScore = 0,
lives = 3,
nextExtraLife = 10000,
gameOverTimer = 0,
screenW = 0,
screenH = 0,
respawnTimer = 0,
waveTimer = 0,
}
function World.resize(w, h)
if not w or not h then w, h = love.graphics.getDimensions() end
World.screenW = w
World.screenH = h
World.scale = w / World.GAME_W
World.visibleH = h / World.scale
World.offsetX = 0
World.offsetY = h - (World.GAME_H * World.scale)
end
function World.ensureScale()
local w, h = love.graphics.getDimensions()
if w ~= World.screenW or h ~= World.screenH then
World.resize(w, h)
local Fonts = require("rendering.fonts")
Fonts.init(World.scale)
end
end
function World.toGame(sx, sy)
local gx = (sx - World.offsetX) / World.scale
local gy = (sy - World.offsetY) / World.scale
return gx, gy
end
function World.toScreen(gx, gy)
return gx * World.scale + World.offsetX, gy * World.scale + World.offsetY
end
function World.visibleTop()
return World.GAME_H - World.visibleH
end
function World.wrapX(x)
return (x % World.GAME_W + World.GAME_W) % World.GAME_W
end
function World.wrapY(y)
return (y % World.GAME_H + World.GAME_H) % World.GAME_H
end
function World.wrappedDist(x1, y1, x2, y2)
local dx = x2 - x1
local dy = y2 - y1
if math.abs(dx) > World.GAME_W / 2 then
dx = dx - World.GAME_W * (dx > 0 and 1 or -1)
end
if math.abs(dy) > World.GAME_H / 2 then
dy = dy - World.GAME_H * (dy > 0 and 1 or -1)
end
return dx, dy, math.sqrt(dx*dx + dy*dy)
end
function World.addScore(points)
World.score = World.score + points
while World.score >= World.nextExtraLife do
World.lives = World.lives + 1
World.nextExtraLife = World.nextExtraLife + 10000
end
if World.score > World.highScore then
World.highScore = World.score
end
end
return World