feat: HD Remaster toggle with 4x canvas render path
G.hdRemaster persisted in localStorage (meatslicer_hd_remaster), toggled from the title screen via H key or the bottom-left tag; activation reloads so the asset tier and canvas resolution swap at boot. draw() applies a uniform hdScale() transform, the room-layer cache renders at render scale, and image smoothing follows the tier.
This commit is contained in:
1 parent
24c1958f2b
commit
ea354d0153
3 files changed
+35
-7
No files matched your search
+25
-2
@@ -6,6 +6,7 @@ const PRESSURE_SLIDER_RECT = { x: 300, y: 470, w: 360, h: 46 };
|
||||
const MENU_EXIT_BUTTON = { x: W - 208, y: H - 48, w: 180, h: 28 };
|
||||
const PAUSE_MENU_BUTTON = { x: W / 2 - 75, y: 526, w: 150, h: 28 };
|
||||
const PAUSE_EXIT_BUTTON = { x: W / 2 + 87, y: 526, w: 150, h: 28 };
|
||||
const HD_TOGGLE_BUTTON = { x: 28, y: H - 48, w: 220, h: 28 };
|
||||
const CONFIRM_WINDOW = 3;
|
||||
|
||||
function pauseBars() {
|
||||
@@ -20,7 +21,11 @@ function pauseBars() {
|
||||
function init() {
|
||||
canvas = document.getElementById('game');
|
||||
ctx = canvas.getContext('2d');
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
try { G.hdRemaster = localStorage.getItem('meatslicer_hd_remaster') === '1'; } catch (e) {}
|
||||
canvas.width = W * hdScale();
|
||||
canvas.height = H * hdScale();
|
||||
canvas.style.imageRendering = G.hdRemaster ? 'auto' : 'pixelated';
|
||||
ctx.imageSmoothingEnabled = !G.hdRemaster;
|
||||
G.devMode = debugEnabled();
|
||||
initInput(canvas);
|
||||
Sprites.load();
|
||||
@@ -67,6 +72,16 @@ function setAutoPerk(enabled) {
|
||||
Sfx.menu();
|
||||
}
|
||||
|
||||
function setHdRemaster(enabled) {
|
||||
G.hdRemaster = !!enabled;
|
||||
try { localStorage.setItem('meatslicer_hd_remaster', G.hdRemaster ? '1' : '0'); } catch (e) {}
|
||||
}
|
||||
function toggleHdRemaster() {
|
||||
setHdRemaster(!G.hdRemaster);
|
||||
Sfx.menu();
|
||||
location.reload();
|
||||
}
|
||||
|
||||
function buildAtmosphereLayer() {
|
||||
if (!document.createElement) return;
|
||||
const layer = document.createElement('canvas');
|
||||
@@ -199,7 +214,8 @@ function update(dt) {
|
||||
setPressureDial(Math.round(((Input.mx - sl.x) / sl.w) * 20) - 10);
|
||||
}
|
||||
if (!Input.mdown) G.menuDialDrag = false;
|
||||
if (keyPressed('enter', ' ') || (Input.mpressed && !inRect(Input.mx, Input.my, sl) && !exitClick)) startRun();
|
||||
if (keyPressed('h') || (Input.mpressed && inRect(Input.mx, Input.my, HD_TOGGLE_BUTTON))) { toggleHdRemaster(); break; }
|
||||
if (keyPressed('enter', ' ') || (Input.mpressed && !inRect(Input.mx, Input.my, sl) && !inRect(Input.mx, Input.my, HD_TOGGLE_BUTTON) && !exitClick)) startRun();
|
||||
break;
|
||||
}
|
||||
case 'play':
|
||||
@@ -296,6 +312,7 @@ function update(dt) {
|
||||
}
|
||||
|
||||
function draw() {
|
||||
ctx.setTransform(hdScale(), 0, 0, hdScale(), 0, 0);
|
||||
ctx.fillStyle = '#0a0506';
|
||||
ctx.fillRect(0, 0, W, H);
|
||||
|
||||
@@ -429,6 +446,12 @@ function drawMenu(ctx) {
|
||||
color: !desktopExit ? '#65595b' : (exitConfirm ? '#ffd36a' : (exitHover ? '#f5e9d6' : '#ad8f8c')),
|
||||
accent: !desktopExit ? '#3a2d31' : (exitConfirm ? '#d69a22' : (exitHover ? '#e22b46' : '#6e3843')),
|
||||
});
|
||||
const hdHover = inRect(Input.mx, Input.my, HD_TOGGLE_BUTTON);
|
||||
drawPixelTag(ctx, '[H] HD REMASTER // ' + (G.hdRemaster ? 'ON' : 'OFF'), HD_TOGGLE_BUTTON.x, HD_TOGGLE_BUTTON.y, {
|
||||
width: HD_TOGGLE_BUTTON.w, height: HD_TOGGLE_BUTTON.h,
|
||||
color: G.hdRemaster ? '#e0b94e' : (hdHover ? '#f5e9d6' : '#ad8f8c'),
|
||||
accent: G.hdRemaster ? '#a47e25' : (hdHover ? '#e22b46' : '#6e3843'),
|
||||
});
|
||||
}
|
||||
|
||||
function drawPressureDial(ctx) {
|
||||
|
||||
+7
-5
@@ -393,17 +393,19 @@ function drawFloor(ctx, r) {
|
||||
// browser; headless tests keep the simple direct path.
|
||||
const canCache = typeof document !== 'undefined' && document.createElement && G.imagesLoaded;
|
||||
if (!canCache) { drawFloorTiles(ctx, r); return; }
|
||||
const key = r.gx + ',' + r.gy + ':' + G.floor + ':' + r.shape + ':' + r.theme;
|
||||
const key = r.gx + ',' + r.gy + ':' + G.floor + ':' + r.shape + ':' + r.theme + ':' + hdScale();
|
||||
if (!G.roomLayer || G.roomLayerKey !== key) {
|
||||
const a = roomBounds(r);
|
||||
const rs = hdScale();
|
||||
const layer = document.createElement('canvas');
|
||||
layer.width = Math.max(W, a.x1); layer.height = Math.max(H, a.y1);
|
||||
layer.width = Math.max(W, a.x1) * rs; layer.height = Math.max(H, a.y1) * rs;
|
||||
const lctx = layer.getContext('2d');
|
||||
lctx.imageSmoothingEnabled = false;
|
||||
drawFloorTiles(lctx, r, layer.width, layer.height);
|
||||
lctx.setTransform(rs, 0, 0, rs, 0, 0);
|
||||
lctx.imageSmoothingEnabled = !G.hdRemaster;
|
||||
drawFloorTiles(lctx, r, layer.width / rs, layer.height / rs);
|
||||
G.roomLayer = layer; G.roomLayerKey = key;
|
||||
}
|
||||
ctx.drawImage(G.roomLayer, 0, 0);
|
||||
ctx.drawImage(G.roomLayer, 0, 0, G.roomLayer.width / hdScale(), G.roomLayer.height / hdScale());
|
||||
}
|
||||
|
||||
function drawRoom(ctx) {
|
||||
|
||||
@@ -49,6 +49,7 @@ const G = {
|
||||
sfxVol: 0.45,
|
||||
musicVol: 0.55,
|
||||
hudAlpha: 1,
|
||||
hdRemaster: false,
|
||||
imagesLoaded: false,
|
||||
roomLayer: null,
|
||||
roomLayerKey: '',
|
||||
@@ -70,6 +71,8 @@ const PRESSURE_DROP_BASE = 3; // dial 0 == 0.03 relief base
|
||||
const DEATH_LOCK = 3;
|
||||
const PRESSURE_DIAL_MIN = -10, PRESSURE_DIAL_MAX = 10;
|
||||
|
||||
function hdScale() { return G.hdRemaster ? 4 : 1; }
|
||||
|
||||
// Preserve the old -5 / 0 / +5 balance while adding genuinely wider extremes.
|
||||
function pressureGainUnits(dial) {
|
||||
const d = clamp(dial, PRESSURE_DIAL_MIN, PRESSURE_DIAL_MAX);
|
||||
|
||||
Reference in new issue
Block a user