Skip to content

Rework HitBox to support multiple named collision regions#2835

Open
Cleptomania wants to merge 3 commits intodevelopmentfrom
hitbox-rework
Open

Rework HitBox to support multiple named collision regions#2835
Cleptomania wants to merge 3 commits intodevelopmentfrom
hitbox-rework

Conversation

@Cleptomania
Copy link
Member

@Cleptomania Cleptomania commented Mar 12, 2026

Summary

  • Replaces the single-polygon HitBox with a multi-region system where each HitBox can contain named Point2List regions (e.g. separate head/body/feet hitboxes), while maintaining backward compatibility with the single-region API
  • Adds per-region collision channel/mask filtering using bitmasks. Each region has a channel (what it is) and mask (what it collides with). Collision requires bidirectional agreement: (A.channel & B.mask) != 0 AND (B.channel & A.mask) != 0
  • Provides channels() utility to convert 1-based channel numbers to bitmasks (e.g. channels(1, 3) = 0b101)
  • Introduces RawHitBoxRegion TypedDict and bumps serialization to v2 format (with v1 backward compat), supporting channel and mask fields per region
  • Merges RotatableHitBox into HitBox and adds JSON serialization support (with optional gzip compression)
  • Updates collision detection, pymunk physics engine, sprite lists, and tilemap to work with multi-region hitboxes
  • Normalizes all points to tuples of tuples internally for immutability and consistency, while still accepting any valid sequence as input
  • Updates sprite_multi_hitbox example to demonstrate channel-based collision filtering (body catches coins on channel 1, shield catches gems on channel 2)
  • Expanded test coverage including 15 new channel/mask tests

Test plan

  • Run hitbox unit tests (tests/unit/hitbox/test_hitbox.py) — all 34 pass
  • Run GUI tests to verify formatting fixes don't break anything
  • Verify pymunk physics engine works with multi-region hitboxes
  • Test the sprite_multi_hitbox example (coins only hit body, gems only hit shield)
  • Confirm backward compatibility with single-region hitbox usage
  • Confirm v1 serialization format loads correctly in v2 code

🤖 Generated with Claude Code

Replaces the single-polygon HitBox with a multi-region system where each
HitBox can contain named Point2List regions. This enables sprites to have
distinct collision shapes (e.g. separate head/body/feet hitboxes) while
maintaining backward compatibility with the single-region API.

Key changes:
- HitBox accepts either a Point2List (single "default" region) or a
  dict[str, Point2List] mapping region names to point lists
- Merge RotatableHitBox into HitBox (removed RotatableHitBox)
- Add serialization support (save/load to JSON, with gzip option)
- Update collision detection, pymunk physics, sprite lists, and tilemap
  to work with multi-region hitboxes
- Add sprite_multi_hitbox example
- Fix type annotations for pyright/mypy compatibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Cleptomania
Copy link
Member Author

Cleptomania commented Mar 12, 2026

Right now this has a re-work that gets rid of the split between HitBox and RotatableHitBox. Originally this split was decided on because hitboxes are expensive to rotate, but in practice we've not really realized any gains from this, and everything is nearly universally always using RotatableHitBox anyways, so I think this split is not worth the headaches it has caused.

In addition to removing that split, it supports multiple polygons per hitbox, and they can be named. Yet to be done is to allow the collision detects to report what regions were collided, so you could do things like check if a head region or an arm region were hit. Obviously using multiple regions will incur a greater performance hit, as the check is a similar cost per region, but this can potentially save users from needing to manage things by composing a character or something out of multiple sprites.

The new hitboxes also support being loaded from JSON, I have plans to build an editor for creating these points, but that is not done yet.

Another thing yet to be done, is to update the Tilemap loading to support loading multiple regions from Tiled objects, this is something Tiled supports but Arcade has historically ignored. I will have to investigate how the region naming should work for loading these, but I believe the objects in Tiled can be given names, so that will probably be the way to go.

Cleptomania and others added 2 commits March 12, 2026 11:26
Add a RawHitBox TypedDict for typed serialization in to_dict/from_dict.
Normalize all points to tuples of tuples on construction, add_region,
and in adjusted point calculation for immutability and consistency.
Update tests to expect tuple-based comparisons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each hitbox region can now have a channel (what it is) and mask (what
it collides with) bitmask. Collision only occurs when both sides agree:
(A.channel & B.mask) != 0 AND (B.channel & A.mask) != 0.

Adds channels() utility for converting 1-based channel numbers to
bitmasks, RawHitBox v2 serialization format, and updates the
multi-hitbox example to demonstrate channel-based filtering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

2 participants