oma-lander/game/terrain.lua
28allday 515f78a3e7 OMA-LANDER: rebrand and tune physics, camera, terrain
Rename to OMA-LANDER in title bar and title screen. Retune lander
physics for a gentler, original-feel experience (lower gravity, slower
rotation, reduced fuel burn, speed cap, top-of-world clamp) and fix
thrust vx sign. Rework camera to frame lander and terrain together
with a smoother altitude-based zoom. Simplify terrain: pads at fixed
zones, cleaner generation loop, zoom-invariant multiplier labels.
Stronger abort burst (kills horizontal speed, halves downward vy).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:39:12 +01:00

148 lines
4.3 KiB
Lua

local World = require("game.world")
local Palette = require("rendering.palette")
local Terrain = {}
local points = {}
local pads = {}
function Terrain.generate()
points = {}
pads = {}
local W = World.WORLD_W
local baseline = 1600
-- Place 3 landing pads at fixed zones to avoid overlap issues
local padDefs = {
{cx = W * 0.2, width = 120, mult = 2, label = "2X"},
{cx = W * 0.55, width = 80, mult = 3, label = "3X"},
{cx = W * 0.8, width = 50, mult = 5, label = "5X"},
}
for _, def in ipairs(padDefs) do
local py = baseline + (math.random() - 0.5) * 200
table.insert(pads, {
x1 = def.cx - def.width / 2,
x2 = def.cx + def.width / 2,
y = py,
mult = def.mult,
label = def.label,
})
end
table.sort(pads, function(a, b) return a.x1 < b.x1 end)
-- Generate terrain left to right, inserting pads as flat segments
local x = 0
local y = baseline + (math.random() - 0.5) * 80
table.insert(points, {x = 0, y = y})
local padIdx = 1
while x < W do
-- Check if next pad is coming up
if padIdx <= #pads and x >= pads[padIdx].x1 - 40 then
local pad = pads[padIdx]
-- Slope to pad start
table.insert(points, {x = pad.x1 - 5, y = y})
table.insert(points, {x = pad.x1, y = pad.y})
-- Flat pad
table.insert(points, {x = pad.x2, y = pad.y})
x = pad.x2 + 1
y = pad.y
padIdx = padIdx + 1
-- Resume jagged
local jx = x + 20 + math.random() * 30
y = y + (math.random() - 0.5) * 80
y = math.max(baseline - 250, math.min(baseline + 250, y))
table.insert(points, {x = jx, y = y})
x = jx
else
-- Normal jagged terrain
local step = 25 + math.random() * 35
x = x + step
y = y + (math.random() - 0.5) * 100
y = math.max(baseline - 250, math.min(baseline + 250, y))
table.insert(points, {x = x, y = y})
end
end
-- Close at right edge
if points[#points].x < W then
table.insert(points, {x = W, y = points[#points].y})
end
end
function Terrain.getPoints()
return points
end
function Terrain.getPads()
return pads
end
function Terrain.getHeightAt(wx)
if #points < 2 then return 1600 end
if wx <= points[1].x then return points[1].y end
if wx >= points[#points].x then return points[#points].y end
for i = 1, #points - 1 do
if points[i].x <= wx and points[i+1].x > wx then
local t = (wx - points[i].x) / (points[i+1].x - points[i].x)
return points[i].y + t * (points[i+1].y - points[i].y)
end
end
return 1600
end
function Terrain.getPadAt(wx)
for _, pad in ipairs(pads) do
if wx >= pad.x1 and wx <= pad.x2 then
return pad
end
end
return nil
end
function Terrain.draw(visMinX, visMaxX)
local p = Palette.get()
-- Terrain surface
love.graphics.setColor(p.terrain)
love.graphics.setLineWidth(2)
local pts = {}
for _, pt in ipairs(points) do
if pt.x >= visMinX - 200 and pt.x <= visMaxX + 200 then
table.insert(pts, pt.x)
table.insert(pts, pt.y)
end
end
if #pts >= 4 then
love.graphics.line(pts)
end
-- Landing pads (brighter)
for _, pad in ipairs(pads) do
if pad.x2 >= visMinX and pad.x1 <= visMaxX then
love.graphics.setColor(p.pad)
love.graphics.setLineWidth(3)
love.graphics.line(pad.x1, pad.y, pad.x2, pad.y)
-- Multiplier label — constant screen size regardless of zoom
love.graphics.setColor(p.pad[1], p.pad[2], p.pad[3], 0.8)
local cx = (pad.x1 + pad.x2) / 2
local Camera = require("game.camera")
local World = require("game.world")
local invZoom = 1 / (World.baseScale * Camera.getZoom())
love.graphics.push()
love.graphics.translate(cx, pad.y + 15 * invZoom)
love.graphics.scale(invZoom * 0.8, invZoom * 0.8)
love.graphics.printf(pad.label, -50, 0, 100, "center")
love.graphics.pop()
end
end
end
return Terrain