Skip to content

Add rect_overlap and sprite_overlap collision detection helpers#439

Merged
jonathanpeppers merged 4 commits intomainfrom
add-rect-overlap
Apr 14, 2026
Merged

Add rect_overlap and sprite_overlap collision detection helpers#439
jonathanpeppers merged 4 commits intomainfrom
add-rect-overlap

Conversation

@jonathanpeppers
Copy link
Copy Markdown
Owner

Add two new NESLib collision detection APIs as described in #421:

  • rect_overlap(x1, y1, w1, h1, x2, y2, w2, h2) — Full AABB rectangle overlap test. Returns true if two axis-aligned rectangles overlap. Uses unsigned byte arithmetic, suitable for NES screen coordinates.

  • sprite_overlap(x1, y1, x2, y2, threshold) — Distance-based collision for same-size sprites. Returns true if the unsigned absolute difference on both axes is less than the threshold.

Both are implemented as 6502 subroutines that read arguments directly from the cc65 parameter stack via indirect indexed addressing, avoiding expensive per-arg popa calls. They depend on addysp for stack cleanup.

Changes

  • src/neslib/NESLib.cs — Added method stubs with XML docs
  • src/dotnes.tasks/ObjectModel/BuiltInSubroutines.cs — 6502 assembly implementations
  • src/dotnes.tasks/ObjectModel/Program6502.cs — Registered in ForEachOptionalBuiltIn with addysp dependency
  • samples/climber/Program.cs — Replaced manual byte-distance collision with sprite_overlap
  • samples/pong/Program.cs — Replaced nested paddle collision checks with rect_overlap
  • Updated test DLLs and verified snapshots

Before/After (climber)

// Before: ~7 lines of manual collision
byte dx = (byte)(actor_x[0] - actor_x[ci]);
if (dx >= 248) dx = (byte)(0 - dx);
byte dyl = (byte)(actor_yy_lo[0] - actor_yy_lo[ci]);
if (dyl >= 248) dyl = (byte)(0 - dyl);
if (dx < 8 && dyl < 8) { collided = 1; }

// After: 1 line
if (sprite_overlap(actor_x[0], actor_yy_lo[0], actor_x[ci], actor_yy_lo[ci], 8))
{ collided = 1; }

Before/After (pong)

// Before: 16 lines of nested ifs per paddle
if (ball_x < 24) {
    if (ball_right == 0) {
        if (ball_y >= p1_y) {
            byte p1_end = (byte)(p1_y + 24);
            if (ball_y < p1_end) { ... }
        }
    }
}

// After: 1 line per paddle
if (ball_right == 0 && rect_overlap(ball_x, ball_y, 8, 8, 16, p1_y, 8, 24))
{ ... }

Closes #421

Copilot AI review requested due to automatic review settings April 3, 2026 03:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Add two new NESLib collision detection APIs:
- rect_overlap(x1, y1, w1, h1, x2, y2, w2, h2) for AABB rectangle overlap
- sprite_overlap(x1, y1, x2, y2, threshold) for distance-based same-size sprite collision

Both return bool (0/1 in A register) and are implemented as 6502 subroutines
that read arguments directly from the cc65 parameter stack for efficiency.

Updated samples:
- climber: replaced manual byte-distance collision with sprite_overlap
- pong: replaced nested paddle collision checks with rect_overlap

Closes #421

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

The transpiler's HandleLdelemU1 saves prior values to a single TEMP
register, not the cc65 parameter stack. When multiple array accesses
are chained as function arguments, values get overwritten. Fix by
storing array element values in local variables before the call,
which uses WriteLdloc's pusha emission path instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 6 out of 12 changed files in this pull request and generated 3 comments.

Comment thread samples/pong/Program.cs Outdated
Comment thread src/dotnes.tasks/ObjectModel/BuiltInSubroutines.cs
Comment thread src/neslib/NESLib.cs Outdated
jonathanpeppers and others added 2 commits April 13, 2026 18:33
The transpiler's default Call path never handled multi-argument NESLib
method calls correctly - all existing multi-arg NESLib methods used
dedicated intrinsic handlers. Adding rect_overlap (8 args) and
sprite_overlap (5 args) exposed this gap.

Transpiler fixes:
- Add IsDefaultCallPathTarget/ScanForUpcomingMultiArgCall helpers to
  detect when a value load precedes a multi-arg call
- Extend WriteLdloc, WriteLdc(byte), HandleLdsfld to emit JSR pusha
  for arguments destined for default-path calls
- Extend HandleLdelemU1 to emit JSR pusha when array element values
  are arguments for upcoming multi-arg calls
- Extend ScanForUpcomingMultiArgCall to handle ldelem_u1 and stloc
  opcodes in the forward scan

Test updates:
- Increase pusha balance test window from 8 to 20 instructions to
  handle ldelem_u1 pushes that occur far before the call site
- Rebuild test DLLs and accept updated verified.bin snapshots

Verified via disassembly (4 JSR pusha + A = 5 args for sprite_overlap)
and Mesen2 runtime screenshots showing correct rendering.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…dition

- Add cheap ball_x range guard before rect_overlap calls in pong to
  avoid unnecessary JSR+stack traffic when ball is far from paddles
- Update rect_overlap XML docs to document that x+w and y+h must not
  wrap past 255 (8-bit arithmetic precondition)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers jonathanpeppers merged commit 0dad921 into main Apr 14, 2026
3 checks passed
@jonathanpeppers jonathanpeppers deleted the add-rect-overlap branch April 14, 2026 01:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add rect_overlap collision detection helper

2 participants