Skip to content

Commit 219e7e7

Browse files
obiotclaude
andauthored
Fix Rect.setSize() not updating bounds (pointer event regression) (#1373)
* Fix Rect.setSize() not updating bounds (regression from TS conversion) Rect.setSize() did not call updateBounds(), leaving bounds stale after position or size changes. This broke pointer event broadphase lookups: the QuadTree query rect always reported bounds at (0,0) instead of the actual click position, causing moles at certain positions in the whack-a-mole example to not respond to clicks. Root cause: commit 4d185c9 (July 2024) replaced Rect.setShape(x,y,w,h) with pos.set() + setSize() during the TypeScript conversion, but setSize() never called updateBounds(). The old setShape() updated everything in one call. See #817 for the underlying pos type mismatch. Fix: add updateBounds() call in Rect.setSize(). Tests: add bounds validation tests for Rect.setSize(), pos.set()+setSize(), Rect.copy(), and RoundRect equivalents. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add recalc() call in Rect.setSize() for edge/normal consistency setSize() now calls recalc() before updateBounds(), matching the behavior of the width/height setters. Without this, edges, normals, and indices were stale after setSize(), which could cause incorrect SAT/collision results on resized rectangles. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4315fc5 commit 219e7e7

4 files changed

Lines changed: 89 additions & 0 deletions

File tree

packages/melonjs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
- **BREAKING**: `Tween` no longer adds itself to `game.world` — uses event-based lifecycle (`TICK`, `GAME_AFTER_UPDATE`, `STATE_PAUSE`, `STATE_RESUME`, `GAME_RESET`) instead. Public API unchanged. `isPersistent` and `updateWhenPaused` properties still supported.
4040

4141
### Fixed
42+
- Geometry: `Rect.setSize()` now calls `updateBounds()` — fixes a regression from July 2024 (`4d185c902`) where replacing `Rect.setShape()` with `pos.set()` + `setSize()` during the TypeScript conversion left bounds stale, causing pointer event broadphase lookups to use `(0,0)` instead of the actual pointer position (see #817)
4243
- WebGL: depth buffer now correctly used for 3D mesh rendering with `gl.LESS` depth function
4344
- Canvas: backface culling corrected for Y-flipped screen space (was culling front faces instead of back)
4445
- Canvas: triangle seam expansion (0.5px) to cover anti-aliasing gaps between adjacent triangles

packages/melonjs/src/geometries/rectangle.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export class Rect extends Polygon {
3838
this.points[1].set(width, 0); // 1, 0
3939
this.points[2].set(width, height); // 1, 1
4040
this.points[3].set(0, height); // 0, 1
41+
this.recalc();
42+
this.updateBounds();
4143
return this;
4244
}
4345

packages/melonjs/tests/rectangle.spec.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,56 @@ describe("Shape : Rect", () => {
241241
expect(rect6.isFinite()).toEqual(false);
242242
});
243243
});
244+
245+
describe("setSize", () => {
246+
it("should update bounds when setSize is called", () => {
247+
const rect = new Rect(0, 0, 10, 10);
248+
rect.setSize(50, 30);
249+
const bounds = rect.getBounds();
250+
expect(bounds.width).toEqual(50);
251+
expect(bounds.height).toEqual(30);
252+
});
253+
254+
it("should reflect position in bounds after pos.set + setSize", () => {
255+
const rect = new Rect(0, 0, 1, 1);
256+
rect.pos.set(100, 200);
257+
rect.setSize(50, 30);
258+
const bounds = rect.getBounds();
259+
expect(bounds.x).toEqual(100);
260+
expect(bounds.y).toEqual(200);
261+
expect(bounds.width).toEqual(50);
262+
expect(bounds.height).toEqual(30);
263+
});
264+
265+
it("should update bounds when only setSize is called after construction", () => {
266+
const rect = new Rect(500, 300, 1, 1);
267+
rect.setSize(20, 15);
268+
const bounds = rect.getBounds();
269+
expect(bounds.x).toEqual(500);
270+
expect(bounds.y).toEqual(300);
271+
expect(bounds.width).toEqual(20);
272+
expect(bounds.height).toEqual(15);
273+
});
274+
275+
it("should recalculate edges and normals after setSize", () => {
276+
const rect = new Rect(0, 0, 10, 10);
277+
rect.setSize(50, 30);
278+
// edges should reflect the new dimensions
279+
expect(rect.edges[0].x).toEqual(50); // top edge
280+
expect(rect.edges[1].y).toEqual(30); // right edge
281+
});
282+
});
283+
284+
describe("copy", () => {
285+
it("should update bounds after copy", () => {
286+
const src = new Rect(100, 200, 50, 30);
287+
const dst = new Rect(0, 0, 1, 1);
288+
dst.copy(src);
289+
const bounds = dst.getBounds();
290+
expect(bounds.x).toEqual(100);
291+
expect(bounds.y).toEqual(200);
292+
expect(bounds.width).toEqual(50);
293+
expect(bounds.height).toEqual(30);
294+
});
295+
});
244296
});

packages/melonjs/tests/roundrect.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,40 @@ describe("Shape : RoundRect", () => {
367367
});
368368
});
369369

370+
describe("bounds updates", () => {
371+
it("should update bounds after setSize", () => {
372+
const rr = new RoundRect(100, 200, 50, 30, 10);
373+
rr.setSize(80, 60);
374+
const bounds = rr.getBounds();
375+
expect(bounds.x).toEqual(100);
376+
expect(bounds.y).toEqual(200);
377+
expect(bounds.width).toEqual(80);
378+
expect(bounds.height).toEqual(60);
379+
});
380+
381+
it("should update bounds after pos.set + setSize", () => {
382+
const rr = new RoundRect(0, 0, 1, 1, 0);
383+
rr.pos.set(300, 400);
384+
rr.setSize(50, 30);
385+
const bounds = rr.getBounds();
386+
expect(bounds.x).toEqual(300);
387+
expect(bounds.y).toEqual(400);
388+
expect(bounds.width).toEqual(50);
389+
expect(bounds.height).toEqual(30);
390+
});
391+
392+
it("should update bounds after copy", () => {
393+
const src = new RoundRect(100, 200, 80, 60, 15);
394+
const dst = new RoundRect(0, 0, 1, 1, 0);
395+
dst.copy(src);
396+
const bounds = dst.getBounds();
397+
expect(bounds.x).toEqual(100);
398+
expect(bounds.y).toEqual(200);
399+
expect(bounds.width).toEqual(80);
400+
expect(bounds.height).toEqual(60);
401+
});
402+
});
403+
370404
describe("vertex reuse optimization", () => {
371405
it("should reuse vertex objects when radius stays > 0 and size changes", () => {
372406
const rr = new RoundRect(0, 0, 100, 100, 20);

0 commit comments

Comments
 (0)