Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/melonjs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
- **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.

### Fixed
- 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)
- WebGL: depth buffer now correctly used for 3D mesh rendering with `gl.LESS` depth function
- Canvas: backface culling corrected for Y-flipped screen space (was culling front faces instead of back)
- Canvas: triangle seam expansion (0.5px) to cover anti-aliasing gaps between adjacent triangles
Expand Down
2 changes: 2 additions & 0 deletions packages/melonjs/src/geometries/rectangle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export class Rect extends Polygon {
this.points[1].set(width, 0); // 1, 0
this.points[2].set(width, height); // 1, 1
this.points[3].set(0, height); // 0, 1
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rect.setSize() mutates points but does not call recalc(). That leaves edges, normals, and indices potentially stale for SAT/collision queries on rectangles that are resized via setSize() (unlike the width/height setters which do recalc() + updateBounds()). Consider calling this.recalc() before this.updateBounds() here to keep the polygon's derived data consistent after resizing.

Suggested change
this.points[3].set(0, height); // 0, 1
this.points[3].set(0, height); // 0, 1
this.recalc();

Copilot uses AI. Check for mistakes.
this.recalc();
this.updateBounds();
return this;
}

Expand Down
52 changes: 52 additions & 0 deletions packages/melonjs/tests/rectangle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,56 @@ describe("Shape : Rect", () => {
expect(rect6.isFinite()).toEqual(false);
});
});

describe("setSize", () => {
it("should update bounds when setSize is called", () => {
const rect = new Rect(0, 0, 10, 10);
rect.setSize(50, 30);
const bounds = rect.getBounds();
expect(bounds.width).toEqual(50);
expect(bounds.height).toEqual(30);
});

it("should reflect position in bounds after pos.set + setSize", () => {
const rect = new Rect(0, 0, 1, 1);
rect.pos.set(100, 200);
rect.setSize(50, 30);
const bounds = rect.getBounds();
expect(bounds.x).toEqual(100);
expect(bounds.y).toEqual(200);
expect(bounds.width).toEqual(50);
expect(bounds.height).toEqual(30);
});

it("should update bounds when only setSize is called after construction", () => {
const rect = new Rect(500, 300, 1, 1);
rect.setSize(20, 15);
const bounds = rect.getBounds();
expect(bounds.x).toEqual(500);
expect(bounds.y).toEqual(300);
expect(bounds.width).toEqual(20);
expect(bounds.height).toEqual(15);
});

it("should recalculate edges and normals after setSize", () => {
const rect = new Rect(0, 0, 10, 10);
rect.setSize(50, 30);
// edges should reflect the new dimensions
expect(rect.edges[0].x).toEqual(50); // top edge
expect(rect.edges[1].y).toEqual(30); // right edge
});
});

describe("copy", () => {
it("should update bounds after copy", () => {
const src = new Rect(100, 200, 50, 30);
const dst = new Rect(0, 0, 1, 1);
dst.copy(src);
const bounds = dst.getBounds();
expect(bounds.x).toEqual(100);
expect(bounds.y).toEqual(200);
expect(bounds.width).toEqual(50);
expect(bounds.height).toEqual(30);
});
});
});
34 changes: 34 additions & 0 deletions packages/melonjs/tests/roundrect.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,40 @@ describe("Shape : RoundRect", () => {
});
});

describe("bounds updates", () => {
it("should update bounds after setSize", () => {
const rr = new RoundRect(100, 200, 50, 30, 10);
rr.setSize(80, 60);
const bounds = rr.getBounds();
expect(bounds.x).toEqual(100);
expect(bounds.y).toEqual(200);
expect(bounds.width).toEqual(80);
expect(bounds.height).toEqual(60);
});

it("should update bounds after pos.set + setSize", () => {
const rr = new RoundRect(0, 0, 1, 1, 0);
rr.pos.set(300, 400);
rr.setSize(50, 30);
const bounds = rr.getBounds();
expect(bounds.x).toEqual(300);
expect(bounds.y).toEqual(400);
expect(bounds.width).toEqual(50);
expect(bounds.height).toEqual(30);
});

it("should update bounds after copy", () => {
const src = new RoundRect(100, 200, 80, 60, 15);
const dst = new RoundRect(0, 0, 1, 1, 0);
dst.copy(src);
const bounds = dst.getBounds();
expect(bounds.x).toEqual(100);
expect(bounds.y).toEqual(200);
expect(bounds.width).toEqual(80);
expect(bounds.height).toEqual(60);
});
});

describe("vertex reuse optimization", () => {
it("should reuse vertex objects when radius stays > 0 and size changes", () => {
const rr = new RoundRect(0, 0, 100, 100, 20);
Expand Down
Loading