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>
This commit is contained in:
parent
790ca87bfb
commit
515f78a3e7
5 changed files with 130 additions and 117 deletions
2
conf.lua
2
conf.lua
|
|
@ -1,5 +1,5 @@
|
||||||
function love.conf(t)
|
function love.conf(t)
|
||||||
t.window.title = "LUNAR LANDER"
|
t.window.title = "OMA-LANDER"
|
||||||
t.window.width = 1024
|
t.window.width = 1024
|
||||||
t.window.height = 768
|
t.window.height = 768
|
||||||
t.window.resizable = true
|
t.window.resizable = true
|
||||||
|
|
|
||||||
|
|
@ -2,30 +2,40 @@ local World = require("game.world")
|
||||||
|
|
||||||
local Camera = {
|
local Camera = {
|
||||||
x = 2000,
|
x = 2000,
|
||||||
y = 400,
|
y = 900,
|
||||||
zoom = 0.5,
|
zoom = 0.35,
|
||||||
}
|
}
|
||||||
|
|
||||||
local BASE_ALT = 1200
|
local MAX_ZOOM = 3.5
|
||||||
local MAX_ZOOM = 4.0
|
local MIN_ZOOM = 0.3
|
||||||
local MIN_ZOOM = 0.35
|
local ZOOM_SPEED = 2.0
|
||||||
|
|
||||||
function Camera.update(lander, terrain, dt)
|
function Camera.update(lander, terrain, dt)
|
||||||
-- Track lander position
|
-- Track lander X
|
||||||
Camera.x = lander.x
|
Camera.x = lander.x
|
||||||
Camera.y = lander.y
|
|
||||||
|
|
||||||
-- Compute altitude
|
-- Get ground height below lander
|
||||||
local groundY = terrain.getHeightAt(lander.x)
|
local groundY = terrain.getHeightAt(lander.x)
|
||||||
local altitude = groundY - lander.y
|
local altitude = groundY - lander.y
|
||||||
altitude = math.max(altitude, 10)
|
|
||||||
|
|
||||||
-- Zoom based on altitude
|
-- Camera Y: always frame BOTH the lander and the terrain
|
||||||
local targetZoom = BASE_ALT / altitude
|
-- Centre the view between the lander and the ground, biased toward showing terrain
|
||||||
|
local midY = (lander.y + groundY) / 2
|
||||||
|
-- Bias: keep terrain in the lower third even at high altitude
|
||||||
|
local targetY = lander.y + altitude * 0.45
|
||||||
|
|
||||||
|
Camera.y = Camera.y + (targetY - Camera.y) * math.min(1, dt * 3)
|
||||||
|
|
||||||
|
-- Zoom: fit the distance from lander to ground within the viewport
|
||||||
|
-- We want the full altitude span to fit in about 70% of screen height
|
||||||
|
local sw, sh = World.screenW, World.screenH
|
||||||
|
local effectiveScale = World.baseScale
|
||||||
|
local neededHeight = math.max(altitude + 100, 200) -- minimum view range
|
||||||
|
local viewportFraction = 0.7
|
||||||
|
local targetZoom = (sh * viewportFraction) / (neededHeight * effectiveScale)
|
||||||
targetZoom = math.max(MIN_ZOOM, math.min(MAX_ZOOM, targetZoom))
|
targetZoom = math.max(MIN_ZOOM, math.min(MAX_ZOOM, targetZoom))
|
||||||
|
|
||||||
-- Smooth lerp
|
Camera.zoom = Camera.zoom + (targetZoom - Camera.zoom) * math.min(1, dt * ZOOM_SPEED)
|
||||||
Camera.zoom = Camera.zoom + (targetZoom - Camera.zoom) * math.min(1, dt * 2.5)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Camera.getAltitude(landerY, terrain, landerX)
|
function Camera.getAltitude(landerY, terrain, landerX)
|
||||||
|
|
@ -61,7 +71,7 @@ end
|
||||||
|
|
||||||
function Camera.reset()
|
function Camera.reset()
|
||||||
Camera.x = 2000
|
Camera.x = 2000
|
||||||
Camera.y = 400
|
Camera.y = 900
|
||||||
Camera.zoom = MIN_ZOOM
|
Camera.zoom = MIN_ZOOM
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,16 @@ local Palette = require("rendering.palette")
|
||||||
|
|
||||||
local Lander = {}
|
local Lander = {}
|
||||||
|
|
||||||
local GRAVITY = 25
|
-- Physics tuned to match original Lunar Lander feel:
|
||||||
local THRUST_ACCEL = 60
|
-- Gentle lunar gravity, thrust comfortably overcomes it,
|
||||||
local ROT_SPEED = 2.1 -- ~120 deg/sec in radians
|
-- deliberate rotation, fuel lasts long enough to learn
|
||||||
local FUEL_RATE = 12 -- fuel per second at full thrust
|
local GRAVITY = 12 -- gentle lunar pull (original was ~1/6 earth)
|
||||||
|
local THRUST_ACCEL = 36 -- about 3x gravity — can hover and climb
|
||||||
|
local ROT_SPEED = 1.4 -- ~80 deg/sec — deliberate, not twitchy
|
||||||
|
local FUEL_RATE = 6 -- fuel per second — 750 gives ~125 sec of thrust
|
||||||
|
local MAX_SPEED = 120 -- terminal velocity cap
|
||||||
|
|
||||||
-- Lander shape (local coords, 0 = pointing up, Y+ down)
|
-- Lander shape (local coords, angle 0 = pointing up, Y+ is down in world)
|
||||||
local BODY = {
|
local BODY = {
|
||||||
{-8, -8}, {-4, -12}, {4, -12}, {8, -8},
|
{-8, -8}, {-4, -12}, {4, -12}, {8, -8},
|
||||||
{10, 0}, {8, 6}, {-8, 6}, {-10, 0},
|
{10, 0}, {8, 6}, {-8, 6}, {-10, 0},
|
||||||
|
|
@ -41,11 +45,11 @@ local ANTENNA = {
|
||||||
local lander = {}
|
local lander = {}
|
||||||
|
|
||||||
function Lander.init()
|
function Lander.init()
|
||||||
lander.x = World.WORLD_W / 2 + (math.random() - 0.5) * 1000
|
lander.x = World.WORLD_W / 2 + (math.random() - 0.5) * 800
|
||||||
lander.y = 200
|
lander.y = 200
|
||||||
lander.vx = 20 + math.random() * 20
|
lander.vx = 5 + math.random() * 8 -- gentle initial drift
|
||||||
lander.vy = 5 + math.random() * 10
|
lander.vy = 2 + math.random() * 3 -- slight downward
|
||||||
lander.angle = 0 -- 0 = pointing up
|
lander.angle = 0
|
||||||
lander.alive = true
|
lander.alive = true
|
||||||
lander.landed = false
|
lander.landed = false
|
||||||
lander.thrusting = false
|
lander.thrusting = false
|
||||||
|
|
@ -65,7 +69,7 @@ end
|
||||||
function Lander.update(dt)
|
function Lander.update(dt)
|
||||||
if not lander.alive or lander.landed then return end
|
if not lander.alive or lander.landed then return end
|
||||||
|
|
||||||
-- Gravity
|
-- Gravity (always pulls down)
|
||||||
lander.vy = lander.vy + GRAVITY * dt
|
lander.vy = lander.vy + GRAVITY * dt
|
||||||
|
|
||||||
-- Rotation
|
-- Rotation
|
||||||
|
|
@ -76,46 +80,60 @@ function Lander.update(dt)
|
||||||
lander.angle = lander.angle + ROT_SPEED * dt
|
lander.angle = lander.angle + ROT_SPEED * dt
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Thrust
|
-- Thrust (fires out the bottom of the lander, pushing opposite)
|
||||||
lander.thrusting = love.keyboard.isDown("up", "w") and World.fuel > 0
|
lander.thrusting = love.keyboard.isDown("up", "w") and World.fuel > 0
|
||||||
if lander.thrusting then
|
if lander.thrusting then
|
||||||
-- Thrust in the direction the lander is pointing (up from lander's perspective)
|
lander.vx = lander.vx + math.sin(lander.angle) * THRUST_ACCEL * dt
|
||||||
lander.vx = lander.vx - math.sin(lander.angle) * THRUST_ACCEL * dt
|
|
||||||
lander.vy = lander.vy - math.cos(lander.angle) * THRUST_ACCEL * dt
|
lander.vy = lander.vy - math.cos(lander.angle) * THRUST_ACCEL * dt
|
||||||
World.fuel = math.max(0, World.fuel - FUEL_RATE * dt)
|
World.fuel = math.max(0, World.fuel - FUEL_RATE * dt)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Cap speed so it doesn't get out of control
|
||||||
|
local speed = math.sqrt(lander.vx * lander.vx + lander.vy * lander.vy)
|
||||||
|
if speed > MAX_SPEED then
|
||||||
|
lander.vx = lander.vx / speed * MAX_SPEED
|
||||||
|
lander.vy = lander.vy / speed * MAX_SPEED
|
||||||
|
end
|
||||||
|
|
||||||
-- Move
|
-- Move
|
||||||
lander.x = lander.x + lander.vx * dt
|
lander.x = lander.x + lander.vx * dt
|
||||||
lander.y = lander.y + lander.vy * dt
|
lander.y = lander.y + lander.vy * dt
|
||||||
|
|
||||||
-- Clamp X
|
-- Clamp X to world bounds
|
||||||
lander.x = math.max(20, math.min(World.WORLD_W - 20, lander.x))
|
lander.x = math.max(20, math.min(World.WORLD_W - 20, lander.x))
|
||||||
|
|
||||||
|
-- Don't let lander fly off the top
|
||||||
|
if lander.y < 0 then
|
||||||
|
lander.y = 0
|
||||||
|
lander.vy = math.max(0, lander.vy)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Lander.abort()
|
function Lander.abort()
|
||||||
if not lander.alive or lander.landed then return end
|
if not lander.alive or lander.landed then return end
|
||||||
if World.fuel < 10 then return end
|
if World.fuel < 10 then return end
|
||||||
|
|
||||||
-- Auto-level: snap angle toward 0
|
-- Auto-level: snap angle to upright
|
||||||
lander.angle = lander.angle * 0.3
|
lander.angle = lander.angle * 0.1
|
||||||
-- Full thrust burst
|
-- Strong upward thrust burst — halve downward velocity and push up
|
||||||
lander.vy = lander.vy - THRUST_ACCEL * 0.5
|
if lander.vy > 0 then
|
||||||
-- Costs a chunk of fuel
|
lander.vy = lander.vy * 0.3
|
||||||
World.fuel = math.max(0, World.fuel - 50)
|
end
|
||||||
|
lander.vy = lander.vy - THRUST_ACCEL * 0.6
|
||||||
|
-- Kill most horizontal speed
|
||||||
|
lander.vx = lander.vx * 0.3
|
||||||
|
-- Heavy fuel cost
|
||||||
|
World.fuel = math.max(0, World.fuel - 60)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Lander.getCollisionPoints()
|
function Lander.getCollisionPoints()
|
||||||
-- Return transformed foot positions for terrain collision
|
|
||||||
local pts = {}
|
local pts = {}
|
||||||
-- Foot endpoints
|
|
||||||
local footPts = {{-17, 16}, {-11, 16}, {11, 16}, {17, 16}}
|
local footPts = {{-17, 16}, {-11, 16}, {11, 16}, {17, 16}}
|
||||||
for _, fp in ipairs(footPts) do
|
for _, fp in ipairs(footPts) do
|
||||||
local wx, wy = transformPoint(fp[1], fp[2], lander.angle, lander.x, lander.y)
|
local wx, wy = transformPoint(fp[1], fp[2], lander.angle, lander.x, lander.y)
|
||||||
table.insert(pts, {x = wx, y = wy})
|
table.insert(pts, {x = wx, y = wy})
|
||||||
end
|
end
|
||||||
-- Body bottom
|
local bodyBottom = {{-8, 6}, {8, 6}, {0, 6}}
|
||||||
local bodyBottom = {{-8, 6}, {8, 6}}
|
|
||||||
for _, bp in ipairs(bodyBottom) do
|
for _, bp in ipairs(bodyBottom) do
|
||||||
local wx, wy = transformPoint(bp[1], bp[2], lander.angle, lander.x, lander.y)
|
local wx, wy = transformPoint(bp[1], bp[2], lander.angle, lander.x, lander.y)
|
||||||
table.insert(pts, {x = wx, y = wy})
|
table.insert(pts, {x = wx, y = wy})
|
||||||
|
|
@ -186,25 +204,28 @@ function Lander.draw()
|
||||||
love.graphics.line(x1, y1, x2, y2)
|
love.graphics.line(x1, y1, x2, y2)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Thrust flame
|
-- Thrust flame (fully transformed)
|
||||||
if lander.thrusting then
|
if lander.thrusting then
|
||||||
love.graphics.setColor(p.thrust)
|
love.graphics.setColor(p.thrust)
|
||||||
love.graphics.setLineWidth(2)
|
love.graphics.setLineWidth(2)
|
||||||
local flameLen = 10 + math.random() * 15
|
local flameLen = 10 + math.random() * 15
|
||||||
local flameSpread = 3 + math.random() * 3
|
local flameSpread = 3 + math.random() * 3
|
||||||
|
|
||||||
local fx1, fy1 = transformPoint(-flameSpread, 6, a, cx, cy)
|
local fx1, fy1 = transformPoint(-flameSpread, 8, a, cx, cy)
|
||||||
local fx2, fy2 = transformPoint(flameSpread, 6, a, cx, cy)
|
local fx2, fy2 = transformPoint(flameSpread, 8, a, cx, cy)
|
||||||
local ftx, fty = transformPoint((math.random()-0.5)*3, 6 + flameLen, a, cx, cy)
|
local ftx, fty = transformPoint((math.random()-0.5)*3, 8 + flameLen, a, cx, cy)
|
||||||
|
|
||||||
love.graphics.line(fx1, fy1, ftx, fty)
|
love.graphics.line(fx1, fy1, ftx, fty)
|
||||||
love.graphics.line(fx2, fy2, ftx, fty)
|
love.graphics.line(fx2, fy2, ftx, fty)
|
||||||
|
|
||||||
-- Inner flame
|
-- Inner bright flame
|
||||||
local flameLen2 = 5 + math.random() * 8
|
|
||||||
local ft2x, ft2y = transformPoint((math.random()-0.5)*2, 6 + flameLen2, a, cx, cy)
|
|
||||||
love.graphics.setColor(p.bright)
|
love.graphics.setColor(p.bright)
|
||||||
love.graphics.line(cx, cy + 3, ft2x, ft2y)
|
local flameLen2 = 5 + math.random() * 8
|
||||||
|
local fi1x, fi1y = transformPoint(-1.5, 8, a, cx, cy)
|
||||||
|
local fi2x, fi2y = transformPoint(1.5, 8, a, cx, cy)
|
||||||
|
local ft2x, ft2y = transformPoint((math.random()-0.5)*1.5, 8 + flameLen2, a, cx, cy)
|
||||||
|
love.graphics.line(fi1x, fi1y, ft2x, ft2y)
|
||||||
|
love.graphics.line(fi2x, fi2y, ft2x, ft2y)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
118
game/terrain.lua
118
game/terrain.lua
|
|
@ -12,90 +12,66 @@ function Terrain.generate()
|
||||||
|
|
||||||
local W = World.WORLD_W
|
local W = World.WORLD_W
|
||||||
local baseline = 1600
|
local baseline = 1600
|
||||||
local step = 30
|
|
||||||
|
|
||||||
-- Place landing pads first
|
-- Place 3 landing pads at fixed zones to avoid overlap issues
|
||||||
local padDefs = {
|
local padDefs = {
|
||||||
{width = 120, mult = 2, label = "2X"},
|
{cx = W * 0.2, width = 120, mult = 2, label = "2X"},
|
||||||
{width = 80, mult = 3, label = "3X"},
|
{cx = W * 0.55, width = 80, mult = 3, label = "3X"},
|
||||||
{width = 50, mult = 5, label = "5X"},
|
{cx = W * 0.8, width = 50, mult = 5, label = "5X"},
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Distribute pads across the terrain
|
|
||||||
local padPositions = {}
|
|
||||||
local usedZones = {}
|
|
||||||
for _, def in ipairs(padDefs) do
|
for _, def in ipairs(padDefs) do
|
||||||
local attempts = 0
|
|
||||||
local px
|
|
||||||
repeat
|
|
||||||
px = 400 + math.random() * (W - 800)
|
|
||||||
attempts = attempts + 1
|
|
||||||
local ok = true
|
|
||||||
for _, used in ipairs(usedZones) do
|
|
||||||
if math.abs(px - used) < 400 then ok = false; break end
|
|
||||||
end
|
|
||||||
if ok then break end
|
|
||||||
until attempts > 50
|
|
||||||
|
|
||||||
local py = baseline + (math.random() - 0.5) * 200
|
local py = baseline + (math.random() - 0.5) * 200
|
||||||
table.insert(padPositions, {x = px, y = py, width = def.width, mult = def.mult, label = def.label})
|
|
||||||
table.insert(usedZones, px)
|
|
||||||
table.insert(pads, {
|
table.insert(pads, {
|
||||||
x1 = px - def.width / 2,
|
x1 = def.cx - def.width / 2,
|
||||||
x2 = px + def.width / 2,
|
x2 = def.cx + def.width / 2,
|
||||||
y = py,
|
y = py,
|
||||||
mult = def.mult,
|
mult = def.mult,
|
||||||
label = def.label,
|
label = def.label,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Sort pads by X for terrain generation
|
|
||||||
table.sort(pads, function(a, b) return a.x1 < b.x1 end)
|
table.sort(pads, function(a, b) return a.x1 < b.x1 end)
|
||||||
|
|
||||||
-- Generate terrain points left to right
|
-- Generate terrain left to right, inserting pads as flat segments
|
||||||
local x = 0
|
local x = 0
|
||||||
local y = baseline + (math.random() - 0.5) * 100
|
local y = baseline + (math.random() - 0.5) * 80
|
||||||
table.insert(points, {x = x, y = y})
|
table.insert(points, {x = 0, y = y})
|
||||||
|
|
||||||
|
local padIdx = 1
|
||||||
|
|
||||||
while x < W do
|
while x < W do
|
||||||
-- Check if we're approaching a pad
|
-- Check if next pad is coming up
|
||||||
local onPad = false
|
if padIdx <= #pads and x >= pads[padIdx].x1 - 40 then
|
||||||
local currentPad = nil
|
local pad = pads[padIdx]
|
||||||
for _, pad in ipairs(pads) do
|
-- Slope to pad start
|
||||||
if x >= pad.x1 - step and x <= pad.x2 + step then
|
table.insert(points, {x = pad.x1 - 5, y = y})
|
||||||
onPad = true
|
table.insert(points, {x = pad.x1, y = pad.y})
|
||||||
currentPad = pad
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if onPad and currentPad then
|
|
||||||
-- Transition to pad level
|
|
||||||
if x < currentPad.x1 then
|
|
||||||
-- Approach: slope down/up to pad
|
|
||||||
table.insert(points, {x = currentPad.x1 - 5, y = y})
|
|
||||||
table.insert(points, {x = currentPad.x1, y = currentPad.y})
|
|
||||||
x = currentPad.x1
|
|
||||||
end
|
|
||||||
-- Flat pad
|
-- Flat pad
|
||||||
table.insert(points, {x = currentPad.x2, y = currentPad.y})
|
table.insert(points, {x = pad.x2, y = pad.y})
|
||||||
x = currentPad.x2
|
x = pad.x2 + 1
|
||||||
y = currentPad.y
|
y = pad.y
|
||||||
-- Resume jagged after pad
|
padIdx = padIdx + 1
|
||||||
x = x + step * 0.5
|
-- Resume jagged
|
||||||
y = y + (math.random() - 0.5) * 60
|
local jx = x + 20 + math.random() * 30
|
||||||
table.insert(points, {x = x, y = y})
|
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
|
else
|
||||||
x = x + step + math.random() * step
|
-- Normal jagged terrain
|
||||||
-- Jagged variation
|
local step = 25 + math.random() * 35
|
||||||
y = y + (math.random() - 0.5) * 120
|
x = x + step
|
||||||
|
y = y + (math.random() - 0.5) * 100
|
||||||
y = math.max(baseline - 250, math.min(baseline + 250, y))
|
y = math.max(baseline - 250, math.min(baseline + 250, y))
|
||||||
table.insert(points, {x = x, y = y})
|
table.insert(points, {x = x, y = y})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Ensure last point reaches edge
|
-- Close at right edge
|
||||||
|
if points[#points].x < W then
|
||||||
table.insert(points, {x = W, y = points[#points].y})
|
table.insert(points, {x = W, y = points[#points].y})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Terrain.getPoints()
|
function Terrain.getPoints()
|
||||||
|
|
@ -107,7 +83,6 @@ function Terrain.getPads()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Terrain.getHeightAt(wx)
|
function Terrain.getHeightAt(wx)
|
||||||
-- Find terrain height at world X by interpolating between points
|
|
||||||
if #points < 2 then return 1600 end
|
if #points < 2 then return 1600 end
|
||||||
if wx <= points[1].x then return points[1].y end
|
if wx <= points[1].x then return points[1].y end
|
||||||
if wx >= points[#points].x then return points[#points].y end
|
if wx >= points[#points].x then return points[#points].y end
|
||||||
|
|
@ -133,13 +108,13 @@ end
|
||||||
function Terrain.draw(visMinX, visMaxX)
|
function Terrain.draw(visMinX, visMaxX)
|
||||||
local p = Palette.get()
|
local p = Palette.get()
|
||||||
|
|
||||||
-- Draw terrain surface
|
-- Terrain surface
|
||||||
love.graphics.setColor(p.terrain)
|
love.graphics.setColor(p.terrain)
|
||||||
love.graphics.setLineWidth(2)
|
love.graphics.setLineWidth(2)
|
||||||
|
|
||||||
local pts = {}
|
local pts = {}
|
||||||
for _, pt in ipairs(points) do
|
for _, pt in ipairs(points) do
|
||||||
if pt.x >= visMinX - 100 and pt.x <= visMaxX + 100 then
|
if pt.x >= visMinX - 200 and pt.x <= visMaxX + 200 then
|
||||||
table.insert(pts, pt.x)
|
table.insert(pts, pt.x)
|
||||||
table.insert(pts, pt.y)
|
table.insert(pts, pt.y)
|
||||||
end
|
end
|
||||||
|
|
@ -148,17 +123,24 @@ function Terrain.draw(visMinX, visMaxX)
|
||||||
love.graphics.line(pts)
|
love.graphics.line(pts)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Draw landing pads (brighter, with labels)
|
-- Landing pads (brighter)
|
||||||
love.graphics.setColor(p.pad)
|
|
||||||
love.graphics.setLineWidth(3)
|
|
||||||
for _, pad in ipairs(pads) do
|
for _, pad in ipairs(pads) do
|
||||||
if pad.x2 >= visMinX and pad.x1 <= visMaxX then
|
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)
|
love.graphics.line(pad.x1, pad.y, pad.x2, pad.y)
|
||||||
|
|
||||||
-- Label below pad
|
-- Multiplier label — constant screen size regardless of zoom
|
||||||
love.graphics.setColor(p.pad[1], p.pad[2], p.pad[3], 0.7)
|
love.graphics.setColor(p.pad[1], p.pad[2], p.pad[3], 0.8)
|
||||||
local labelX = (pad.x1 + pad.x2) / 2
|
local cx = (pad.x1 + pad.x2) / 2
|
||||||
love.graphics.print(pad.label, labelX - 8, pad.y + 5)
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
2
main.lua
2
main.lua
|
|
@ -99,7 +99,7 @@ local function drawTitleScreen()
|
||||||
local titleY = sh * 0.15
|
local titleY = sh * 0.15
|
||||||
love.graphics.setFont(Fonts.large)
|
love.graphics.setFont(Fonts.large)
|
||||||
love.graphics.setColor(p.bright)
|
love.graphics.setColor(p.bright)
|
||||||
love.graphics.printf("LUNAR LANDER", 0, titleY, sw, "center")
|
love.graphics.printf("OMA-LANDER", 0, titleY, sw, "center")
|
||||||
|
|
||||||
-- Controls
|
-- Controls
|
||||||
love.graphics.setFont(Fonts.small)
|
love.graphics.setFont(Fonts.small)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue