oma-tank/game/radar.lua
2026-04-18 11:35:06 +01:00

120 lines
4.7 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local World = require("game.world")
local Palette = require("rendering.palette")
local Radar = {}
-- Authentic-arcade circular radar: rotating sweep line, fading blips where the
-- sweep last crossed an enemy, forward-cone diagonals, 4 compass ticks.
local RADAR_RANGE = 1000 -- world units shown inside the circle
local SWEEP_SPEED = 4 -- rad/s
-- Blip fade: alpha drops ~0.51 per second after the sweep has passed an enemy
local BLIP_FADE_PER_SEC = 0.51
local FORWARD_CONE_HALF = math.rad(30)
local sweepAngle = 0
local blips = {} -- [id] = { rx, ry, alpha } in radar-local coords
function Radar.init()
sweepAngle = 0
blips = {}
end
function Radar.update(dt, player, enemy)
-- Sweep rotates counter-clockwise (angle decreases each tick)
sweepAngle = (sweepAngle - SWEEP_SPEED * dt) % (math.pi * 2)
-- Fade existing blips
for id, b in pairs(blips) do
b.alpha = b.alpha - BLIP_FADE_PER_SEC * dt
if b.alpha <= 0 then blips[id] = nil end
end
if not (enemy and enemy.alive and player) then return end
-- Enemy position in radar-local (player-facing) coords — forward = +y on the scope
local dx, dz, dist = World.wrappedDist(player.x, player.z, enemy.x, enemy.z)
if dist > RADAR_RANGE then return end
local cosA = math.cos(player.angle)
local sinA = math.sin(player.angle)
local rx = dx * cosA - dz * sinA -- right on radar
local ry = dx * sinA + dz * cosA -- forward on radar (drawn as -y on screen)
-- Register a blip if the sweep line passed over the enemy's bearing this frame.
--
-- The sweep rotates CCW, so across one frame the sweep angle moves from
-- `lastSweep` → `sweepAngle` (a decrease mod 2π). The enemy is "inside" that
-- arc when its bearing lies in [sweepAngle, lastSweep]. The arc wraps past 0
-- when sweepAngle > lastSweep (decrementing wrapped around), so there are
-- two cases:
-- • non-wrap: sweepAngle < lastSweep → enemyBearing in [sweepAngle, lastSweep]
-- • wrapped: sweepAngle > lastSweep → enemyBearing in [sweepAngle, 2π) [0, lastSweep]
local enemyBearing = math.atan2(rx, ry) % (math.pi * 2)
local lastSweep = (sweepAngle + SWEEP_SPEED * dt) % (math.pi * 2)
local swept
if sweepAngle <= lastSweep then
swept = enemyBearing >= sweepAngle and enemyBearing <= lastSweep
else
swept = enemyBearing >= sweepAngle or enemyBearing <= lastSweep
end
if swept then
blips.current = { rx = rx / RADAR_RANGE, ry = ry / RADAR_RANGE, alpha = 1.0 }
end
end
function Radar.draw(player, enemy, _obstacles)
local p = Palette.get()
local sw = World.screenW
local rh = World.radarH
local sc = sw / 1024
-- Update drift, but in draw so caller doesn't need to plumb a dedicated hook yet.
Radar.update(love.timer.getDelta(), player, enemy)
-- Radar strip background
love.graphics.setColor(p.radar_bg[1], p.radar_bg[2], p.radar_bg[3], 0.4)
love.graphics.rectangle("fill", 0, 0, sw, rh)
-- Radar circle position — top-centre of the HUD strip
local radius = math.min(rh * 0.42, sw * 0.08)
local cx = sw / 2
local cy = rh / 2
-- Outer ring
love.graphics.setColor(p.bright[1], p.bright[2], p.bright[3], 0.65)
love.graphics.setLineWidth(1.5 * sc)
love.graphics.circle("line", cx, cy, radius, 48)
-- Forward cone (two diagonals upward from centre, spanning ±30°)
local coneX = math.sin(FORWARD_CONE_HALF) * radius
local coneY = math.cos(FORWARD_CONE_HALF) * radius
love.graphics.setColor(p.bright[1], p.bright[2], p.bright[3], 0.35)
love.graphics.setLineWidth(1 * sc)
love.graphics.line(cx, cy, cx - coneX, cy - coneY)
love.graphics.line(cx, cy, cx + coneX, cy - coneY)
-- Compass ticks (N/E/S/W) on the rim
local tick = radius * 0.12
love.graphics.setColor(p.bright[1], p.bright[2], p.bright[3], 0.5)
love.graphics.line(cx, cy - radius, cx, cy - radius + tick)
love.graphics.line(cx, cy + radius, cx, cy + radius - tick)
love.graphics.line(cx - radius, cy, cx - radius + tick, cy)
love.graphics.line(cx + radius, cy, cx + radius - tick, cy)
-- Sweep line (bearing 0 = straight up)
local sx = cx + math.sin(sweepAngle) * radius
local sy = cy - math.cos(sweepAngle) * radius
love.graphics.setColor(p.bright[1], p.bright[2], p.bright[3], 0.8)
love.graphics.setLineWidth(1.5 * sc)
love.graphics.line(cx, cy, sx, sy)
-- Fading blips
for _, b in pairs(blips) do
local bx = cx + b.rx * radius
local by = cy - b.ry * radius
love.graphics.setColor(p.enemy[1], p.enemy[2], p.enemy[3], math.min(1, b.alpha))
love.graphics.circle("fill", bx, by, 3 * sc)
end
end
return Radar