mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-11-07 23:43:53 +01:00
The ASCII renderer never set focusPoint, so switching to it mid-game left the SP camera with no focus → scale-only transform pinned the grid to the corner and the explored area sat off-screen (black). AsciiRenderer.render now sets focusPoint on the player cell (sticky), and the camera fallback covers name==="ascii" too (cell-based, same as tiled). Iso already reports focusPoint. 3D drives its own THREE camera + sizes its canvas to the level, so _applyCamera now scale-to-FITS the 3D canvas into the host (centered, no player-follow) instead of applying a broken zoom.
109 lines
4.5 KiB
JavaScript
109 lines
4.5 KiB
JavaScript
// AsciiRenderer — draws a Scene as a monospace glyph grid on a 2D canvas.
|
|
// The always-available fallback tier: tiny, legible, accessible.
|
|
(function (root) {
|
|
'use strict';
|
|
|
|
function AsciiRenderer(host, opts) {
|
|
opts = opts || {};
|
|
this.name = 'ascii';
|
|
this.host = host;
|
|
this.cell = opts.cell || 22;
|
|
this.canvas = document.createElement('canvas');
|
|
this.canvas.className = 'rk-canvas';
|
|
this.ctx = this.canvas.getContext('2d');
|
|
host.appendChild(this.canvas);
|
|
}
|
|
|
|
AsciiRenderer.prototype.render = function (scene) {
|
|
if (!scene) return;
|
|
var cell = this.cell, ctx = this.ctx;
|
|
this.canvas.width = scene.cols * cell;
|
|
this.canvas.height = scene.rows * cell;
|
|
|
|
ctx.fillStyle = scene.background || '#000';
|
|
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
|
|
var glyphFont = (cell - 4) + "px 'Courier New', monospace";
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'middle';
|
|
|
|
ctx.font = glyphFont;
|
|
// For a designed room, ASCII shows a floor-plan from the walkability grid.
|
|
var room = (!scene.isDungeon && window.RK && RK.roomReady && RK.roomReady()) ? RK.activeRoom.desc : null;
|
|
for (var y = 0; y < scene.rows; y++) {
|
|
for (var x = 0; x < scene.cols; x++) {
|
|
if (room) {
|
|
var walk = room.walkable[y] && room.walkable[y][x];
|
|
ctx.fillStyle = walk ? '#2f4030' : '#39404c';
|
|
ctx.fillText(walk ? '·' : '#', x * cell + cell / 2, y * cell + cell / 2);
|
|
} else {
|
|
var def = scene.legend[scene.grid[y][x]] || { char: '?', color: '#555' };
|
|
ctx.fillStyle = def.color;
|
|
// Dungeon lighting: dim tiles in shadow.
|
|
if (scene.lightGrid && scene.lightGrid[y] && scene.lightGrid[y][x] != null) {
|
|
var b = scene.lightGrid[y][x];
|
|
if (b < 1) ctx.globalAlpha = b;
|
|
}
|
|
ctx.fillText(def.char, x * cell + cell / 2, y * cell + cell / 2);
|
|
ctx.globalAlpha = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < scene.entities.length; i++) {
|
|
var e = scene.entities[i];
|
|
var cx = e.x * cell + cell / 2, cy = e.y * cell + cell / 2;
|
|
ctx.font = glyphFont;
|
|
ctx.fillStyle = e.color || '#fff';
|
|
// Dungeon features and entities use their own char/color.
|
|
if (e.kind === 'feature' || e.kind === 'item' || e.kind === 'monster') {
|
|
ctx.fillStyle = e.color || '#fff';
|
|
ctx.fillText(e.char || '?', cx, cy);
|
|
if (e.you) {
|
|
ctx.strokeStyle = '#ffffff';
|
|
ctx.lineWidth = 1;
|
|
ctx.strokeRect(e.x * cell + 2, e.y * cell + 2, cell - 4, cell - 4);
|
|
}
|
|
if (e.label) {
|
|
ctx.font = '10px monospace';
|
|
ctx.fillStyle = '#d7dbe0';
|
|
ctx.fillText(e.label, cx, e.y * cell - 1);
|
|
}
|
|
continue;
|
|
}
|
|
ctx.fillStyle = e.color || '#fff';
|
|
ctx.fillText(e.char || '@', cx, cy);
|
|
if (e.you) {
|
|
ctx.strokeStyle = '#ffffff';
|
|
ctx.lineWidth = 1;
|
|
ctx.strokeRect(e.x * cell + 2, e.y * cell + 2, cell - 4, cell - 4);
|
|
}
|
|
if (e.label) {
|
|
ctx.font = '10px monospace';
|
|
ctx.fillStyle = '#d7dbe0';
|
|
ctx.fillText(e.label, cx, e.y * cell - 1);
|
|
}
|
|
}
|
|
|
|
// Camera focus — centre the SP camera on the player cell (same convention as the tiled
|
|
// renderer). Sticky: only update when the player is present, so switching TO ascii mid-game
|
|
// doesn't leave focusPoint null (which pinned the whole grid to the corner → black screen).
|
|
for (var pj = 0; pj < scene.entities.length; pj++) {
|
|
var pe = scene.entities[pj];
|
|
if (pe.kind === 'player' || pe.you) {
|
|
this.focusPoint = { x: pe.x * cell + cell / 2, y: pe.y * cell + cell / 2 };
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
AsciiRenderer.prototype.destroy = function () {
|
|
if (this.canvas && this.canvas.parentNode) this.canvas.parentNode.removeChild(this.canvas);
|
|
this.canvas = null;
|
|
this.ctx = null;
|
|
};
|
|
|
|
root.RK = root.RK || {};
|
|
root.RK.AsciiRenderer = AsciiRenderer;
|
|
})(window);
|