Tiles and Tileset displaying in Dart
Jump to navigation
Jump to search
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 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';
// import 'package:roguelike_engine_demo/render/renderloop.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;
}