From 1c3595cb5be803fe1325de65017d250e53b739cd Mon Sep 17 00:00:00 2001 From: Mistium <92952823+Mistium@users.noreply.github.com> Date: Thu, 24 Sep 2026 02:35:47 +0100 Subject: [PATCH] Tolerate a drawable without a skin when fencing a position A target can move while its skin is still loading or after the skin was destroyed. getFencedPositionOfDrawable already tolerated a missing drawable but dereferenced the skin unconditionally, so a "go to" block on such a target threw "Cannot read properties of undefined (reading 'getFenceBounds')". Keep the requested position when there is nothing to fence against. Co-Authored-By: Claude Fable 5.1 --- src/RenderWebGL.js | 9 ++++++++- test/unit/RenderWebGLOptimizationTests.js | 8 ++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/RenderWebGL.js b/src/RenderWebGL.js index 28fec5f7e..54bb09cf8 100644 --- a/src/RenderWebGL.js +++ b/src/RenderWebGL.js @@ -1880,9 +1880,16 @@ class RenderWebGL extends EventEmitter { return [x, y]; } + const skin = drawable._skin; + if (!skin) { + // A target can move while its skin is still loading or after it was destroyed. + // There is nothing to fence against, so keep the requested position. + return [x, y]; + } + const dx = x - drawable._position[0]; const dy = y - drawable._position[1]; - const aabb = drawable._skin.getFenceBounds(drawable, __fenceBounds); + const aabb = skin.getFenceBounds(drawable, __fenceBounds); const inset = Math.floor(Math.min(aabb.width, aabb.height) / 2); const sx = this._xRight - Math.min(FENCE_WIDTH, inset); diff --git a/test/unit/RenderWebGLOptimizationTests.js b/test/unit/RenderWebGLOptimizationTests.js index 2711883af..dcab93a2b 100644 --- a/test/unit/RenderWebGLOptimizationTests.js +++ b/test/unit/RenderWebGLOptimizationTests.js @@ -40,3 +40,11 @@ test('skin sizes tolerate asynchronous loading and destroyed skins', t => { t.same(renderer.getSkinSize(123), [0, 0]); t.end(); }); + +test('fencing keeps the requested position while a drawable has no skin', t => { + const renderer = Object.create(RenderWebGL.prototype); + renderer._allDrawables = [{_position: [0, 0], _skin: null}]; + t.same(renderer.getFencedPositionOfDrawable(0, [500, -400]), [500, -400]); + t.same(renderer.getFencedPositionOfDrawable(7, [12, 34]), [12, 34]); + t.end(); +});