diff --git a/doc/bridge_packages/flame_behaviors/collision-detection.md b/doc/bridge_packages/flame_behaviors/collision-detection.md index f89392a7c1a..cfa6167f6f1 100644 --- a/doc/bridge_packages/flame_behaviors/collision-detection.md +++ b/doc/bridge_packages/flame_behaviors/collision-detection.md @@ -33,7 +33,7 @@ class MyEntityCollisionBehavior extends CollisionBehavior { @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, MyCollidingEntity other, ) { // We are starting colliding with MyCollidingEntity diff --git a/doc/flame/collision_detection.md b/doc/flame/collision_detection.md index 9668cb9b145..4d039fdb675 100644 --- a/doc/flame/collision_detection.md +++ b/doc/flame/collision_detection.md @@ -81,7 +81,7 @@ Example: ```dart class MyCollidable extends PositionComponent with CollisionCallbacks { @override - void onCollision(Set points, PositionComponent other) { + void onCollision(List points, PositionComponent other) { if (other is ScreenHitbox) { //... } else if (other is YourOtherComponent) { @@ -101,7 +101,7 @@ class MyCollidable extends PositionComponent with CollisionCallbacks { ``` In this example we use Dart's `is` keyword to check what kind of component we collided with. -The set of points is where the edges of the hitboxes intersect. +The list of points is where the edges of the hitboxes intersect. Note that the `onCollision` method will be called on both `PositionComponent`s if they have both implemented the `onCollision` method, and also on both hitboxes. The same goes for the @@ -137,7 +137,7 @@ save all the other `PositionComponent`s to this list: ```dart @override -void onCollision(Set intersectionPoints, PositionComponent other) { +void onCollision(List intersectionPoints, PositionComponent other) { collisionComponents.add(other); super.onCollision(intersectionPoints, other); } @@ -395,7 +395,7 @@ class Bullet extends PositionComponent with CollisionCallbacks { @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { // Removes the component when it comes in contact with a Brick. diff --git a/doc/flame/examples/lib/collision_detection.dart b/doc/flame/examples/lib/collision_detection.dart index 278affc7618..12be6843a51 100644 --- a/doc/flame/examples/lib/collision_detection.dart +++ b/doc/flame/examples/lib/collision_detection.dart @@ -55,7 +55,7 @@ class RectangleCollidable extends PositionComponent with CollisionCallbacks { @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/doc/flame/other/performance.md b/doc/flame/other/performance.md index ef3b45e77ba..77edd0cef8f 100644 --- a/doc/flame/other/performance.md +++ b/doc/flame/other/performance.md @@ -177,7 +177,7 @@ class Bullet extends SpriteComponent with CollisionCallbacks { } @override - void onCollisionStart(Set points, PositionComponent other) { + void onCollisionStart(List points, PositionComponent other) { super.onCollisionStart(points, other); // Return to pool on collision. No manual release needed. removeFromParent(); diff --git a/doc/tutorials/platformer/app/lib/actors/ember.dart b/doc/tutorials/platformer/app/lib/actors/ember.dart index 78dde97e368..642198f5f95 100644 --- a/doc/tutorials/platformer/app/lib/actors/ember.dart +++ b/doc/tutorials/platformer/app/lib/actors/ember.dart @@ -112,7 +112,7 @@ class EmberPlayer extends SpriteAnimationComponent } @override - void onCollision(Set intersectionPoints, PositionComponent other) { + void onCollision(List intersectionPoints, PositionComponent other) { if (other is GroundBlock || other is PlatformBlock) { if (intersectionPoints.length == 2) { // Calculate the collision normal and separation distance. diff --git a/doc/tutorials/platformer/step_5.md b/doc/tutorials/platformer/step_5.md index 0ed6381572b..0d1286ac3bf 100644 --- a/doc/tutorials/platformer/step_5.md +++ b/doc/tutorials/platformer/step_5.md @@ -131,7 +131,7 @@ Now add the following `onCollision` method: ```dart @override -void onCollision(Set intersectionPoints, PositionComponent other) { +void onCollision(List intersectionPoints, PositionComponent other) { if (other is GroundBlock || other is PlatformBlock) { if (intersectionPoints.length == 2) { // Calculate the collision normal and separation distance. diff --git a/doc/tutorials/space_shooter/app/lib/step6/main.dart b/doc/tutorials/space_shooter/app/lib/step6/main.dart index 0b53b52ec80..606d27353dc 100644 --- a/doc/tutorials/space_shooter/app/lib/step6/main.dart +++ b/doc/tutorials/space_shooter/app/lib/step6/main.dart @@ -197,7 +197,7 @@ class Enemy extends SpriteAnimationComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/doc/tutorials/space_shooter/step_6.md b/doc/tutorials/space_shooter/step_6.md index 96eec893697..e9c0bbcff35 100644 --- a/doc/tutorials/space_shooter/step_6.md +++ b/doc/tutorials/space_shooter/step_6.md @@ -80,7 +80,7 @@ class Enemy extends SpriteAnimationComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); @@ -148,7 +148,7 @@ in order to add the explosion to the game: ```dart @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/examples/games/crystal_ball/lib/src/game/entities/the_ball.dart b/examples/games/crystal_ball/lib/src/game/entities/the_ball.dart index 20cc8c8cf35..a1f9e01e1c2 100644 --- a/examples/games/crystal_ball/lib/src/game/entities/the_ball.dart +++ b/examples/games/crystal_ball/lib/src/game/entities/the_ball.dart @@ -58,7 +58,7 @@ class TheBall extends PositionComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/examples/games/rogue_shooter/lib/components/bullet_component.dart b/examples/games/rogue_shooter/lib/components/bullet_component.dart index f4de9b8227a..9618a9dbd55 100644 --- a/examples/games/rogue_shooter/lib/components/bullet_component.dart +++ b/examples/games/rogue_shooter/lib/components/bullet_component.dart @@ -29,7 +29,7 @@ class BulletComponent extends SpriteAnimationComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/examples/games/rogue_shooter/lib/components/player_component.dart b/examples/games/rogue_shooter/lib/components/player_component.dart index 3016c6c84be..9e1759e0822 100644 --- a/examples/games/rogue_shooter/lib/components/player_component.dart +++ b/examples/games/rogue_shooter/lib/components/player_component.dart @@ -59,7 +59,7 @@ class PlayerComponent extends SpriteAnimationComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/examples/games/trex/lib/player.dart b/examples/games/trex/lib/player.dart index 2412cdc4e08..d61e351f05a 100644 --- a/examples/games/trex/lib/player.dart +++ b/examples/games/trex/lib/player.dart @@ -101,7 +101,7 @@ class Player extends SpriteAnimationGroupComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/examples/lib/stories/camera_and_viewport/follow_component_example.dart b/examples/lib/stories/camera_and_viewport/follow_component_example.dart index ae0e25fa705..ad4e2647ad9 100644 --- a/examples/lib/stories/camera_and_viewport/follow_component_example.dart +++ b/examples/lib/stories/camera_and_viewport/follow_component_example.dart @@ -85,7 +85,7 @@ class MovableEmber extends Ember @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/examples/lib/stories/collision_detection/bouncing_ball_example.dart b/examples/lib/stories/collision_detection/bouncing_ball_example.dart index 29e864e9fa8..20f937d7136 100644 --- a/examples/lib/stories/collision_detection/bouncing_ball_example.dart +++ b/examples/lib/stories/collision_detection/bouncing_ball_example.dart @@ -72,7 +72,7 @@ class Ball extends CircleComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/examples/lib/stories/collision_detection/circles_example.dart b/examples/lib/stories/collision_detection/circles_example.dart index 6be41741a1f..ab590b03a56 100644 --- a/examples/lib/stories/collision_detection/circles_example.dart +++ b/examples/lib/stories/collision_detection/circles_example.dart @@ -58,7 +58,7 @@ class MyCollidable extends PositionComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/examples/lib/stories/collision_detection/collidable_animation_example.dart b/examples/lib/stories/collision_detection/collidable_animation_example.dart index 9bb0af4946d..4c6af8dc589 100644 --- a/examples/lib/stories/collision_detection/collidable_animation_example.dart +++ b/examples/lib/stories/collision_detection/collidable_animation_example.dart @@ -108,7 +108,7 @@ class AnimatedComponent extends SpriteAnimationComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/examples/lib/stories/collision_detection/multiple_shapes_example.dart b/examples/lib/stories/collision_detection/multiple_shapes_example.dart index 673f29ff868..8fa18715db7 100644 --- a/examples/lib/stories/collision_detection/multiple_shapes_example.dart +++ b/examples/lib/stories/collision_detection/multiple_shapes_example.dart @@ -147,7 +147,7 @@ abstract class MyCollidable extends PositionComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); @@ -229,7 +229,7 @@ class SnowmanPart extends CircleHitbox { } @override - void onCollisionStart(Set intersectionPoints, ShapeHitbox other) { + void onCollisionStart(List intersectionPoints, ShapeHitbox other) { super.onCollisionStart(intersectionPoints, other); if (other.hitboxParent is ScreenHitbox) { diff --git a/examples/lib/stories/collision_detection/multiple_worlds_example.dart b/examples/lib/stories/collision_detection/multiple_worlds_example.dart index 37a2f08c1f1..5b4c1e03d55 100644 --- a/examples/lib/stories/collision_detection/multiple_worlds_example.dart +++ b/examples/lib/stories/collision_detection/multiple_worlds_example.dart @@ -61,7 +61,7 @@ class CollidableEmber extends Ember with CollisionCallbacks { @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/examples/lib/stories/collision_detection/quadtree_example.dart b/examples/lib/stories/collision_detection/quadtree_example.dart index 5d3730ec038..9c1716fd77c 100644 --- a/examples/lib/stories/collision_detection/quadtree_example.dart +++ b/examples/lib/stories/collision_detection/quadtree_example.dart @@ -226,7 +226,7 @@ class Player extends SpriteComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { final myCenter = Vector2( @@ -295,7 +295,7 @@ class Bullet extends PositionComponent with CollisionCallbacks, HasPaint { @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { if (other is Brick) { diff --git a/examples/lib/stories/components/time_scale_example.dart b/examples/lib/stories/components/time_scale_example.dart index b3f2b3edb59..a5b2e176c92 100644 --- a/examples/lib/stories/components/time_scale_example.dart +++ b/examples/lib/stories/components/time_scale_example.dart @@ -109,7 +109,7 @@ class _Chopper extends SpriteAnimationComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { if (other is _Chopper) { diff --git a/examples/lib/stories/input/joystick_player.dart b/examples/lib/stories/input/joystick_player.dart index d7ca3b28643..73e22f4eb8a 100644 --- a/examples/lib/stories/input/joystick_player.dart +++ b/examples/lib/stories/input/joystick_player.dart @@ -32,7 +32,7 @@ class JoystickPlayer extends SpriteComponent @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/examples/lib/stories/system/step_engine_example.dart b/examples/lib/stories/system/step_engine_example.dart index 0e0ed0ee68f..5e34196dbf9 100644 --- a/examples/lib/stories/system/step_engine_example.dart +++ b/examples/lib/stories/system/step_engine_example.dart @@ -132,7 +132,7 @@ class _DetectorComponents extends CircleComponent with CollisionCallbacks { @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { paint.color = BasicPalette.black.color; diff --git a/packages/flame/lib/src/collisions/collision_callbacks.dart b/packages/flame/lib/src/collisions/collision_callbacks.dart index b3c0e36688d..f95bc2e8cb1 100644 --- a/packages/flame/lib/src/collisions/collision_callbacks.dart +++ b/packages/flame/lib/src/collisions/collision_callbacks.dart @@ -54,14 +54,14 @@ mixin GenericCollisionCallbacks { /// [onCollision] is called in every tick when this object is colliding with /// [other]. @mustCallSuper - void onCollision(Set intersectionPoints, T other) { + void onCollision(List intersectionPoints, T other) { onCollisionCallback?.call(intersectionPoints, other); } /// [onCollisionStart] is called in the first tick when this object starts /// colliding with [other]. @mustCallSuper - void onCollisionStart(Set intersectionPoints, T other) { + void onCollisionStart(List intersectionPoints, T other) { activeCollisions.add(other); onCollisionStartCallback?.call(intersectionPoints, other); } @@ -115,14 +115,14 @@ mixin CollisionCallbacks on Component @override @mustCallSuper - void onCollision(Set intersectionPoints, PositionComponent other) { + void onCollision(List intersectionPoints, PositionComponent other) { onCollisionCallback?.call(intersectionPoints, other); } @override @mustCallSuper void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { activeCollisions.add(other); @@ -167,7 +167,7 @@ mixin CollisionCallbacks on Component /// `onCollisionStartCallback`. typedef CollisionCallback = void Function( - Set intersectionPoints, + List intersectionPoints, T other, ); diff --git a/packages/flame/lib/src/collisions/collision_detection.dart b/packages/flame/lib/src/collisions/collision_detection.dart index d1669198fec..014c4229cd5 100644 --- a/packages/flame/lib/src/collisions/collision_detection.dart +++ b/packages/flame/lib/src/collisions/collision_detection.dart @@ -80,11 +80,11 @@ abstract class CollisionDetection< /// Check what the intersection points of two items are, /// returns an empty list if there are no intersections. - Set intersections(T itemA, T itemB); + List intersections(T itemA, T itemB); - void handleCollisionStart(Set intersectionPoints, T itemA, T itemB); + void handleCollisionStart(List intersectionPoints, T itemA, T itemB); - void handleCollision(Set intersectionPoints, T itemA, T itemB); + void handleCollision(List intersectionPoints, T itemA, T itemB); void handleCollisionEnd(T itemA, T itemB); diff --git a/packages/flame/lib/src/collisions/collision_passthrough.dart b/packages/flame/lib/src/collisions/collision_passthrough.dart index 686079229ab..cedffc39d40 100644 --- a/packages/flame/lib/src/collisions/collision_passthrough.dart +++ b/packages/flame/lib/src/collisions/collision_passthrough.dart @@ -24,7 +24,7 @@ mixin CollisionPassthrough on CollisionCallbacks { @override @mustCallSuper - void onCollision(Set intersectionPoints, PositionComponent other) { + void onCollision(List intersectionPoints, PositionComponent other) { super.onCollision(intersectionPoints, other); passthroughParent?.onCollision(intersectionPoints, other); } @@ -32,7 +32,7 @@ mixin CollisionPassthrough on CollisionCallbacks { @override @mustCallSuper void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/packages/flame/lib/src/collisions/hitboxes/hitbox.dart b/packages/flame/lib/src/collisions/hitboxes/hitbox.dart index 385e0f8c09f..f8310745a34 100644 --- a/packages/flame/lib/src/collisions/hitboxes/hitbox.dart +++ b/packages/flame/lib/src/collisions/hitboxes/hitbox.dart @@ -30,7 +30,7 @@ abstract class Hitbox> bool containsPoint(Vector2 point); /// Where this [Hitbox] has intersection points with another [Hitbox]. - Set intersections(T other); + List intersections(T other); /// This should be a cheaper calculation than comparing the exact boundaries /// if the exact calculation is expensive. diff --git a/packages/flame/lib/src/collisions/hitboxes/shape_hitbox.dart b/packages/flame/lib/src/collisions/hitboxes/shape_hitbox.dart index 5c445e88031..321aa060d72 100644 --- a/packages/flame/lib/src/collisions/hitboxes/shape_hitbox.dart +++ b/packages/flame/lib/src/collisions/hitboxes/shape_hitbox.dart @@ -158,7 +158,7 @@ mixin ShapeHitbox on ShapeComponent implements Hitbox { /// Where this [ShapeComponent] has intersection points with another shape @override - Set intersections(Hitbox other) { + List intersections(Hitbox other) { assert( other is ShapeComponent, 'The intersection can only be performed between shapes', @@ -218,7 +218,7 @@ mixin ShapeHitbox on ShapeComponent implements Hitbox { @override @mustCallSuper - void onCollision(Set intersectionPoints, ShapeHitbox other) { + void onCollision(List intersectionPoints, ShapeHitbox other) { onCollisionCallback?.call(intersectionPoints, other); if (hitboxParent is CollisionCallbacks && triggersParentCollision && @@ -232,7 +232,7 @@ mixin ShapeHitbox on ShapeComponent implements Hitbox { @override @mustCallSuper - void onCollisionStart(Set intersectionPoints, ShapeHitbox other) { + void onCollisionStart(List intersectionPoints, ShapeHitbox other) { activeCollisions.add(other); onCollisionStartCallback?.call(intersectionPoints, other); if (hitboxParent is CollisionCallbacks && diff --git a/packages/flame/lib/src/collisions/standard_collision_detection.dart b/packages/flame/lib/src/collisions/standard_collision_detection.dart index 6f697ee80cd..439eed41d48 100644 --- a/packages/flame/lib/src/collisions/standard_collision_detection.dart +++ b/packages/flame/lib/src/collisions/standard_collision_detection.dart @@ -18,7 +18,7 @@ class StandardCollisionDetection> /// Check what the intersection points of two collidables are, /// returns an empty list if there are no intersections. @override - Set intersections( + List intersections( ShapeHitbox hitboxA, ShapeHitbox hitboxB, ) { @@ -31,7 +31,7 @@ class StandardCollisionDetection> /// [ShapeHitbox.hitboxParent] that they have collided with. @override void handleCollisionStart( - Set intersectionPoints, + List intersectionPoints, ShapeHitbox hitboxA, ShapeHitbox hitboxB, ) { @@ -45,7 +45,7 @@ class StandardCollisionDetection> /// [ShapeHitbox.hitboxParent] that they have collided with. @override void handleCollision( - Set intersectionPoints, + List intersectionPoints, ShapeHitbox hitboxA, ShapeHitbox hitboxB, ) { diff --git a/packages/flame/lib/src/experimental/geometry/shapes/rectangle.dart b/packages/flame/lib/src/experimental/geometry/shapes/rectangle.dart index bb599e40738..0b1366cab99 100644 --- a/packages/flame/lib/src/experimental/geometry/shapes/rectangle.dart +++ b/packages/flame/lib/src/experimental/geometry/shapes/rectangle.dart @@ -157,8 +157,16 @@ class Rectangle extends Shape { /// Returns all intersections between this rectangle's edges and the given /// line segment. - Set intersections(LineSegment line) { - return edges.expand((e) => e.intersections(line)).toSet(); + List intersections(LineSegment line) { + final intersectionPoints = []; + for (final edge in edges) { + for (final intersection in edge.intersections(line)) { + if (!intersectionPoints.contains(intersection)) { + intersectionPoints.add(intersection); + } + } + } + return intersectionPoints; } @override diff --git a/packages/flame/lib/src/geometry/shape_intersections.dart b/packages/flame/lib/src/geometry/shape_intersections.dart index af68afffc44..995d11e8ed6 100644 --- a/packages/flame/lib/src/geometry/shape_intersections.dart +++ b/packages/flame/lib/src/geometry/shape_intersections.dart @@ -7,13 +7,13 @@ abstract class Intersections< T1 extends ShapeComponent, T2 extends ShapeComponent > { - Set intersect(T1 shapeA, T2 shapeB); + List intersect(T1 shapeA, T2 shapeB); bool supportsShapes(ShapeComponent shapeA, ShapeComponent shapeB) { return shapeA is T1 && shapeB is T2 || shapeA is T2 && shapeB is T1; } - Set unorderedIntersect( + List unorderedIntersect( ShapeComponent shapeA, ShapeComponent shapeB, ) { @@ -34,12 +34,12 @@ class PolygonPolygonIntersections /// If they share a segment of a line, both end points and the center point of /// that line segment will be counted as collision points @override - Set intersect( + List intersect( PolygonComponent polygonA, PolygonComponent polygonB, { Rect? overlappingRect, }) { - final intersectionPoints = {}; + final intersectionPoints = []; final intersectionsA = polygonA.possibleIntersectionVertices( overlappingRect, ); @@ -49,7 +49,11 @@ class PolygonPolygonIntersections for (final lineA in intersectionsA) { for (final lineB in intersectionsB) { final lineIntersections = lineA.intersections(lineB); - intersectionPoints.addAll(lineIntersections); + for (final intersection in lineIntersections) { + if (!intersectionPoints.contains(intersection)) { + intersectionPoints.add(intersection); + } + } } } if (intersectionPoints.isEmpty && (polygonA.isSolid || polygonB.isSolid)) { @@ -60,7 +64,7 @@ class PolygonPolygonIntersections : null); if (outerShape != null && outerShape.isSolid) { final innerShape = outerShape == polygonA ? polygonB : polygonA; - return {innerShape.absoluteCenter}; + return [innerShape.absoluteCenter]; } } return intersectionPoints; @@ -70,17 +74,21 @@ class PolygonPolygonIntersections class CirclePolygonIntersections extends Intersections { @override - Set intersect( + List intersect( CircleComponent circle, PolygonComponent polygon, { Rect? overlappingRect, }) { - final intersectionPoints = {}; + final intersectionPoints = []; final possibleVertices = polygon.possibleIntersectionVertices( overlappingRect, ); for (final line in possibleVertices) { - intersectionPoints.addAll(circle.lineSegmentIntersections(line)); + for (final intersection in circle.lineSegmentIntersections(line)) { + if (!intersectionPoints.contains(intersection)) { + intersectionPoints.add(intersection); + } + } } if (intersectionPoints.isEmpty && (circle.isSolid || polygon.isSolid)) { final outerShape = circle.containsPoint(polygon.globalVertices().first) @@ -88,7 +96,7 @@ class CirclePolygonIntersections : (polygon.containsPoint(circle.absoluteCenter) ? polygon : null); if (outerShape != null && outerShape.isSolid) { final innerShape = outerShape == circle ? polygon : circle; - return {innerShape.absoluteCenter}; + return [innerShape.absoluteCenter]; } } return intersectionPoints; @@ -98,7 +106,7 @@ class CirclePolygonIntersections class CircleCircleIntersections extends Intersections { @override - Set intersect(CircleComponent shapeA, CircleComponent shapeB) { + List intersect(CircleComponent shapeA, CircleComponent shapeB) { final centerA = shapeA.absoluteCenter; final centerB = shapeB.absoluteCenter; final distance = centerA.distanceTo(centerB); @@ -106,28 +114,28 @@ class CircleCircleIntersections final radiusB = shapeB.scaledRadius; if (distance > radiusA + radiusB) { // Since the circles are too far away from each other to intersect we - // return the empty set. - return {}; + // return the empty list. + return []; } else if (distance < (radiusA - radiusB).abs()) { // When one circle is contained within the other there is only a collision // if the outer circle isn't hollow. final outerShape = radiusA > radiusB ? shapeA : shapeB; if (outerShape.isSolid) { final center = outerShape == shapeA ? centerB : centerA; - return {center}; + return [center]; } else { - return {}; + return []; } } else if (distance == 0 && radiusA == radiusB) { // The circles are identical and on top of each other, so there are an // infinite number of solutions. Since it is problematic to return a - // set of infinite size, we'll return 4 distinct points here. - return { + // list of infinite size, we'll return 4 distinct points here. + return [ shapeA.absoluteCenter + Vector2(radiusA, 0), shapeA.absoluteCenter + Vector2(0, -radiusA), shapeA.absoluteCenter + Vector2(-radiusA, 0), shapeA.absoluteCenter + Vector2(0, radiusA), - }; + ]; } else { // There are definitely collision points if we end up in here. // To calculate these we use the fact that we can form two triangles going @@ -159,10 +167,13 @@ class CircleCircleIntersections (shapeB.absoluteCenter.x - shapeA.absoluteCenter.x).abs() / distance, ); - return { - centerPoint + delta, - centerPoint - delta, - }; + final intersectionA = centerPoint + delta; + final intersectionB = centerPoint - delta; + if (intersectionA == intersectionB) { + // The circles are tangent and only touch in one point. + return [intersectionA]; + } + return [intersectionA, intersectionB]; } } } @@ -173,7 +184,7 @@ final List _intersectionSystems = [ PolygonPolygonIntersections(), ]; -Set intersections(ShapeComponent shapeA, ShapeComponent shapeB) { +List intersections(ShapeComponent shapeA, ShapeComponent shapeB) { final intersectionSystem = _intersectionSystems.firstWhere( (system) => system.supportsShapes(shapeA, shapeB), orElse: () { diff --git a/packages/flame/test/collisions/collision_callback_benchmark_test.dart b/packages/flame/test/collisions/collision_callback_benchmark_test.dart index cc5074390a8..867e6d9b3bf 100644 --- a/packages/flame/test/collisions/collision_callback_benchmark_test.dart +++ b/packages/flame/test/collisions/collision_callback_benchmark_test.dart @@ -22,7 +22,7 @@ class _TestBlock extends PositionComponent with CollisionCallbacks { @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); diff --git a/packages/flame/test/collisions/collision_detection_test.dart b/packages/flame/test/collisions/collision_detection_test.dart index 7650c3b1476..8c02c60d54b 100644 --- a/packages/flame/test/collisions/collision_detection_test.dart +++ b/packages/flame/test/collisions/collision_detection_test.dart @@ -309,12 +309,12 @@ void main() { ]); final intersections = geometry.intersections(polygonA, polygonB); expect( - intersections.containsAll([ + intersections, + containsAll([ Vector2(2.0, 2.0), Vector2(2.0, 1.5), Vector2(2.0, 1.0), ]), - true, reason: 'Does not have all the correct intersection points', ); expect( @@ -373,7 +373,8 @@ void main() { ); final intersections = geometry.intersections(polygonA, polygonB); expect( - intersections.containsAll([ + intersections, + containsAll([ Vector2(2, 0), Vector2(2, 2), Vector2(1, 0), @@ -381,7 +382,6 @@ void main() { Vector2(0, 1), Vector2(0, 2), ]), - true, reason: 'Does not have all the correct intersection points', ); expect( @@ -407,12 +407,16 @@ void main() { Vector2(2, 1), ]); final intersections = geometry.intersections(polygonA, polygonB); - intersections.containsAll([ - Vector2(-0.2857142857142857, 2.4285714285714284), - Vector2(1.7500000000000002, 1.2500000000000002), - Vector2(1.5555555555555556, 0.6666666666666667), - Vector2(1.1999999999999997, 0.39999999999999997), - ]); + expect( + intersections, + containsAll([ + Vector2(-0.2857142857142857, 2.4285714285714284), + Vector2(1.7500000000000002, 1.2500000000000002), + Vector2(1.5555555555555556, 0.6666666666666667), + Vector2(1.1999999999999997, 0.39999999999999997), + ]), + reason: 'Does not have all the correct intersection points', + ); expect( intersections.length == 4, true, @@ -450,12 +454,12 @@ void main() { ); final intersections = geometry.intersections(rectangleA, rectangleB); expect( - intersections.containsAll([ + intersections, + containsAll([ Vector2(4, 0), Vector2(4, 2), Vector2(4, 4), ]), - true, reason: 'Missed intersections', ); expect( @@ -709,13 +713,13 @@ void main() { final circleB = CircleComponent(radius: 4.0, position: Vector2.all(3)); final intersections = geometry.intersections(circleA, circleB); expect( - intersections.containsAll([ + intersections, + containsAll([ Vector2(11, 7), Vector2(7, 3), Vector2(3, 7), Vector2(7, 11), ]), - true, reason: 'Missed intersections', ); expect( @@ -817,8 +821,8 @@ void main() { ); final intersections = geometry.intersections(circle, polygon); expect( - intersections.containsAll([Vector2(0, 1), Vector2(1, 0)]), - true, + intersections, + containsAll([Vector2(0, 1), Vector2(1, 0)]), reason: 'Missed intersections', ); expect(intersections.length, 2, reason: 'Wrong number of intersections'); @@ -863,13 +867,13 @@ void main() { ]); final intersections = geometry.intersections(circle, polygon); expect( - intersections.containsAll([ + intersections, + containsAll([ Vector2(1, 2), Vector2(2, 1), Vector2(1, 0), Vector2(0, 1), ]), - true, reason: 'Missed intersections', ); expect( diff --git a/packages/flame/test/collisions/collision_test_helpers.dart b/packages/flame/test/collisions/collision_test_helpers.dart index 66e8fedfd0c..56b3544d4c1 100644 --- a/packages/flame/test/collisions/collision_test_helpers.dart +++ b/packages/flame/test/collisions/collision_test_helpers.dart @@ -138,8 +138,8 @@ class TestBlock extends PositionComponent with CollisionCallbacks { : '_TestBlock[$name]'; } - Set intersections(TestBlock other) { - final result = {}; + List intersections(TestBlock other) { + final result = []; for (final hitboxA in children.query()) { for (final hitboxB in other.children.query()) { result.addAll(hitboxA.intersections(hitboxB)); @@ -150,7 +150,7 @@ class TestBlock extends PositionComponent with CollisionCallbacks { @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { super.onCollisionStart(intersectionPoints, other); @@ -158,7 +158,7 @@ class TestBlock extends PositionComponent with CollisionCallbacks { } @override - void onCollision(Set intersectionPoints, PositionComponent other) { + void onCollision(List intersectionPoints, PositionComponent other) { super.onCollision(intersectionPoints, other); onCollisionCounter++; } diff --git a/packages/flame_behaviors/example/lib/entities/circle/behaviors/circle_collision_behavior.dart b/packages/flame_behaviors/example/lib/entities/circle/behaviors/circle_collision_behavior.dart index 9b8d28ad66c..ca00f5d6265 100644 --- a/packages/flame_behaviors/example/lib/entities/circle/behaviors/circle_collision_behavior.dart +++ b/packages/flame_behaviors/example/lib/entities/circle/behaviors/circle_collision_behavior.dart @@ -7,7 +7,7 @@ class CircleCollisionBehavior extends CollisionBehavior { final _collisionColor = Colors.green.withValues(alpha: 0.8); @override - void onCollisionStart(Set intersectionPoints, Circle other) { + void onCollisionStart(List intersectionPoints, Circle other) { parent.paint.color = _collisionColor; } diff --git a/packages/flame_behaviors/example/lib/entities/circle/behaviors/rectangle_collision_behavior.dart b/packages/flame_behaviors/example/lib/entities/circle/behaviors/rectangle_collision_behavior.dart index 58d3f8aa7b6..b4a551fb82b 100644 --- a/packages/flame_behaviors/example/lib/entities/circle/behaviors/rectangle_collision_behavior.dart +++ b/packages/flame_behaviors/example/lib/entities/circle/behaviors/rectangle_collision_behavior.dart @@ -7,7 +7,7 @@ class RectangleCollisionBehavior extends CollisionBehavior { final _collisionColor = Colors.yellow.withValues(alpha: 0.8); @override - void onCollisionStart(Set intersectionPoints, Rectangle other) { + void onCollisionStart(List intersectionPoints, Rectangle other) { parent.paint.color = _collisionColor; } diff --git a/packages/flame_behaviors/example/lib/entities/rectangle/behaviors/circle_colliding_behavior.dart b/packages/flame_behaviors/example/lib/entities/rectangle/behaviors/circle_colliding_behavior.dart index 494f1253e6c..87faa088bdc 100644 --- a/packages/flame_behaviors/example/lib/entities/rectangle/behaviors/circle_colliding_behavior.dart +++ b/packages/flame_behaviors/example/lib/entities/rectangle/behaviors/circle_colliding_behavior.dart @@ -7,7 +7,7 @@ class CircleCollidingBehavior extends CollisionBehavior { final _collisionColor = Colors.green.withValues(alpha: 0.8); @override - void onCollisionStart(Set intersectionPoints, Circle other) { + void onCollisionStart(List intersectionPoints, Circle other) { parent.paint.color = _collisionColor; } diff --git a/packages/flame_behaviors/example/lib/entities/rectangle/behaviors/rectangle_colliding_behavior.dart b/packages/flame_behaviors/example/lib/entities/rectangle/behaviors/rectangle_colliding_behavior.dart index c78ba6d7e29..fede4ba4e51 100644 --- a/packages/flame_behaviors/example/lib/entities/rectangle/behaviors/rectangle_colliding_behavior.dart +++ b/packages/flame_behaviors/example/lib/entities/rectangle/behaviors/rectangle_colliding_behavior.dart @@ -8,7 +8,7 @@ class RectangleCollidingBehavior final _collisionColor = Colors.yellow.withValues(alpha: 0.8); @override - void onCollisionStart(Set intersectionPoints, Rectangle other) { + void onCollisionStart(List intersectionPoints, Rectangle other) { parent.paint.color = _collisionColor; } diff --git a/packages/flame_behaviors/lib/src/behaviors/propagating_collision_behavior.dart b/packages/flame_behaviors/lib/src/behaviors/propagating_collision_behavior.dart index aa7c8ba4296..17cb517ea9f 100644 --- a/packages/flame_behaviors/lib/src/behaviors/propagating_collision_behavior.dart +++ b/packages/flame_behaviors/lib/src/behaviors/propagating_collision_behavior.dart @@ -20,10 +20,10 @@ abstract class CollisionBehavior< bool isValid(Component c) => c is Collider; /// Called when the entity collides with [Collider]. - void onCollision(Set intersectionPoints, Collider other) {} + void onCollision(List intersectionPoints, Collider other) {} /// Called when the entity starts to collides with [Collider]. - void onCollisionStart(Set intersectionPoints, Collider other) {} + void onCollisionStart(List intersectionPoints, Collider other) {} /// Called when the entity stops to collides with [Collider]. void onCollisionEnd(Collider other) {} @@ -122,7 +122,7 @@ class PropagatingCollisionBehavior @override void onCollisionStart( - Set intersectionPoints, + List intersectionPoints, PositionComponent other, ) { activeCollisions.add(other); @@ -141,7 +141,7 @@ class PropagatingCollisionBehavior @override @mustCallSuper - void onCollision(Set intersectionPoints, PositionComponent other) { + void onCollision(List intersectionPoints, PositionComponent other) { final otherEntity = findEntity(other); if (otherEntity == null) { return; diff --git a/packages/flame_behaviors/test/src/behaviors/propagating_collision_behavior_test.dart b/packages/flame_behaviors/test/src/behaviors/propagating_collision_behavior_test.dart index 65d5426bbde..d577019b56f 100644 --- a/packages/flame_behaviors/test/src/behaviors/propagating_collision_behavior_test.dart +++ b/packages/flame_behaviors/test/src/behaviors/propagating_collision_behavior_test.dart @@ -31,13 +31,13 @@ abstract class _CollisionBehavior< bool onCollisionEndCalled = false; @override - void onCollisionStart(Set intersectionPoints, A other) { + void onCollisionStart(List intersectionPoints, A other) { super.onCollisionStart(intersectionPoints, other); onCollisionStartCalled = true; } @override - void onCollision(Set intersectionPoints, A other) { + void onCollision(List intersectionPoints, A other) { super.onCollision(intersectionPoints, other); onCollisionCalled = true; } diff --git a/packages/flame_behaviors/test/src/behaviors/screen_collision_behavior_test.dart b/packages/flame_behaviors/test/src/behaviors/screen_collision_behavior_test.dart index b8992818fb9..6e52ba7ddea 100644 --- a/packages/flame_behaviors/test/src/behaviors/screen_collision_behavior_test.dart +++ b/packages/flame_behaviors/test/src/behaviors/screen_collision_behavior_test.dart @@ -18,14 +18,14 @@ class _TrackingScreenCollisionBehavior ScreenHitbox? lastOther; @override - void onCollisionStart(Set intersectionPoints, ScreenHitbox other) { + void onCollisionStart(List intersectionPoints, ScreenHitbox other) { super.onCollisionStart(intersectionPoints, other); startCalled = true; lastOther = other; } @override - void onCollision(Set intersectionPoints, ScreenHitbox other) { + void onCollision(List intersectionPoints, ScreenHitbox other) { super.onCollision(intersectionPoints, other); collisionCalled = true; } diff --git a/packages/flame_bloc/example/lib/src/game/components/bullet.dart b/packages/flame_bloc/example/lib/src/game/components/bullet.dart index da0aa41195f..0e8264f0033 100644 --- a/packages/flame_bloc/example/lib/src/game/components/bullet.dart +++ b/packages/flame_bloc/example/lib/src/game/components/bullet.dart @@ -61,7 +61,7 @@ class BulletComponent extends SpriteAnimationComponent } @override - void onCollision(Set intersectionPoints, PositionComponent other) { + void onCollision(List intersectionPoints, PositionComponent other) { super.onCollision(intersectionPoints, other); if (other is EnemyComponent) { destroyed = true; diff --git a/packages/flame_bloc/example/lib/src/game/components/player.dart b/packages/flame_bloc/example/lib/src/game/components/player.dart index a69c5f35610..45c5a6ce6e8 100644 --- a/packages/flame_bloc/example/lib/src/game/components/player.dart +++ b/packages/flame_bloc/example/lib/src/game/components/player.dart @@ -118,7 +118,7 @@ class PlayerComponent extends SpriteAnimationComponent } @override - void onCollision(Set intersectionPoints, PositionComponent other) { + void onCollision(List intersectionPoints, PositionComponent other) { super.onCollision(intersectionPoints, other); if (other is EnemyComponent) { takeHit();