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/game.dart';
import 'package:flame/input.dart';
import 'package:flutter/material.dart';
class NineTileBoxExample extends FlameGame with TapDetector, DoubleTapDetector {
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.
''';
late NineTileBox nineTileBox;
final Vector2 boxSize = Vector2.all(300);
late NineTileBoxComponent nineTileBoxComponent;
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = Sprite(await images.load('nine-box.png'));
nineTileBox = NineTileBox(sprite, tileSize: 8, destTileSize: 24);
}
@override
void render(Canvas canvas) {
super.render(canvas);
final position = (size - boxSize) / 2;
nineTileBox.draw(canvas, position, boxSize);
final boxSize = Vector2.all(300);
final nineTileBox = NineTileBox(sprite, destTileSize: 148);
add(
nineTileBoxComponent = NineTileBoxComponent(
nineTileBox: nineTileBox,
position: size / 2,
size: boxSize,
anchor: Anchor.center,
),
);
}
@override
void onTap() {
boxSize.scale(1.2);
nineTileBoxComponent.scale.scale(1.2);
}
@override
void onDoubleTap() {
boxSize.scale(0.8);
nineTileBoxComponent.scale.scale(0.8);
}
}

View File

@ -6,9 +6,9 @@ Widget nineTileBoxBuilder(DashbookContext ctx) {
return Container(
width: ctx.numberProperty('width', 200),
height: ctx.numberProperty('height', 200),
child: NineTileBox.asset(
child: NineTileBoxWidget.asset(
path: 'nine-box.png',
tileSize: 8,
tileSize: 22,
destTileSize: 50,
child: const Center(
child: Text(

View File

@ -15,19 +15,22 @@ class NineTileBox {
static final _whitePaint = BasicPalette.white.paint();
/// 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.
int tileSize;
final int tileSize;
/// The size each tile becomes when rendered
/// (optionally used to scale the src image).
late int destTileSize;
late final Rect _center;
late final Rect _dst;
/// Creates a nine-box instance.
///
/// [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
/// 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
/// instead (so no scaling happens).
NineTileBox(this.sprite, {int? tileSize, int? destTileSize})
: tileSize = tileSize ?? sprite.src.width.toInt() {
: tileSize = tileSize ?? sprite.src.width ~/ 3 {
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].
void drawRect(Canvas c, Rect rect) {
final position = Vector2(rect.left, rect.top);
final size = Vector2(rect.width, rect.height);
draw(c, position, size);
/// Renders this nine box with the dimensions provided by [dst].
void drawRect(Canvas c, [Rect? dst]) {
c.drawImageNine(sprite.image, _center, dst ?? _dst, _whitePaint);
}
/// Renders this nine box as a rectangle at [position] with size [size].
void draw(Canvas c, Vector2 position, Vector2 size) {
// corners
_drawTile(c, _getDest(position), 0, 0);
final bottomLeft = position + Vector2(0, size.y - destTileSize);
_drawTile(c, _getDest(bottomLeft), 0, 2);
final topRight = position + Vector2(size.x - destTileSize, 0);
_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);
c.drawImageNine(
sprite.image,
_center,
Rect.fromLTWH(position.x, position.y, size.x, size.y),
_whitePaint,
);
}
}

View File

@ -1,10 +1,11 @@
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import '../../assets.dart';
import '../../flame.dart';
import '../extensions/vector2.dart';
import '../nine_tile_box.dart' as non_widget;
import '../sprite.dart';
import 'base_future_builder.dart';
@ -15,117 +16,32 @@ class _Painter extends CustomPainter {
final ui.Image image;
final double tileSize;
final double destTileSize;
late final non_widget.NineTileBox _nineTileBox;
_Painter({
required this.image,
required this.tileSize,
required this.destTileSize,
});
Sprite _getSpriteTile(double x, double y) =>
Sprite(image, srcPosition: Vector2(x, y), srcSize: Vector2.all(tileSize));
}) : _nineTileBox = non_widget.NineTileBox(
Sprite(image),
tileSize: tileSize.toInt(),
destTileSize: destTileSize.toInt(),
);
@override
void paint(Canvas canvas, Size size) {
final topLeftCorner = _getSpriteTile(0, 0);
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,
);
_nineTileBox.drawRect(canvas, Offset.zero & size);
}
@override
bool shouldRepaint(_) => false;
}
@Deprecated('Renamed to [NineTileBoxWidget]')
typedef NineTileBox = NineTileBoxWidget;
/// A [StatelessWidget] that renders NineTileBox
class NineTileBox extends StatelessWidget {
class NineTileBoxWidget extends StatelessWidget {
final Future<ui.Image> Function() _imageFuture;
/// 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
final WidgetBuilder? loadingBuilder;
NineTileBox({
NineTileBoxWidget({
required ui.Image image,
required this.tileSize,
required this.destTileSize,
@ -157,7 +73,7 @@ class NineTileBox extends StatelessWidget {
}) : _imageFuture = (() => Future.value(image)),
super(key: key);
NineTileBox.asset({
NineTileBoxWidget.asset({
required String path,
required this.tileSize,
required this.destTileSize,