Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Ray should not be able to escape CircleHitbox #3341

Merged
merged 2 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions packages/flame/lib/src/collisions/hitboxes/circle_hitbox.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ class CircleHitbox extends CircleComponent with ShapeHitbox {
// the parent size and the radius is defined from the shortest side.
}

late final _temporaryLineSegment = LineSegment.zero();
late final _temporaryNormal = Vector2.zero();
late final _temporaryCenter = Vector2.zero();
late final _temporaryAbsoluteCenter = Vector2.zero();
static final _temporaryLineSegment = LineSegment.zero();
static final _temporaryNormal = Vector2.zero();
static final _temporaryCenter = Vector2.zero();
static final _temporaryAbsoluteCenter = Vector2.zero();
static final _temporaryOrigin = Vector2.zero();

@override
RaycastResult<ShapeHitbox>? rayIntersection(
Expand All @@ -56,6 +57,13 @@ class CircleHitbox extends CircleComponent with ShapeHitbox {
}) {
var isInsideHitbox = false;
_temporaryLineSegment.from.setFrom(ray.origin);
// Adding a small value to the origin to avoid the ray to be on the edge
// of the circle and then directly intersecting and causing the reflecting
// ray to go in the wrong direction.
_temporaryOrigin.setValues(
ray.origin.x + ray.direction.x * 0.00001,
Copy link
Member

Choose a reason for hiding this comment

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

should we put that into an epsilon?

ray.origin.y + ray.direction.y * 0.00001,
);
_temporaryAbsoluteCenter.setFrom(absoluteCenter);
_temporaryCenter
..setFrom(_temporaryAbsoluteCenter)
Expand All @@ -73,7 +81,7 @@ class CircleHitbox extends CircleComponent with ShapeHitbox {
..y *= (ray.direction.y.sign * _temporaryLineSegment.to.y.sign);
}

if (ray.origin.distanceToSquared(_temporaryAbsoluteCenter) <
if (_temporaryOrigin.distanceToSquared(_temporaryAbsoluteCenter) <
radius * radius) {
_temporaryLineSegment.to.scaleTo(2 * radius);
isInsideHitbox = true;
Expand Down Expand Up @@ -105,7 +113,10 @@ class CircleHitbox extends CircleComponent with ShapeHitbox {
origin: intersectionPoint,
direction: reflectionDirection,
)) ??
Ray2(origin: intersectionPoint, direction: reflectionDirection);
Ray2(
origin: intersectionPoint,
direction: reflectionDirection,
);

result.setWith(
hitbox: this,
Expand Down
25 changes: 25 additions & 0 deletions packages/flame/test/collisions/collision_detection_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1804,6 +1804,31 @@ void main() {
expect(reflectionRay2?.origin, Vector2(50, 0));
expect(reflectionRay2?.direction, Vector2(1, 1)..normalize());
},
'make sure that ray does not escape circle hitbox': (game) async {
final world = (game as FlameGame).world;
final circle = CircleComponent(
position: Vector2(0, 0),
radius: 5,
anchor: Anchor.center,
)..add(CircleHitbox());
await world.ensureAdd(circle);
final ray = Ray2(
origin: Vector2(0, 0),
direction: Vector2(1.0, 0),
);
final results = game.collisionDetection.raytrace(ray);
expect(results.length, 10);
expect(results.first.isActive, isTrue);
expect(results.first.isInsideHitbox, isTrue);
expect(
results.first.intersectionPoint,
Vector2(5, 0),
);
final reflectionRay = results.first.reflectionRay;
expect(reflectionRay?.origin, Vector2(5, 0));
expect(reflectionRay?.direction, Vector2(-1, 0)..normalize());
expect(results.first.normal, Vector2(-1, 0));
},
});
});

Expand Down