From 9b70fa0dbba26fbb7106692a2bd353cbdcef1a49 Mon Sep 17 00:00:00 2001 From: Sebastine Odeh Date: Thu, 26 Sep 2024 13:05:15 +0100 Subject: [PATCH] foot movement on map --- .../features/more/presentation/map/grid.dart | 195 +++++++++++++++++- .../more/presentation/widgets/foot.dart | 32 ++- .../more/presentation/widgets/map.dart | 99 +++++---- .../more/presentation/widgets/map_block.dart | 11 +- .../more/presentation/widgets/map_layout.dart | 2 +- 5 files changed, 267 insertions(+), 72 deletions(-) diff --git a/packages/conferenceapp/lib/src/features/more/presentation/map/grid.dart b/packages/conferenceapp/lib/src/features/more/presentation/map/grid.dart index ffccbce..72dd7b3 100644 --- a/packages/conferenceapp/lib/src/features/more/presentation/map/grid.dart +++ b/packages/conferenceapp/lib/src/features/more/presentation/map/grid.dart @@ -1,5 +1,8 @@ import 'dart:core'; +import 'dart:math'; +import 'dart:ui'; +import 'package:cave/cave.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart' hide Action; @@ -39,6 +42,7 @@ class GridPainter extends CustomPainter { this.showGrid = false, this.showPath = false, this.showBlocks = false, + this.onWalkerPosition, }); final Grid grid; @@ -49,6 +53,7 @@ class GridPainter extends CustomPainter { final bool showGrid; final bool showPath; final bool showBlocks; + final void Function(Offset walkerPostion, double angle)? onWalkerPosition; @override void paint(Canvas canvas, Size size) { @@ -116,22 +121,170 @@ class GridPainter extends CustomPainter { for (final pathMetric in pathMetrics) { try { - final extractPath = - pathMetric.extractPath(0, pathMetric.length * progress); + final extractPath = pathMetric.extractPath( + 0, pathMetric.length * progress, + startWithMoveTo: false); - final metric = extractPath.computeMetrics().first; - final tangent = metric.getTangentForOffset(metric.length)!; + final tangent = _computeTangentForPath(extractPath); final offset = tangent.position; - canvas.drawOval( - Rect.fromCircle(center: offset, radius: cellSize * 1.5), - Paint() - ..style = PaintingStyle.fill - ..color = Colors.orange); + canvas.save(); + canvas.translate(offset.dx, offset.dy); + + double rotationAngle = tangent.angle.abs() - pi / 2; + + final isOnXAxis = rotationAngle == pi / 2 || rotationAngle == -pi / 2; + + if (isOnXAxis) { + rotationAngle = rotationAngle - pi; + } else { + // if the tangent angle is -90, then the rotation angle should be 180 + if (_getDegFromRad(tangent.angle) == -90) { + rotationAngle = pi; + } + } + + onWalkerPosition?.call(offset, rotationAngle); + canvas.rotate(rotationAngle); + + _walker(canvas, Size(cellSize * 1.5, cellSize * 1.5)); + if (!isOnXAxis) { + canvas.translate(0, cellSize / 2); + } + + Matrix4 matrix4 = Matrix4.identity(); + matrix4.scale(-1.0, 1.0); + canvas.transform(matrix4.storage); + _walker(canvas, Size(cellSize * 1.5, cellSize * 1.5)); + + canvas.restore(); + // canvas.drawOval( + // Rect.fromCircle(center: offset, radius: cellSize * 1.5), + // Paint() + // ..style = PaintingStyle.fill + // ..color = Colors.orange); } catch (_) {} } } + void _walker(Canvas canvas, Size size) { + Path path_0 = Path(); + path_0.moveTo(size.width * 0.3759985, size.height * 0.4896138); + path_0.cubicTo( + size.width * 0.4655944, + size.height * 0.5371670, + size.width * 0.5076371, + size.height * 0.6434983, + size.width * 0.4776357, + size.height * 0.7412578); + path_0.cubicTo( + size.width * 0.4721253, + size.height * 0.7588096, + size.width * 0.4672271, + size.height * 0.7769737, + size.width * 0.4633494, + size.height * 0.7951377); + path_0.cubicTo( + size.width * 0.4474303, + size.height * 0.8767741, + size.width * 0.4688598, + size.height * 0.9792276, + size.width * 0.5586598, + size.height * 0.9973917); + path_0.cubicTo( + size.width * 0.6039679, + size.height * 1.006984, + size.width * 0.6490720, + size.height * 0.9894322, + size.width * 0.6809102, + size.height * 0.9561654); + path_0.cubicTo( + size.width * 0.7758124, + size.height * 0.8530995, + size.width * 0.7468315, + size.height * 0.5426774, + size.width * 0.7460151, + size.height * 0.4649188); + path_0.cubicTo( + size.width * 0.7460151, + size.height * 0.4308357, + size.width * 0.7451988, + size.height * 0.3959361, + size.width * 0.7317288, + size.height * 0.3640980); + path_0.cubicTo( + size.width * 0.7015233, + size.height * 0.2926662, + size.width * 0.6166216, + size.height * 0.2640935, + size.width * 0.5413121, + size.height * 0.2442967); + path_0.cubicTo( + size.width * 0.4176330, + size.height * 0.1991926, + size.width * 0.3396704, + size.height * 0.2561339, + size.width * 0.3135467, + size.height * 0.2981767); + path_0.cubicTo( + size.width * 0.2874231, + size.height * 0.3402194, + size.width * 0.2684427, + size.height * 0.4336929, + size.width * 0.3759985, + size.height * 0.4896138); + path_0.close(); + + Paint paint0Fill = Paint()..style = PaintingStyle.fill; + paint0Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); + canvas.drawPath(path_0, paint0Fill); + + Paint paint1Fill = Paint()..style = PaintingStyle.fill; + paint1Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); + canvas.drawOval( + Rect.fromCenter( + center: Offset(size.width * 0.2894640, size.height * 0.09041222), + width: size.width * 0.1285772, + height: size.height * 0.1808244), + paint1Fill); + + Paint paint2Fill = Paint()..style = PaintingStyle.fill; + paint2Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); + canvas.drawOval( + Rect.fromCenter( + center: Offset(size.width * 0.4380421, size.height * 0.1055149), + width: size.width * 0.07632996, + height: size.height * 0.1077599), + paint2Fill); + + Paint paint3Fill = Paint()..style = PaintingStyle.fill; + paint3Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); + canvas.drawOval( + Rect.fromCenter( + center: Offset(size.width * 0.5570271, size.height * 0.1387817), + width: size.width * 0.06816633, + height: size.height * 0.09510631), + paint3Fill); + + Paint paint4Fill = Paint()..style = PaintingStyle.fill; + paint4Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); + canvas.drawOval( + Rect.fromCenter( + center: Offset(size.width * 0.6656034, size.height * 0.1667422), + width: size.width * 0.06041088, + height: size.height * 0.08408541), + paint4Fill); + + Paint paint5Fill = Paint()..style = PaintingStyle.fill; + paint5Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); + canvas.drawOval( + Rect.fromCenter( + center: Offset(size.width * 0.7473805, size.height * 0.2229039), + width: size.width * 0.07469723, + height: size.height * 0.05387997), + paint5Fill); + } + void _paintGrid(Canvas canvas, Size size) { for (int i = 0; i < grid.rows; i++) { for (int j = 0; j < grid.columns; j++) { @@ -190,6 +343,11 @@ class GridPainter extends CustomPainter { } } + Tangent _computeTangentForPath(Path path) { + final metric = path.computeMetrics().first; + return metric.getTangentForOffset(metric.length)!; + } + @override bool shouldRepaint(covariant CustomPainter oldDelegate) { if (oldDelegate is! GridPainter) return false; @@ -345,3 +503,22 @@ class Grid extends Equatable { @override List get props => [grid]; } + +//Copy this CustomPainter code to the Bottom of the File +class RPSCustomPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) {} + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; + } +} + +double _getDegFromRad(double radians) { + return radians * (180 / pi); +} + +double getRadFromDeg(double angle) { + return angle * (pi / 180); +} diff --git a/packages/conferenceapp/lib/src/features/more/presentation/widgets/foot.dart b/packages/conferenceapp/lib/src/features/more/presentation/widgets/foot.dart index d384ec5..1f0f5d6 100644 --- a/packages/conferenceapp/lib/src/features/more/presentation/widgets/foot.dart +++ b/packages/conferenceapp/lib/src/features/more/presentation/widgets/foot.dart @@ -2,12 +2,29 @@ import 'package:cave/cave.dart'; import 'package:flutter/material.dart'; class MapFoot extends StatelessWidget { - const MapFoot({super.key}); + const MapFoot({super.key, required this.isRightFoot, this.color}); + + const MapFoot.left({super.key, this.color}) : isRightFoot = false; + + const MapFoot.right({super.key, this.color}) : isRightFoot = true; + + final bool isRightFoot; + final Color? color; @override Widget build(BuildContext context) { - return SvgPicture.string( + Widget child = SvgPicture.string( _footSvg, + height: 20.h, + colorFilter: color != null // + ? ColorFilter.mode(color!, BlendMode.srcIn) + : null, + ); + + if (isRightFoot) return child; + return Transform.flip( + flipX: true, + child: child, ); } } @@ -16,10 +33,7 @@ const _footSvg = ''' - - - - @@ -27,9 +41,7 @@ const _footSvg = ''' - - - + cx="366.2" cy="109.218" rx="18.3" ry="13.2" + /> '''; diff --git a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map.dart b/packages/conferenceapp/lib/src/features/more/presentation/widgets/map.dart index 2c428db..c5e7296 100644 --- a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map.dart +++ b/packages/conferenceapp/lib/src/features/more/presentation/widgets/map.dart @@ -179,6 +179,8 @@ class _LandmarkMapState extends ConsumerState } } + Offset? walkerPosition; + @override void initState() { super.initState(); @@ -221,8 +223,9 @@ class _LandmarkMapState extends ConsumerState void _runAnimation(int distance) { speedProgressAnim = controller.drive(Tween(begin: 0, end: 1)); - final simulation = FrictionSimulation.through(0, distance.toDouble(), - switch (distance) { <= 50 => 0.5, <= 100 => 0.4, _ => 0.3 }, 0); + final speed = switch (distance) { <= 50 => 0.38, <= 100 => 0.2, _ => 0.05 }; + final simulation = + FrictionSimulation.through(0, distance.toDouble(), speed, 0); controller.animateWith(simulation); } @@ -280,51 +283,59 @@ class _LandmarkMapState extends ConsumerState @override Widget build(BuildContext context) { - return AnimatedBuilder( - animation: controller, - builder: (context, child) { - return CustomPaint( - foregroundPainter: GridPainter( - grid: grid, - cellSize: cellSize, - progress: speedProgressAnim.value, - cellTrackRange: widget.getDirections, - actions: actions, - showGrid: ref.watch(showGridStateProvider), - showPath: ref.watch(showPathStateProvider), - ), - child: CustomPaint( - foregroundPainter: GridPainter( - grid: baseGrid, - cellSize: cellSize, - progress: 0, - showBlocks: ref.watch(showBlocksProvider), + return Stack( + fit: StackFit.expand, + children: [ + Positioned.fill( + child: AnimatedBuilder( + animation: controller, + builder: (context, child) { + return CustomPaint( + foregroundPainter: GridPainter( + grid: grid, + cellSize: cellSize, + progress: speedProgressAnim.value, + cellTrackRange: widget.getDirections, + actions: actions, + showGrid: ref.watch(showGridStateProvider), + showPath: ref.watch(showPathStateProvider), + ), + child: CustomPaint( + foregroundPainter: GridPainter( + grid: baseGrid, + cellSize: cellSize, + progress: 0, + showBlocks: ref.watch(showBlocksProvider), + ), + child: child, + ), + ); + }, + child: CustomMultiChildLayout( + delegate: MapLayoutDelegate( + blocks: mapSchematics, + onBlocksLayout: (areas) { + widget.onBlocksLayout(areas.toList()); + roomsLayouts = areas; + WidgetsFlutterBinding.ensureInitialized() + .addPostFrameCallback((_) { + areas.forEach(_fillPositionOnGrid); + }); + }, + ), + children: [ + for (int i = 0; i < mapSchematics.length; i++) + LayoutId( + id: i, + child: CustomPaint( + painter: MapBlockPainter(block: mapSchematics[i]), + ), + ), + ], ), - child: child, ), - ); - }, - child: CustomMultiChildLayout( - delegate: MapLayoutDelegate( - blocks: mapSchematics, - onBlocksLayout: (areas) { - widget.onBlocksLayout(areas.toList()); - roomsLayouts = areas; - WidgetsFlutterBinding.ensureInitialized().addPostFrameCallback((_) { - areas.forEach(_fillPositionOnGrid); - }); - }, ), - children: [ - for (int i = 0; i < mapSchematics.length; i++) - LayoutId( - id: i, - child: CustomPaint( - painter: MapBlockPainter(block: mapSchematics[i]), - ), - ), - ], - ), + ], ); } diff --git a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_block.dart b/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_block.dart index e09b9a0..51b5dab 100644 --- a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_block.dart +++ b/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_block.dart @@ -1,8 +1,7 @@ -import 'dart:math'; - import 'package:cave/cave.dart'; import 'package:flutter/material.dart'; +import '../map/grid.dart'; import '../map/map_utils.dart'; double openingRadius = 32.w; @@ -44,7 +43,7 @@ class MapBlockPainter extends CustomPainter { // render entrance label if (entranceLabelExists) { canvas.save(); - canvas.rotate(_getDegInRad(-90)); + canvas.rotate(getRadFromDeg(-90)); textPainter.paint( canvas, Offset(-(size.height + textPainter.width) / 2, @@ -173,7 +172,7 @@ class MapBlockPainter extends CustomPainter { labelPainter.layout(); // render block label if (labelPainter.width > blockWidth) { - canvas.rotate(_getDegInRad(-90)); + canvas.rotate(getRadFromDeg(-90)); labelPainter.paint( canvas, Offset(-(size.height + labelPainter.width) / 2, @@ -190,10 +189,6 @@ class MapBlockPainter extends CustomPainter { canvas.restore(); } - double _getDegInRad(double angle) { - return angle * (pi / 180); - } - Path _getPathWithOpenings(List openings, Size size, [_AllowedEdges edges = _defaultAllowedEdges, double horizontalPaddingFactor = 0]) { diff --git a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_layout.dart b/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_layout.dart index 8b23631..5b4770b 100644 --- a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_layout.dart +++ b/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_layout.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; import '../map/map_utils.dart'; -double cellSize = 5; +double cellSize = 8; class MapLayoutDelegate extends MultiChildLayoutDelegate { final List blocks;