diff --git a/html/js/render/isoRenderer.js b/html/js/render/isoRenderer.js index ce3ba83..d4d0066 100644 --- a/html/js/render/isoRenderer.js +++ b/html/js/render/isoRenderer.js @@ -83,6 +83,20 @@ return null; }; + // A stroked iso diamond outline — used to flag the floor cells the player can actually step to, + // so ambiguous wall gaps are never mistaken for openings. + IsoRenderer.prototype._diamondOutline = function (cx, cy, color) { + var ctx = this.ctx, hw = this.tileW / 2, hh = this.tileH / 2; + ctx.save(); + ctx.beginPath(); + ctx.moveTo(cx, cy - hh); ctx.lineTo(cx + hw, cy); ctx.lineTo(cx, cy + hh); ctx.lineTo(cx - hw, cy); + ctx.closePath(); + ctx.lineWidth = 2.5; + ctx.strokeStyle = color; + ctx.stroke(); + ctx.restore(); + }; + // Draw a text glyph centered at a projected cell (feature fallback when no pack tile fits). IsoRenderer.prototype._glyph = function (cx, cy, ch, color) { var ctx = this.ctx; @@ -402,6 +416,25 @@ } } } + + // Walkability affordance: the iso wall tiles leave ambiguous gaps that read as doorways, so + // flag the floor cells the player can actually step to (orthogonally adjacent, walkable + + // explored) with a soft pulsing outline — a reliable "you can go here" cue independent of how + // the walls render. + if (this._plx != null) { + var pulse = 0.30 + Math.sin(now / 320) * 0.18; + var nbrs = [[0, -1], [0, 1], [-1, 0], [1, 0]]; + for (var ni = 0; ni < nbrs.length; ni++) { + var nx = this._plx + nbrs[ni][0], ny = this._ply + nbrs[ni][1]; + if (ny < 0 || nx < 0 || !scene.grid[ny] || nx >= scene.cols) continue; + var nk = scene.grid[ny][nx]; + if (nk === 'wall' || nk === 'dark' || nk === 'torch' || nk === undefined) continue; + var np = this._project(nx, ny, originX, originY); + this._diamondOutline(np.x, np.y + this.tileH * 0.5, 'rgba(130,220,255,' + pulse + ')'); + } + this._animating = true; // keep the pulse animating between game updates + } + this._vignette(); if (this._animating) this._invalidate(); };