From 3b79292f8fbaef0bfdf167099d339d05f93b4f98 Mon Sep 17 00:00:00 2001 From: RuiAlonso Date: Wed, 23 Mar 2022 19:17:32 +0100 Subject: [PATCH] feat: create ellipses from geometry --- lib/game/components/pathway.dart | 41 +++++++++++++++++++++++++ lib/game/pinball_game.dart | 2 +- packages/geometry/lib/src/geometry.dart | 37 ++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/lib/game/components/pathway.dart b/lib/game/components/pathway.dart index 8604e0f3..30595f02 100644 --- a/lib/game/components/pathway.dart +++ b/lib/game/components/pathway.dart @@ -144,6 +144,47 @@ class Pathway extends BodyComponent with InitialPosition, Layered { ); } + /// Creates an ellipse [Pathway]. + /// + /// Does so with two [ChainShape] separated by a [width]. Can + /// be rotated by a given [rotation] in radians. + /// + /// If [singleWall] is true, just one [ChainShape] is created. + factory Pathway.ellipse({ + Color? color, + required Vector2 center, + required double width, + required double bigRadius, + required double smallRadius, + required double angle, + double rotation = 0, + bool singleWall = false, + }) { + final paths = >[]; + + // TODO(ruialonso): Refactor repetitive logic + final outerWall = calculateEllipse( + center: center, + bigRadius: bigRadius, + smallRadius: smallRadius, + ).map((vector) => vector..rotate(rotation)).toList(); + paths.add(outerWall); + + if (!singleWall) { + final innerWall = calculateEllipse( + center: center, + bigRadius: bigRadius - width, + smallRadius: smallRadius - width, + ).map((vector) => vector..rotate(rotation)).toList(); + paths.add(innerWall); + } + + return Pathway._( + color: color, + paths: paths, + ); + } + final List> _paths; /// Constructs different [ChainShape]s to form the [Pathway] shape. diff --git a/lib/game/pinball_game.dart b/lib/game/pinball_game.dart index 44a7ec01..cc5bf2f6 100644 --- a/lib/game/pinball_game.dart +++ b/lib/game/pinball_game.dart @@ -1,5 +1,5 @@ // ignore_for_file: public_member_api_docs - +import 'dart:math' as math; import 'dart:async'; import 'package:flame/extensions.dart'; import 'package:flame/input.dart'; diff --git a/packages/geometry/lib/src/geometry.dart b/packages/geometry/lib/src/geometry.dart index 8574bc73..bbddac9b 100644 --- a/packages/geometry/lib/src/geometry.dart +++ b/packages/geometry/lib/src/geometry.dart @@ -33,6 +33,43 @@ List calculateArc({ return points; } +/// Calculates all [Vector2]s of an ellipse. +/// +/// An ellipse can be achieved by specifying a [center], a [bigRadius] and a +/// [smallRadius]. +/// In addition, a semi-ellipse can be achieved by specifying its [angle] and an +/// [offsetAngle] (both in radians). +/// +/// The higher the [precision], the more [Vector2]s will be calculated; +/// achieving a more rounded ellipse. +/// +/// For more information read: https://en.wikipedia.org/wiki/Ellipse. +List calculateEllipse({ + required Vector2 center, + required double bigRadius, + required double smallRadius, + int precision = 100, +}) { + assert( + 0 < smallRadius && smallRadius <= bigRadius, + 'smallRadius ($smallRadius) and bigRadius ($bigRadius) must be in ' + 'range 0 < smallRadius <= bigRadius', + ); + + final stepAngle = 2 * math.pi / (precision - 1); + + final points = []; + for (var i = 0; i < precision; i++) { + final xCoord = center.x + smallRadius * math.cos(stepAngle * i); + final yCoord = center.y - bigRadius * math.sin(stepAngle * i); + + final point = Vector2(xCoord, yCoord); + points.add(point); + } + + return points; +} + /// Calculates all [Vector2]s of a bezier curve. /// /// A bezier curve of [controlPoints] that say how to create this curve.