Skip to content

Fix GPU collision missing sprites flipped with negative scale - #2907

Merged
pvcraven merged 1 commit into
developmentfrom
fix/gpu-collision-flipped-sprites
Oct 1, 2026
Merged

pvcraven merged 1 commit into
developmentfrom
fix/gpu-collision-flipped-sprites

Conversation

@pvcraven

@pvcraven pvcraven commented Oct 1, 2026

Copy link
Copy Markdown
Member

Problem

The GPU collision path (CollisionMethod.GPU, also used automatically by AUTO for lists over 1500 sprites without a spatial hash) finds nearby sprites with a geometry shader that compared sizes with:

vec2 size = max(size[0], check_size);

A sprite flipped with a negative scale has a negative width or height. So max() picked the other sprite's size, and a flipped sprite could be dropped even when it overlapped. This is the GPU counterpart of the CPU fix in #2892.

wall = arcade.SpriteSolidColor(200, 20)   # bullet at x=80 is inside its right end
wall.scale = (-1, 1)
check_for_collision_with_list(bullet, walls, method=CollisionMethod.GPU)
# development: []   this PR: [wall]   (SIMPLE: [wall])

Fix

max(abs(size[0]), abs(check_size)) in both versions of the shader:

  • col_trans_gs.glsl: the buffer version, used by desktop OpenGL sprite lists.
  • col_tex_trans_gs.glsl: the texture version, only used by the texture-based sprite list storage. That storage is currently only used on WebGL, where GPU collision is disabled, so nothing reaches this shader today. I fixed it anyway so the two stay in sync.

Tests

  • test_gpu_collision_flipped_sprites: a long wall and a small bullet near its end, using get_nearby_sprites_gpu and check_for_collision_with_list(method=GPU). It covers six scale combinations: not flipped, the wall flipped in x, y, or both, the bullet flipped, and both flipped. It also checks that a far-away bullet still isn't found. It's skipped on WebGL.
    • On development the three cases with the wall flipped horizontally fail. The others already passed, because the wall's height or the bullet's size happened to be large enough, so they're kept as coverage.
  • Texture shader: checked manually, since no code path reaches it. I put SpriteListTextureData storage into a sprite list on desktop GL and called get_nearby_sprites_gpu. With the old shader, the flipped walls were missed (0 found); with the fix, they're found (1 found), and a far-away point still finds nothing.
  • Full suite on pyglet 3.0.dev11: 1405 passed. The 3 failures are the render tests that only fail on my machine.

🤖 Generated with Claude Code

The GPU collision geometry shaders compared sizes with
max(size[0], check_size). A sprite flipped with a negative scale has a
negative width or height, so max() picked the other sprite's size and
the flipped sprite could be rejected even when the two overlapped. This
is the GPU counterpart of #2892.

Use abs() on both sizes, in the buffer and texture versions of the
shader.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pvcraven
pvcraven merged commit 6c704b7 into development Oct 1, 2026
7 checks passed
@pvcraven
pvcraven deleted the fix/gpu-collision-flipped-sprites branch October 1, 2026 19:57
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.

1 participant