From e4747e37478fa3a4f6caa1cfcf90b845900141ff Mon Sep 17 00:00:00 2001 From: Abdelaziz Mahdy Date: Tue, 10 Dec 2024 21:09:44 -0400 Subject: [PATCH] Revert "Merge pull request #2 from abdelaziz-mahdy/optimize-rendering" This reverts commit f67bfa203016a924019bf40697f759c0a0f2f15a, reversing changes made to 56db1cdd7a729b07b5111389224db197931e1a52. --- lib/ball.dart | 16 +-- lib/ball_painter.dart | 122 +++--------------- lib/ball_physics_manager.dart | 6 +- lib/ball_physics_widget.dart | 58 +++++---- macos/Podfile.lock | 2 +- macos/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- macos/Runner/AppDelegate.swift | 2 +- pubspec.lock | 7 +- 9 files changed, 63 insertions(+), 154 deletions(-) diff --git a/lib/ball.dart b/lib/ball.dart index 32fb850..964c2c2 100644 --- a/lib/ball.dart +++ b/lib/ball.dart @@ -10,14 +10,12 @@ class Ball { List trail = []; DateTime creationTime; - Ball({ - required this.position, - required this.velocity, - required this.color, - required this.radius, - }) : creationTime = DateTime.now(); - - Rect get boundingBox => Rect.fromCircle(center: position, radius: radius); + Ball( + {required this.position, + required this.velocity, + required this.color, + required this.radius}) + : creationTime = DateTime.now(); @override bool operator ==(covariant Ball other) { @@ -40,4 +38,4 @@ class Ball { trail.hashCode ^ creationTime.hashCode; } -} \ No newline at end of file +} diff --git a/lib/ball_painter.dart b/lib/ball_painter.dart index 642bfea..4056438 100644 --- a/lib/ball_painter.dart +++ b/lib/ball_painter.dart @@ -1,31 +1,20 @@ import 'package:bouncy_ball_physics/ball.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -/// Enum representing the shape of the trail left by balls. enum TrailShape { line, singleTriangle, multipleTriangles, } -/// A custom painter for rendering bouncing balls with optional trails. class BallPainter extends CustomPainter { - /// The list of balls to be painted. List balls; - - /// The shape of the trail for each ball. TrailShape trailShape; - /// Cache for ball paints based on their colors. - final Map _paintCache = {}; - - /// Constructor to initialize the ball painter. - /// [balls] is the list of balls to be painted. - /// [trailShape] defines the trail style for the balls. Default is [TrailShape.line]. BallPainter({required this.balls, this.trailShape = TrailShape.line}); - /// Retrieves or creates a [Paint] object for a given ball. + final Map _paintCache = {}; + Paint _getPaintForBall(Ball ball) { return _paintCache.putIfAbsent( ball.color, @@ -35,68 +24,29 @@ class BallPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { - int ballCount = balls.length; - int hiddenBalls = 0; - double totalHiddenPercentage = 0.0; - - // Sort balls by Y-position (descending). - balls.sort((a, b) => b.position.dy.compareTo(a.position.dy)); - - // Store bounding boxes of drawn balls. - List drawnBallsBounds = []; - for (var ball in balls) { final paint = _getPaintForBall(ball); paint.strokeWidth = ball.radius / 10; - /// Calculate the hidden percentage of the current ball's bounding box relative to previously drawn balls. - /// Iterates through the bounding boxes of previously drawn balls to determine how much of the current ball is hidden. - /// Stops early if the hidden percentage reaches or exceeds 40% (0.4) to optimize performance. - double hiddenPct = 0.0; - for (var drawnBounds in drawnBallsBounds) { - hiddenPct = ball.boundingBox.hiddenPercentage(drawnBounds); - if (hiddenPct >= 0.4) { - break; // Exit the loop early if the ball is sufficiently hidden. - } + switch (trailShape) { + case TrailShape.line: + // Draw the trail as a line + _drawLineTrail(canvas, ball, paint); + break; + case TrailShape.singleTriangle: + // Draw the trail as a single triangle + _drawSingleTriangleTrail(canvas, ball, paint); + break; + case TrailShape.multipleTriangles: + // Draw the trail as multiple triangles + _drawMultipleTrianglesTrail(canvas, ball, paint); + break; } - // If the ball is less than 40% hidden, draw it. - if (hiddenPct < 0.4) { - switch (trailShape) { - case TrailShape.line: - _drawLineTrail(canvas, ball, paint); - break; - case TrailShape.singleTriangle: - _drawSingleTriangleTrail(canvas, ball, paint); - break; - case TrailShape.multipleTriangles: - _drawMultipleTrianglesTrail(canvas, ball, paint); - break; - } - - canvas.drawCircle(ball.position, ball.radius, paint); - - // If the ball is completely visible, add its bounds to the drawn list. - if (hiddenPct == 0.0) { - drawnBallsBounds.add(ball.boundingBox); - } - } else { - hiddenBalls++; - } - totalHiddenPercentage += hiddenPct; - } - - // Calculate and log the overall hidden percentage. - double overallHiddenPercentage = - ballCount > 0 ? (totalHiddenPercentage / ballCount) * 100 : 0.0; - - if (kDebugMode) { - print( - "ballCount: $ballCount, hiddenBalls: $hiddenBalls, hiddenPercentage: ${overallHiddenPercentage.toStringAsFixed(2)}%}"); + canvas.drawCircle(ball.position, ball.radius, paint); } } - /// Draws a line trail for the ball. void _drawLineTrail(Canvas canvas, Ball ball, Paint paint) { for (var i = 0; i < ball.trail.length - 1; i++) { canvas.drawLine(ball.trail[i], ball.trail[i + 1], @@ -104,7 +54,6 @@ class BallPainter extends CustomPainter { } } - /// Draws a single triangle trail for the ball. void _drawSingleTriangleTrail(Canvas canvas, Ball ball, Paint paint) { var path = Path(); if (ball.trail.isNotEmpty) { @@ -116,7 +65,6 @@ class BallPainter extends CustomPainter { canvas.drawPath(path, paint); } - /// Draws multiple triangles as a trail for the ball. void _drawMultipleTrianglesTrail(Canvas canvas, Ball ball, Paint paint) { for (int i = 0; i < ball.trail.length - 1; i++) { _drawTriangle( @@ -124,14 +72,8 @@ class BallPainter extends CustomPainter { } } - /// Draws a single triangle given three points. void _drawTriangle( - Canvas canvas, - Offset point1, - Offset point2, - Offset point3, - Paint paint, - ) { + Canvas canvas, Offset point1, Offset point2, Offset point3, Paint paint) { var path = Path(); path.moveTo(point1.dx, point1.dy); path.lineTo(point2.dx, point2.dy); @@ -146,33 +88,3 @@ class BallPainter extends CustomPainter { return true; } } - -/// Extension methods for the [Rect] class. -extension RectExtensions on Rect { - /// Checks if this rectangle completely contains another rectangle. - bool containsRect(Rect other) { - return left <= other.left && - right >= other.right && - top <= other.top && - bottom >= other.bottom; - } - - /// Calculates the percentage of this rectangle that is hidden by another rectangle. - /// Returns 0.0 if there is no overlap, and 1.0 if this rect is fully contained. - double hiddenPercentage(Rect other) { - // If there is no overlap, return 0.0. - if (!overlaps(other)) { - return 0.0; - } - - // Calculate the intersection rectangle. - Rect intersection = intersect(other); - - // Calculate the area of this rectangle and the intersection rectangle. - double thisArea = width * height; - double intersectionArea = intersection.width * intersection.height; - - // Calculate the hidden percentage (0 to 1 range). - return (intersectionArea / thisArea).clamp(0.0, 1.0); - } -} diff --git a/lib/ball_physics_manager.dart b/lib/ball_physics_manager.dart index 897deb5..f6c491c 100644 --- a/lib/ball_physics_manager.dart +++ b/lib/ball_physics_manager.dart @@ -15,10 +15,8 @@ class BallPhysicsManager { final ValueNotifier fpsNotifier = ValueNotifier(0.0); final ValueNotifier ballLimitNotifier = ValueNotifier(100); final ValueNotifier tailLengthNotifier = ValueNotifier(100); - double slidersBallsMaxValue = 5000; - double slidersBallsMinValue = 1; - double slidersTailMaxValue = 500; - double slidersTailMinValue = 1; + double slidersMaxValue = 500; + double slidersMinValue = 1; static const int fpsAverageCount = 60; final List _fpsValues = []; diff --git a/lib/ball_physics_widget.dart b/lib/ball_physics_widget.dart index fcc09fc..e085035 100644 --- a/lib/ball_physics_widget.dart +++ b/lib/ball_physics_widget.dart @@ -72,24 +72,26 @@ class BallPhysicsWidgetState extends State flex: 2, child: Container( decoration: BoxDecoration(border: Border.all()), - child: LayoutBuilder(builder: (context, constraints) { - return ValueListenableBuilder( - valueListenable: trailShapeNotifier, - builder: (context, trailShape, child) { - return AnimatedBuilder( - animation: _controller, - builder: (context, child) { - manager.updatePhysics(context, constraints.biggest); - return CustomPaint( - painter: BallPainter( - balls: manager.balls, trailShape: trailShape), - child: Container(), - ); - }, - ); - }, - ); - }), + child: LayoutBuilder( + builder: (context, constraints) { + return ValueListenableBuilder( + valueListenable: trailShapeNotifier, + builder: (context, trailShape, child) { + return AnimatedBuilder( + animation: _controller, + builder: (context, child) { + manager.updatePhysics(context, constraints.biggest); + return CustomPaint( + painter: BallPainter( + balls: manager.balls, trailShape: trailShape), + child: Container(), + ); + }, + ); + }, + ); + } + ), ), ), ], @@ -111,11 +113,11 @@ class BallPhysicsWidgetState extends State builder: (BuildContext context, int value, Widget? child) { return Slider( value: manager.ballLimitNotifier.value.toDouble(), - min: manager.slidersBallsMinValue, - max: manager.slidersBallsMaxValue, - divisions: (manager.slidersBallsMaxValue - - manager.slidersBallsMinValue) - .toInt(), + min: manager.slidersMinValue, + max: manager.slidersMaxValue, + divisions: + (manager.slidersMaxValue - manager.slidersMinValue) + .toInt(), label: manager.ballLimitNotifier.value.toString(), onChanged: (double value) { manager.ballLimitNotifier.value = value.toInt(); @@ -128,11 +130,11 @@ class BallPhysicsWidgetState extends State builder: (BuildContext context, int value, Widget? child) { return Slider( value: manager.tailLengthNotifier.value.toDouble(), - min: manager.slidersTailMinValue, - max: manager.slidersTailMaxValue, - divisions: (manager.slidersTailMaxValue - - manager.slidersTailMinValue) - .toInt(), + min: manager.slidersMinValue, + max: manager.slidersMaxValue, + divisions: + (manager.slidersMaxValue - manager.slidersMinValue) + .toInt(), label: manager.tailLengthNotifier.value.toString(), onChanged: (double value) { manager.tailLengthNotifier.value = value.toInt(); diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 44d4097..1f6779f 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -13,4 +13,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 -COCOAPODS: 1.16.2 +COCOAPODS: 1.14.3 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index a4dc199..2348252 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -258,7 +258,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1510; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 331C80D4294CF70F00263BE5 = { diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 77c24ca..2514e09 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Bool { return true diff --git a/pubspec.lock b/pubspec.lock index d515519..604bcc5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -243,10 +243,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.6.1" vector_math: dependency: transitive description: @@ -272,5 +272,4 @@ packages: source: hosted version: "3.0.3" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.2.3 <4.0.0"