diff --git a/html/js/render/spGameRenderer.js b/html/js/render/spGameRenderer.js index 41118f9..03cbbcb 100644 --- a/html/js/render/spGameRenderer.js +++ b/html/js/render/spGameRenderer.js @@ -102,15 +102,12 @@ var r = SP._renderer; var host = doc() && doc().getElementById('rk-game-host'); if (!r || !r.canvas || !host) return; - // The 3D renderer drives its OWN THREE camera and sizes its canvas to the level, so a - // player-follow CSS transform would zoom/crop it wrongly. Instead scale-to-FIT the whole - // canvas into the host and centre it (no player follow) — a sane, non-broken view. + // The 3D renderer fills the host itself (setSize) and its OWN THREE camera follows the + // player — so DON'T apply a CSS transform (it would double-transform the WebGL view). if (r.name === '3d') { - var cw = r.canvas.width || 1, ch = r.canvas.height || 1; - var hw3 = host.clientWidth || host.offsetWidth || 640, hh3 = host.clientHeight || host.offsetHeight || 400; - var fit = Math.min(hw3 / cw, hh3 / ch); - r.canvas.style.transformOrigin = '0 0'; - r.canvas.style.transform = 'translate(' + ((hw3 - cw * fit) / 2) + 'px,' + ((hh3 - ch * fit) / 2) + 'px) scale(' + fit + ')'; + r.canvas.style.transform = 'none'; + r.canvas.style.left = '0'; + r.canvas.style.top = '0'; return; } var scale = SP._zoom || 1.7; diff --git a/html/js/render/threeRenderer.js b/html/js/render/threeRenderer.js index fe4bf49..9131343 100644 --- a/html/js/render/threeRenderer.js +++ b/html/js/render/threeRenderer.js @@ -50,11 +50,17 @@ this._raf = requestAnimationFrame(function tick() { self._animate(); self._raf = requestAnimationFrame(tick); }); }; - ThreeRenderer.prototype._resize = function (scene) { - var w = Math.max(420, scene.cols * 32); - var h = Math.max(360, scene.rows * 28 + 120); - this.renderer.setSize(w, h, false); - var aspect = w / h, span = Math.max(scene.cols, scene.rows) * 0.78 + 2.5; + // Fill the host and frame a fixed "screenful" around the player. The camera FOLLOWS the player + // (see _animate) instead of framing the whole level, so 3D behaves like the other modes. Only + // does work when the host size actually changed (cheap to call every frame). + ThreeRenderer.prototype._fitToHost = function () { + var host = this.host; + var w = (host && (host.clientWidth || host.offsetWidth)) || 640; + var h = (host && (host.clientHeight || host.offsetHeight)) || 400; + if (w === this._cw && h === this._ch) return; + this._cw = w; this._ch = h; + this.renderer.setSize(w, h, true); // updateStyle:true → the canvas CSS-fills the host + var aspect = w / h, span = 8; // fixed zoom = a screenful around the player this.camera.left = -span * aspect; this.camera.right = span * aspect; this.camera.top = span; @@ -219,7 +225,7 @@ ThreeRenderer.prototype.render = function (scene) { if (!scene || !this.renderer) return; - this._resize(scene); + this._fitToHost(); var key = scene.cols + 'x' + scene.rows + ':' + scene.grid.map(function (r) { return r.join(''); }).join('/'); if (key !== this._sizeKey) { this._buildTiles(scene); @@ -273,6 +279,19 @@ o.rotation.y += (r - o.rotation.y) * 0.18; } } + + // Player-follow camera: keep the fixed iso offset (8,9,8) but re-target the player's world + // position each frame. The player mesh itself lerps, so the camera glides smoothly with it. + this._fitToHost(); // pick up any host resize + var pcam = null; + for (var pid in this.entities) { + var pen = this.entities[pid]; + if (pen.e && (pen.e.you || pen.e.kind === 'player')) { pcam = pen.obj; break; } + } + if (pcam) { + this.camera.position.set(pcam.position.x + 8, 9, pcam.position.z + 8); + this.camera.lookAt(pcam.position.x, 0, pcam.position.z); + } this.renderer.render(this.scene, this.camera); };