orbit/js/ui/CyberShape.js

105 lines
3.2 KiB
JavaScript

/**
* The angular "cut-corner" shapes of the cyberpunk UI: rectangles with
* two opposing corners sliced off (top-left + bottom-right), drawn with
* a Graphics so they can be hit-tested with a plain rectangle.
*
* Static helpers — no state, no scene bookkeeping:
*
* CyberShape.draw(panel, 320, 52, { fill: 0x0a1120, stroke: 0x00e5ff, ... });
* CyberShape.frame(scene, w/2, h/2, w, h, { color: neon, alpha: 0.35 });
*/
export class CyberShape {
/**
* The cut-corner polygon, centered on (0,0). `notch` is the size of
* each corner slice (clamped so it can never eat the whole shape).
*/
static points(w, h, notch) {
const n = Math.max(0, Math.min(notch ?? 0, w / 2, h / 2));
const x = w / 2;
const y = h / 2;
return [
{ x: -x + n, y: -y },
{ x, y: -y },
{ x, y: y - n },
{ x: x - n, y },
{ x: -x, y },
{ x: -x, y: -y + n },
];
}
/**
* Draw a cut-corner panel into an existing Graphics (at its origin).
*
* o: {
* notch, // corner slice size (px); default min(14, h*0.28)
* fill, fillAlpha, // panel fill (color int)
* stroke, strokeAlpha, // edge (color int)
* lineWidth, // edge width
* glow, glowAlpha, // optional soft outer pass (color int)
* }
* Omit `fill`/`stroke` to draw only the part you gave.
*/
static draw(g, w, h, o = {}) {
const pts = CyberShape.points(w, h, o.notch ?? Math.min(14, h * 0.28));
if (o.fill !== undefined) {
g.fillStyle(o.fill, o.fillAlpha ?? 1);
g.fillPoints(pts, true);
}
if (o.stroke !== undefined) {
g.lineStyle(o.lineWidth ?? 1.5, o.stroke, o.strokeAlpha ?? 1);
g.strokePoints(pts, true);
}
if (o.glow !== undefined) {
g.lineStyle((o.lineWidth ?? 1.5) + 4, o.glow, o.glowAlpha ?? 0.25);
g.strokePoints(pts, true);
}
}
/**
* A new cut-corner panel Graphics centered at (x, y) in the scene.
* Same options as draw(). Returns the Graphics.
*/
static panel(scene, x, y, w, h, o = {}) {
const g = scene.add.graphics().setPosition(x, y);
CyberShape.draw(g, w, h, o);
return g;
}
/**
* HUD corner brackets + edge ticks framing a rect centered at (x, y) —
* the viewfinder chrome around the console.
*
* o: { color, alpha, length, lineWidth, ticks }
*/
static frame(scene, x, y, w, h, o = {}) {
const color = o.color ?? 0x00e5ff;
const alpha = o.alpha ?? 0.5;
const length = o.length ?? 26;
const lw = o.lineWidth ?? 2;
const g = scene.add.graphics().setPosition(x, y);
g.lineStyle(lw, color, alpha);
const hw = w / 2;
const hh = h / 2;
const corner = (cx, cy, sx, sy) => {
g.lineBetween(cx, cy, cx, cy + sy * length);
g.lineBetween(cx, cy, cx + sx * length, cy);
};
corner(-hw, -hh, 1, 1);
corner(hw, -hh, -1, 1);
corner(-hw, hh, 1, -1);
corner(hw, hh, -1, -1);
if (o.ticks !== false) {
g.lineStyle(lw, color, alpha * 0.7);
const t = 7;
g.lineBetween(0, -hh, 0, -hh + t);
g.lineBetween(0, hh, 0, hh - t);
g.lineBetween(-hw, 0, -hw + t, 0);
g.lineBetween(hw, 0, hw - t, 0);
}
return g;
}
}