Skip to content

Commit

Permalink
fix: Consider displaced hitboxes in GestureHitboxes mixin (#2957)
Browse files Browse the repository at this point in the history
Previously the point sent in to `containsLocalPoint` for
`GestureHitboxes` didn't take the parent transformation into
consideration, this is fixed in this PR.
  • Loading branch information
spydon authored Jan 4, 2024
1 parent 75cf239 commit 1085518
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@ mixin GestureHitboxes on Component {
return hitboxes.any((hitbox) => hitbox.containsPoint(point));
}

static final _temporaryPoint = Vector2.zero();

@override
bool containsLocalPoint(Vector2 point) {
return hitboxes.any((hitbox) => hitbox.containsLocalPoint(point));
return hitboxes.any(
(hitbox) => hitbox.containsLocalPoint(
hitbox.parentToLocal(point, output: _temporaryPoint),
),
);
}
}
6 changes: 4 additions & 2 deletions packages/flame/lib/src/components/position_component.dart
Original file line number Diff line number Diff line change
Expand Up @@ -273,10 +273,12 @@ class PositionComponent extends Component
}

@override
Vector2 parentToLocal(Vector2 point) => transform.globalToLocal(point);
Vector2 parentToLocal(Vector2 point, {Vector2? output}) =>
transform.globalToLocal(point, output: output);

@override
Vector2 localToParent(Vector2 point) => transform.localToGlobal(point);
Vector2 localToParent(Vector2 point, {Vector2? output}) =>
transform.localToGlobal(point, output: output);

/// Convert local coordinates of a point [point] inside the component
/// into the parent's coordinate space.
Expand Down
43 changes: 43 additions & 0 deletions packages/flame/test/components/mixins/gesture_hitboxes_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,49 @@ void main() {
expect(component.containsPoint(point), isTrue);
});

testWithFlameGame('CircleHitbox is displaced within the parent component',
(game) async {
final component = _HitboxComponent();
component.position.setAll(10);
component.size.setValues(2.0, 2.0);

final hitbox = CircleHitbox(
position: Vector2(1.0, 1.5),
radius: 0.5,
anchor: Anchor.center,
);

component.add(hitbox);
await game.ensureAdd(component);

final point = component.position + hitbox.position;
expect(component.containsPoint(point), isTrue);
final outsidePoint = component.position + Vector2(1.0, 0.99);
expect(component.containsPoint(outsidePoint), isFalse);
});

testWithFlameGame(
'RectangleHitbox is displaced within the parent component',
(game) async {
final component = _HitboxComponent();
component.position.setAll(10);
component.size.setValues(2.0, 2.0);

final hitbox = RectangleHitbox(
position: Vector2(1.0, 1.5),
size: Vector2.all(1.0),
anchor: Anchor.center,
);

component.add(hitbox);
await game.ensureAdd(component);

final point = component.position + hitbox.position;
expect(component.containsPoint(point), isTrue);
final outsidePoint = component.position + Vector2(1.0, 0.99);
expect(component.containsPoint(outsidePoint), isFalse);
});

testWithFlameGame('get component hitboxes', (game) async {
final component = _HitboxComponent();
component.position.setValues(1.0, 1.0);
Expand Down

0 comments on commit 1085518

Please sign in to comment.