mirror of
				https://github.com/flame-engine/flame.git
				synced 2025-10-31 00:48:47 +08:00 
			
		
		
		
	refactor: Use canvas.drawImageNine in NineTileBox (#1314)
`canvas.drawImageNine` is built-in now a lot of logic was removed from NineTileBox.
This commit is contained in:
		
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 205 B After Width: | Height: | Size: 460 B | 
| @ -1,7 +1,6 @@ | |||||||
| import 'package:flame/components.dart'; | import 'package:flame/components.dart'; | ||||||
| import 'package:flame/game.dart'; | import 'package:flame/game.dart'; | ||||||
| import 'package:flame/input.dart'; | import 'package:flame/input.dart'; | ||||||
| import 'package:flutter/material.dart'; |  | ||||||
|  |  | ||||||
| class NineTileBoxExample extends FlameGame with TapDetector, DoubleTapDetector { | class NineTileBoxExample extends FlameGame with TapDetector, DoubleTapDetector { | ||||||
|   static const String description = ''' |   static const String description = ''' | ||||||
| @ -10,30 +9,31 @@ class NineTileBoxExample extends FlameGame with TapDetector, DoubleTapDetector { | |||||||
|     Tap to make the box bigger and double tap to make it smaller. |     Tap to make the box bigger and double tap to make it smaller. | ||||||
|   '''; |   '''; | ||||||
|  |  | ||||||
|   late NineTileBox nineTileBox; |   late NineTileBoxComponent nineTileBoxComponent; | ||||||
|   final Vector2 boxSize = Vector2.all(300); |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Future<void> onLoad() async { |   Future<void> onLoad() async { | ||||||
|     await super.onLoad(); |     await super.onLoad(); | ||||||
|     final sprite = Sprite(await images.load('nine-box.png')); |     final sprite = Sprite(await images.load('nine-box.png')); | ||||||
|     nineTileBox = NineTileBox(sprite, tileSize: 8, destTileSize: 24); |     final boxSize = Vector2.all(300); | ||||||
|   } |     final nineTileBox = NineTileBox(sprite, destTileSize: 148); | ||||||
|  |     add( | ||||||
|   @override |       nineTileBoxComponent = NineTileBoxComponent( | ||||||
|   void render(Canvas canvas) { |         nineTileBox: nineTileBox, | ||||||
|     super.render(canvas); |         position: size / 2, | ||||||
|     final position = (size - boxSize) / 2; |         size: boxSize, | ||||||
|     nineTileBox.draw(canvas, position, boxSize); |         anchor: Anchor.center, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   void onTap() { |   void onTap() { | ||||||
|     boxSize.scale(1.2); |     nineTileBoxComponent.scale.scale(1.2); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   void onDoubleTap() { |   void onDoubleTap() { | ||||||
|     boxSize.scale(0.8); |     nineTileBoxComponent.scale.scale(0.8); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,9 +6,9 @@ Widget nineTileBoxBuilder(DashbookContext ctx) { | |||||||
|   return Container( |   return Container( | ||||||
|     width: ctx.numberProperty('width', 200), |     width: ctx.numberProperty('width', 200), | ||||||
|     height: ctx.numberProperty('height', 200), |     height: ctx.numberProperty('height', 200), | ||||||
|     child: NineTileBox.asset( |     child: NineTileBoxWidget.asset( | ||||||
|       path: 'nine-box.png', |       path: 'nine-box.png', | ||||||
|       tileSize: 8, |       tileSize: 22, | ||||||
|       destTileSize: 50, |       destTileSize: 50, | ||||||
|       child: const Center( |       child: const Center( | ||||||
|         child: Text( |         child: Text( | ||||||
|  | |||||||
| @ -15,19 +15,22 @@ class NineTileBox { | |||||||
|   static final _whitePaint = BasicPalette.white.paint(); |   static final _whitePaint = BasicPalette.white.paint(); | ||||||
|  |  | ||||||
|   /// The sprite used to render the box, must be a 3x3 grid of square tiles. |   /// The sprite used to render the box, must be a 3x3 grid of square tiles. | ||||||
|   Sprite sprite; |   final Sprite sprite; | ||||||
|  |  | ||||||
|   /// The size of each tile in the source sprite image. |   /// The size of each tile in the source sprite image. | ||||||
|   int tileSize; |   final int tileSize; | ||||||
|  |  | ||||||
|   /// The size each tile becomes when rendered |   /// The size each tile becomes when rendered | ||||||
|   /// (optionally used to scale the src image). |   /// (optionally used to scale the src image). | ||||||
|   late int destTileSize; |   late int destTileSize; | ||||||
|  |  | ||||||
|  |   late final Rect _center; | ||||||
|  |   late final Rect _dst; | ||||||
|  |  | ||||||
|   /// Creates a nine-box instance. |   /// Creates a nine-box instance. | ||||||
|   /// |   /// | ||||||
|   /// [sprite] is the 3x3 grid and [tileSize] is the size of each tile. |   /// [sprite] is the 3x3 grid and [tileSize] is the size of each tile. | ||||||
|   /// The src sprite must a square of size 3*[tileSize]. |   /// The src sprite must be a square of size 3*[tileSize]. | ||||||
|   /// |   /// | ||||||
|   /// If [tileSize] is not provided, the width of the sprite is assumed as the |   /// If [tileSize] is not provided, the width of the sprite is assumed as the | ||||||
|   /// size. Otherwise the width and height properties of the sprite are ignored. |   /// size. Otherwise the width and height properties of the sprite are ignored. | ||||||
| @ -35,61 +38,25 @@ class NineTileBox { | |||||||
|   /// If [destTileSize] is not provided, the evaluated [tileSize] is used |   /// If [destTileSize] is not provided, the evaluated [tileSize] is used | ||||||
|   /// instead (so no scaling happens). |   /// instead (so no scaling happens). | ||||||
|   NineTileBox(this.sprite, {int? tileSize, int? destTileSize}) |   NineTileBox(this.sprite, {int? tileSize, int? destTileSize}) | ||||||
|       : tileSize = tileSize ?? sprite.src.width.toInt() { |       : tileSize = tileSize ?? sprite.src.width ~/ 3 { | ||||||
|     this.destTileSize = destTileSize ?? this.tileSize; |     this.destTileSize = destTileSize ?? this.tileSize; | ||||||
|  |     final centerEdge = this.tileSize.toDouble(); | ||||||
|  |     _center = Rect.fromLTWH(centerEdge, centerEdge, centerEdge, centerEdge); | ||||||
|  |     _dst = Rect.fromLTWH(0, 0, this.destTileSize * 3, this.destTileSize * 3); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /// Renders this nine box with the dimensions provided by [rect]. |   /// Renders this nine box with the dimensions provided by [dst]. | ||||||
|   void drawRect(Canvas c, Rect rect) { |   void drawRect(Canvas c, [Rect? dst]) { | ||||||
|     final position = Vector2(rect.left, rect.top); |     c.drawImageNine(sprite.image, _center, dst ?? _dst, _whitePaint); | ||||||
|     final size = Vector2(rect.width, rect.height); |  | ||||||
|     draw(c, position, size); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /// Renders this nine box as a rectangle at [position] with size [size]. |   /// Renders this nine box as a rectangle at [position] with size [size]. | ||||||
|   void draw(Canvas c, Vector2 position, Vector2 size) { |   void draw(Canvas c, Vector2 position, Vector2 size) { | ||||||
|     // corners |     c.drawImageNine( | ||||||
|     _drawTile(c, _getDest(position), 0, 0); |       sprite.image, | ||||||
|     final bottomLeft = position + Vector2(0, size.y - destTileSize); |       _center, | ||||||
|     _drawTile(c, _getDest(bottomLeft), 0, 2); |       Rect.fromLTWH(position.x, position.y, size.x, size.y), | ||||||
|     final topRight = position + Vector2(size.x - destTileSize, 0); |       _whitePaint, | ||||||
|     _drawTile(c, _getDest(topRight), 2, 0); |     ); | ||||||
|     final bottomRight = Vector2(topRight.x, bottomLeft.y); |  | ||||||
|     _drawTile(c, _getDest(bottomRight), 2, 2); |  | ||||||
|  |  | ||||||
|     // horizontal sides |  | ||||||
|     final mx = size.x - 2 * destTileSize; |  | ||||||
|     final middleLeft = position + Vector2Extension.fromInts(destTileSize, 0); |  | ||||||
|     _drawTile(c, _getDest(middleLeft, width: mx), 1, 0); |  | ||||||
|     final middleRight = middleLeft + Vector2(0, size.y - destTileSize); |  | ||||||
|     _drawTile(c, _getDest(middleRight, width: mx), 1, 2); |  | ||||||
|  |  | ||||||
|     // vertical sides |  | ||||||
|     final my = size.y - 2 * destTileSize; |  | ||||||
|     final topCenter = position + Vector2Extension.fromInts(0, destTileSize); |  | ||||||
|     _drawTile(c, _getDest(topCenter, height: my), 0, 1); |  | ||||||
|     final bottomCenter = topCenter + Vector2(size.x - destTileSize, 0); |  | ||||||
|     _drawTile(c, _getDest(bottomCenter, height: my), 2, 1); |  | ||||||
|  |  | ||||||
|     // center |  | ||||||
|     final center = position + Vector2.all(destTileSize.toDouble()); |  | ||||||
|     _drawTile(c, _getDest(center, width: mx, height: my), 1, 1); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Rect _getDest(Vector2 position, {double? width, double? height}) { |  | ||||||
|     final w = width ?? _destTileSizeDouble; |  | ||||||
|     final h = height ?? _destTileSizeDouble; |  | ||||||
|     return Rect.fromLTWH(position.x, position.y, w, h); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   double get _tileSizeDouble => tileSize.toDouble(); |  | ||||||
|  |  | ||||||
|   double get _destTileSizeDouble => destTileSize.toDouble(); |  | ||||||
|  |  | ||||||
|   void _drawTile(Canvas c, Rect dest, int i, int j) { |  | ||||||
|     final xSrc = sprite.src.left + _tileSizeDouble * i; |  | ||||||
|     final ySrc = sprite.src.top + _tileSizeDouble * j; |  | ||||||
|     final src = Rect.fromLTWH(xSrc, ySrc, _tileSizeDouble, _tileSizeDouble); |  | ||||||
|     c.drawImageRect(sprite.image, src, dest, _whitePaint); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,10 +1,11 @@ | |||||||
| import 'dart:ui' as ui; | import 'dart:ui' as ui; | ||||||
|  |  | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
| import 'package:flutter/widgets.dart'; | import 'package:flutter/widgets.dart'; | ||||||
|  |  | ||||||
| import '../../assets.dart'; | import '../../assets.dart'; | ||||||
| import '../../flame.dart'; | import '../../flame.dart'; | ||||||
| import '../extensions/vector2.dart'; | import '../nine_tile_box.dart' as non_widget; | ||||||
| import '../sprite.dart'; | import '../sprite.dart'; | ||||||
| import 'base_future_builder.dart'; | import 'base_future_builder.dart'; | ||||||
|  |  | ||||||
| @ -15,117 +16,32 @@ class _Painter extends CustomPainter { | |||||||
|   final ui.Image image; |   final ui.Image image; | ||||||
|   final double tileSize; |   final double tileSize; | ||||||
|   final double destTileSize; |   final double destTileSize; | ||||||
|  |   late final non_widget.NineTileBox _nineTileBox; | ||||||
|  |  | ||||||
|   _Painter({ |   _Painter({ | ||||||
|     required this.image, |     required this.image, | ||||||
|     required this.tileSize, |     required this.tileSize, | ||||||
|     required this.destTileSize, |     required this.destTileSize, | ||||||
|   }); |   }) : _nineTileBox = non_widget.NineTileBox( | ||||||
|  |           Sprite(image), | ||||||
|   Sprite _getSpriteTile(double x, double y) => |           tileSize: tileSize.toInt(), | ||||||
|       Sprite(image, srcPosition: Vector2(x, y), srcSize: Vector2.all(tileSize)); |           destTileSize: destTileSize.toInt(), | ||||||
|  |         ); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   void paint(Canvas canvas, Size size) { |   void paint(Canvas canvas, Size size) { | ||||||
|     final topLeftCorner = _getSpriteTile(0, 0); |     _nineTileBox.drawRect(canvas, Offset.zero & size); | ||||||
|     final topRightCorner = _getSpriteTile(tileSize * 2, 0); |  | ||||||
|  |  | ||||||
|     final bottomLeftCorner = _getSpriteTile(0, 2 * tileSize); |  | ||||||
|     final bottomRightCorner = _getSpriteTile(tileSize * 2, 2 * tileSize); |  | ||||||
|  |  | ||||||
|     final topSide = _getSpriteTile(tileSize, 0); |  | ||||||
|     final bottomSide = _getSpriteTile(tileSize, tileSize * 2); |  | ||||||
|  |  | ||||||
|     final leftSide = _getSpriteTile(0, tileSize); |  | ||||||
|     final rightSide = _getSpriteTile(tileSize * 2, tileSize); |  | ||||||
|  |  | ||||||
|     final middle = _getSpriteTile(tileSize, tileSize); |  | ||||||
|  |  | ||||||
|     final horizontalWidget = size.width - destTileSize * 2; |  | ||||||
|     final verticalHeight = size.height - destTileSize * 2; |  | ||||||
|  |  | ||||||
|     void render(Sprite sprite, double x, double y, double w, double h) { |  | ||||||
|       sprite.render(canvas, position: Vector2(x, y), size: Vector2(w, h)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Middle |  | ||||||
|     render( |  | ||||||
|       middle, |  | ||||||
|       destTileSize, |  | ||||||
|       destTileSize, |  | ||||||
|       horizontalWidget, |  | ||||||
|       verticalHeight, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     // Top and bottom side |  | ||||||
|     render( |  | ||||||
|       topSide, |  | ||||||
|       destTileSize, |  | ||||||
|       0, |  | ||||||
|       horizontalWidget, |  | ||||||
|       destTileSize, |  | ||||||
|     ); |  | ||||||
|     render( |  | ||||||
|       bottomSide, |  | ||||||
|       destTileSize, |  | ||||||
|       size.height - destTileSize, |  | ||||||
|       horizontalWidget, |  | ||||||
|       destTileSize, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     // Left and right side |  | ||||||
|     render( |  | ||||||
|       leftSide, |  | ||||||
|       0, |  | ||||||
|       destTileSize, |  | ||||||
|       destTileSize, |  | ||||||
|       verticalHeight, |  | ||||||
|     ); |  | ||||||
|     render( |  | ||||||
|       rightSide, |  | ||||||
|       size.width - destTileSize, |  | ||||||
|       destTileSize, |  | ||||||
|       destTileSize, |  | ||||||
|       verticalHeight, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     // Corners |  | ||||||
|     render( |  | ||||||
|       topLeftCorner, |  | ||||||
|       0, |  | ||||||
|       0, |  | ||||||
|       destTileSize, |  | ||||||
|       destTileSize, |  | ||||||
|     ); |  | ||||||
|     render( |  | ||||||
|       topRightCorner, |  | ||||||
|       size.width - destTileSize, |  | ||||||
|       0, |  | ||||||
|       destTileSize, |  | ||||||
|       destTileSize, |  | ||||||
|     ); |  | ||||||
|     render( |  | ||||||
|       bottomLeftCorner, |  | ||||||
|       0, |  | ||||||
|       size.height - destTileSize, |  | ||||||
|       destTileSize, |  | ||||||
|       destTileSize, |  | ||||||
|     ); |  | ||||||
|     render( |  | ||||||
|       bottomRightCorner, |  | ||||||
|       size.width - destTileSize, |  | ||||||
|       size.height - destTileSize, |  | ||||||
|       destTileSize, |  | ||||||
|       destTileSize, |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   bool shouldRepaint(_) => false; |   bool shouldRepaint(_) => false; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @Deprecated('Renamed to [NineTileBoxWidget]') | ||||||
|  | typedef NineTileBox = NineTileBoxWidget; | ||||||
|  |  | ||||||
| /// A [StatelessWidget] that renders NineTileBox | /// A [StatelessWidget] that renders NineTileBox | ||||||
| class NineTileBox extends StatelessWidget { | class NineTileBoxWidget extends StatelessWidget { | ||||||
|   final Future<ui.Image> Function() _imageFuture; |   final Future<ui.Image> Function() _imageFuture; | ||||||
|  |  | ||||||
|   /// The size of the tile on the image |   /// The size of the tile on the image | ||||||
| @ -144,7 +60,7 @@ class NineTileBox extends StatelessWidget { | |||||||
|   /// A builder function that is called while the loading is on the way |   /// A builder function that is called while the loading is on the way | ||||||
|   final WidgetBuilder? loadingBuilder; |   final WidgetBuilder? loadingBuilder; | ||||||
|  |  | ||||||
|   NineTileBox({ |   NineTileBoxWidget({ | ||||||
|     required ui.Image image, |     required ui.Image image, | ||||||
|     required this.tileSize, |     required this.tileSize, | ||||||
|     required this.destTileSize, |     required this.destTileSize, | ||||||
| @ -157,7 +73,7 @@ class NineTileBox extends StatelessWidget { | |||||||
|   })  : _imageFuture = (() => Future.value(image)), |   })  : _imageFuture = (() => Future.value(image)), | ||||||
|         super(key: key); |         super(key: key); | ||||||
|  |  | ||||||
|   NineTileBox.asset({ |   NineTileBoxWidget.asset({ | ||||||
|     required String path, |     required String path, | ||||||
|     required this.tileSize, |     required this.tileSize, | ||||||
|     required this.destTileSize, |     required this.destTileSize, | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Lukas Klingsbo
					Lukas Klingsbo