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:
Lukas Klingsbo
2022-01-17 00:22:51 +01:00
committed by GitHub
parent dc37053fb6
commit d77e5efee5
5 changed files with 49 additions and 166 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 B

After

Width:  |  Height:  |  Size: 460 B

View File

@ -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);
} }
} }

View File

@ -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(

View File

@ -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);
} }
} }

View File

@ -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,