Difference between revisions of "Tiles and Tileset displaying in Dart"
Jump to navigation
Jump to search
(Created page with "== Dart Implementation of Tiles and Tileset in Dart == The code below demonstrates how to load a tileset and access individual tiles. It reads in the tileset, then renders...") |
m |
||
(One intermediate revision by the same user not shown) | |||
Line 1: | Line 1: | ||
The code below demonstrates how to load a tileset and access individual tiles. It reads in the tileset, then renders its tiles in a grid consisting of the indiviual tiles. The code consits of these classes: | |||
'''MyApp''' | |||
Renders a GridView of the tileset. | |||
'''TileSetFactory''' | |||
Returns an individual TileWidget. It holds one Widget for each tile. Tiles are accessed via (column,row) coordinates. | |||
'''TileWidget''' | |||
Paints an individual tile. | |||
'''SquarePainter''' | |||
Paints a square section of the tileset. | |||
Line 27: | Line 30: | ||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||
import 'package:flutter/services.dart'; | import 'package:flutter/services.dart'; | ||
void main() { | void main() { |
Latest revision as of 23:26, 6 November 2023
The code below demonstrates how to load a tileset and access individual tiles. It reads in the tileset, then renders its tiles in a grid consisting of the indiviual tiles. The code consits of these classes:
MyApp
Renders a GridView of the tileset.
TileSetFactory
Returns an individual TileWidget. It holds one Widget for each tile. Tiles are accessed via (column,row) coordinates.
TileWidget
Paints an individual tile.
SquarePainter
Paints a square section of the tileset.
The tileset used in the example can be downloaded here:
https://rltiles.sourceforge.net/download.html
Dart Implementation
import 'dart:async';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final String _tilesetPath = 'assets/tilesets/dctile/tile.png';
final int _tileWidth = 32;
final int _tileHeight = 32;
late final Future<ui.Image> _tilesetFuture = _loadUiImage(_tilesetPath);
MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: FutureBuilder<ui.Image>(
future: _tilesetFuture,
builder: (ctx, snapshot) {
if (snapshot.hasData == false) {
return SizedBox(
width: _tileWidth.toDouble(),
height: _tileHeight.toDouble(),
);
}
if (snapshot.hasError == true) {
return SizedBox(
width: _tileWidth.toDouble(),
height: _tileHeight.toDouble(),
);
}
final tileset = snapshot.data!;
final TileSetFactory factory =
TileSetFactory(tileset, _tileWidth, _tileHeight);
final List<Row> rows = [];
for (int row = 0; row < factory.rows; row++) {
final List<TileWidget> cells = [];
for (int col = 0; col < factory.columns; col++) {
cells.add(factory.getTile(col, row));
}
rows.add(Row(children: cells));
}
return InteractiveViewer(
scaleEnabled: false,
constrained: false,
child: Column(children: rows),
);
},
),
),
);
}
Future<ui.Image> _loadUiImage(String assetPath) async {
final data = await rootBundle.load(assetPath);
final list = Uint8List.view(data.buffer);
final completer = Completer<ui.Image>();
ui.decodeImageFromList(list, completer.complete);
return completer.future;
}
}
// ---------------------------------------------------------------------
//
// ---------------------------------------------------------------------
class TileSetFactory {
final ui.Image _tileset;
final int _tileWidth;
final int _tileHeight;
final Map<String, TileWidget> _tiles = {};
TileSetFactory(this._tileset, this._tileWidth, this._tileHeight);
int get columns => _tileset.width ~/ _tileWidth;
int get rows => _tileset.height ~/ _tileHeight;
int get length => columns * rows;
TileWidget getTile(int col, int row) {
final key = '${col}_$row';
_tiles.putIfAbsent(
key,
() => TileWidget(
_tileset,
col * _tileWidth,
row * _tileHeight,
_tileWidth,
_tileHeight,
),
);
return _tiles[key]!;
}
}
// ---------------------------------------------------------------------
//
// ---------------------------------------------------------------------
class TileWidget extends StatelessWidget {
final int left;
final int top;
final int width;
final int height;
final ui.Image image;
const TileWidget(this.image, this.left, this.top, this.width, this.height,
{super.key});
@override
Widget build(BuildContext context) {
return CustomPaint(
size: Size(width.toDouble(), height.toDouble()),
painter: SquarePainter(image, left, top, width, height));
}
}
// ---------------------------------------------------------------------
//
// ---------------------------------------------------------------------
class SquarePainter extends CustomPainter {
final int left;
final int top;
final int width;
final int height;
final ui.Image tileset;
SquarePainter(this.tileset, this.left, this.top, this.width, this.height);
@override
void paint(Canvas canvas, Size size) {
canvas.drawAtlas(
tileset,
[
RSTransform.fromComponents(
rotation: 0.0,
scale: 1.0,
anchorX: 0.0,
anchorY: 0.0,
translateX: 0.0,
translateY: 0.0)
],
[
Rect.fromLTWH(
left.toDouble(),
top.toDouble(),
width.toDouble(),
height.toDouble(),
)
],
[],
BlendMode.src,
null,
Paint(),
);
}
@override
bool shouldRepaint(SquarePainter oldDelegate) => false;
@override
bool shouldRebuildSemantics(SquarePainter oldDelegate) => false;
}