Repository navigation
Defer spatial hash updates until the next query - #2977
Merged
Merged
Conversation
Moving, rotating or resizing a sprite in a hashed SpriteList removed it from the spatial hash and added it again, on every change. SpatialHash now only marks it as moved; the next query updates each moved sprite once and skips sprites still in the same cells. Moving 5,000 hashed sprites went from 36 to 8 ms per frame (39 to 22 ms with a collision check after); queries with nothing moving cost the same. contents and buckets_for_sprite become properties that apply pending moves first, so code reading them still sees current data. Also corrects the performance tips, which said hashing doubles the cost of moving, and fixes a benchmark that used removed method names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pvcraven
force-pushed
the
deferred-spatial-hash
branch
from
October 9, 2026 21:26
a145e98 to
3d0c5f1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1568
#1568 had four parts. Two were done in #2894–#2900: cached hit box radius, bounds and axes, and
HitBoxas its own class. Sharing one hit box per texture is worth little now that those caches exist, so it's left out. This PR does the remaining valid part, deferring spatial hash updates when sprites move.The problem
Each change to
center_x,center_y,angle, scale or texture of a sprite in a hashedSpriteListcalledSpatialHash.move(), which removed the sprite and added it again. Each add also forced the hit box's adjusted points to be recalculated. Moving a sprite's x and then its y re-added it twice per frame, even if it stayed in the same cells and nothing ever checked for collisions.The change (all in
arcade/sprite_list/spatial_hash.py)move()only adds the sprite to a set of moved sprites.get_sprites_near_sprite,get_sprites_near_point,get_sprites_near_rect) first put each moved sprite in its new cells. A sprite whose cell range hasn't changed is skipped, using a stored (min, max) cell pair per sprite.remove()drops a sprite from the moved set, andreset()clears it.contentsandbuckets_for_spriteare now properties that apply pending moves first, so code reading them, including the existing tests, sees current data. The class keeps the same public names, so nothing breaks.Sprite code is unchanged; it still calls
update_spatial_hash(). Rendering doesn't go through the hash, so drawing isn't affected.Measured (5,000 16×16 sprites in a 1000×1000 area, default cell size)
center_x += 1,center_y += 1)check_for_collision_with_listCollision checks with nothing moving cost the same: three alternating runs gave 92–97 µs per check both before and after.
Also
benchmarks/spatial_hash/add_remove_vs_move.pyusedinsert_object_for_boxandremove_object, which no longer exist. It now usesadd/remove, and queries once after moving so the moves are applied.Tests
tests/unit/spritelist/test_spatial_hash_moves.py:contentsandbuckets_for_spritereflect movesreset()forgets pending movesOn
development, the two tests that measure re-adds fail and the other five pass.The full test suite (1858), ruff, mypy, pyright and
make.py docs-fullpass. 8 examples that use spatial hashes run without errors: platformers, walls, rooms, moving platforms, the bullet sweep and the camera platformer.🤖 Generated with Claude Code