mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-02 11:28:20 +08:00
Improve IsometricTileMap and Spritesheet classes
This commit is contained in:
@ -19,13 +19,10 @@ void main() async {
|
|||||||
|
|
||||||
final _animationSpriteSheet = SpriteSheet(
|
final _animationSpriteSheet = SpriteSheet(
|
||||||
image: image,
|
image: image,
|
||||||
columns: 19,
|
srcSize: Vector2.all(96),
|
||||||
rows: 1,
|
|
||||||
textureWidth: 96,
|
|
||||||
textureHeight: 96,
|
|
||||||
);
|
);
|
||||||
_animation = _animationSpriteSheet.createAnimation(
|
_animation = _animationSpriteSheet.createAnimation(
|
||||||
0,
|
row: 0,
|
||||||
stepTime: 0.2,
|
stepTime: 0.2,
|
||||||
to: 19,
|
to: 19,
|
||||||
);
|
);
|
||||||
@ -50,7 +47,7 @@ class MyHomePage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
Vector2 _position = Vector2(256.0, 256.0);
|
Vector2 _position = Vector2.all(256);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -60,9 +57,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
|
|
||||||
void changePosition() async {
|
void changePosition() async {
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
setState(() {
|
setState(() => _position += Vector2.all(10));
|
||||||
_position = Vector2(10 + _position.x, 10 + _position.y);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _clickFab(GlobalKey<ScaffoldState> key) {
|
void _clickFab(GlobalKey<ScaffoldState> key) {
|
||||||
|
|||||||
41
doc/examples/isometric/.gitignore
vendored
Normal file
41
doc/examples/isometric/.gitignore
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
/build/
|
||||||
|
|
||||||
|
# Web related
|
||||||
|
lib/generated_plugin_registrant.dart
|
||||||
|
|
||||||
|
# Symbolication related
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
# Obfuscation related
|
||||||
|
app.*.map.json
|
||||||
@ -4,6 +4,7 @@ import 'package:flame/game.dart';
|
|||||||
import 'package:flame/components/isometric_tile_map_component.dart';
|
import 'package:flame/components/isometric_tile_map_component.dart';
|
||||||
import 'package:flame/gestures.dart';
|
import 'package:flame/gestures.dart';
|
||||||
import 'package:flame/sprite.dart';
|
import 'package:flame/sprite.dart';
|
||||||
|
import 'package:flame/spritesheet.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart' hide Image;
|
import 'package:flutter/material.dart' hide Image;
|
||||||
|
|
||||||
@ -25,7 +26,9 @@ class Selector extends SpriteComponent {
|
|||||||
|
|
||||||
Selector(double s, Image image)
|
Selector(double s, Image image)
|
||||||
: super.fromSprite(
|
: super.fromSprite(
|
||||||
Vector2.all(s), Sprite(image, srcSize: Vector2.all(32.0)));
|
Vector2.all(s),
|
||||||
|
Sprite(image, srcSize: Vector2.all(32.0)),
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void render(Canvas canvas) {
|
void render(Canvas canvas) {
|
||||||
@ -48,7 +51,7 @@ class MyGame extends BaseGame with MouseMovementDetector {
|
|||||||
final selectorImage = await images.load('selector.png');
|
final selectorImage = await images.load('selector.png');
|
||||||
|
|
||||||
final tilesetImage = await images.load('tiles.png');
|
final tilesetImage = await images.load('tiles.png');
|
||||||
final tileset = IsometricTileset(tilesetImage, 32);
|
final tileset = SpriteSheet(image: tilesetImage, srcSize: Vector2.all(32));
|
||||||
final matrix = [
|
final matrix = [
|
||||||
[3, 1, 1, 1, 0, 0],
|
[3, 1, 1, 1, 0, 0],
|
||||||
[-1, 1, 2, 1, 0, 0],
|
[-1, 1, 2, 1, 0, 0],
|
||||||
@ -58,7 +61,11 @@ class MyGame extends BaseGame with MouseMovementDetector {
|
|||||||
[1, 3, 3, 3, 0, 2],
|
[1, 3, 3, 3, 0, 2],
|
||||||
];
|
];
|
||||||
add(
|
add(
|
||||||
base = IsometricTileMapComponent(tileset, matrix, destTileSize: s)
|
base = IsometricTileMapComponent(
|
||||||
|
tileset,
|
||||||
|
matrix,
|
||||||
|
destTileSize: Vector2.all(s.toDouble()),
|
||||||
|
)
|
||||||
..x = x
|
..x = x
|
||||||
..y = y,
|
..y = y,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -532,16 +532,14 @@ class MyGame extends BaseGame {
|
|||||||
const rows = 8;
|
const rows = 8;
|
||||||
const frames = columns * rows;
|
const frames = columns * rows;
|
||||||
final spriteImage = images.fromCache('boom3.png');
|
final spriteImage = images.fromCache('boom3.png');
|
||||||
final spritesheet = SpriteSheet(
|
final spritesheet = SpriteSheet.fromColsAndRows(
|
||||||
rows: rows,
|
|
||||||
columns: columns,
|
|
||||||
image: spriteImage,
|
image: spriteImage,
|
||||||
textureWidth: spriteImage.width ~/ columns,
|
columns: columns,
|
||||||
textureHeight: spriteImage.height ~/ rows,
|
rows: rows,
|
||||||
);
|
);
|
||||||
final sprites = List<Sprite>.generate(
|
final sprites = List<Sprite>.generate(
|
||||||
frames,
|
frames,
|
||||||
(i) => spritesheet.getSprite(i ~/ rows, i % columns),
|
(i) => spritesheet.getSpriteById(i),
|
||||||
);
|
);
|
||||||
|
|
||||||
return SpriteAnimation.spriteList(sprites);
|
return SpriteAnimation.spriteList(sprites);
|
||||||
|
|||||||
BIN
doc/examples/spritesheet/flutter_01.png
Normal file
BIN
doc/examples/spritesheet/flutter_01.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
@ -1,9 +1,9 @@
|
|||||||
import 'package:flame/extensions/vector2.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flame/components/sprite_animation_component.dart';
|
import 'package:flame/components/sprite_animation_component.dart';
|
||||||
import 'package:flame/components/sprite_component.dart';
|
import 'package:flame/components/sprite_component.dart';
|
||||||
|
import 'package:flame/extensions/vector2.dart';
|
||||||
import 'package:flame/game.dart';
|
import 'package:flame/game.dart';
|
||||||
import 'package:flame/spritesheet.dart';
|
import 'package:flame/spritesheet.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
@ -16,16 +16,14 @@ class MyGame extends BaseGame {
|
|||||||
Future<void> onLoad() async {
|
Future<void> onLoad() async {
|
||||||
final spriteSheet = SpriteSheet(
|
final spriteSheet = SpriteSheet(
|
||||||
image: await images.load('spritesheet.png'),
|
image: await images.load('spritesheet.png'),
|
||||||
textureWidth: 16,
|
srcSize: Vector2(16.0, 18.0),
|
||||||
textureHeight: 18,
|
|
||||||
columns: 11,
|
|
||||||
rows: 2,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
final vampireAnimation =
|
final vampireAnimation =
|
||||||
spriteSheet.createAnimation(0, stepTime: 0.1, to: 7);
|
spriteSheet.createAnimation(row: 0, stepTime: 0.1, to: 7);
|
||||||
final ghostAnimation = spriteSheet.createAnimation(1, stepTime: 0.1, to: 7);
|
final ghostAnimation =
|
||||||
final spriteSize = Vector2(80, 90);
|
spriteSheet.createAnimation(row: 1, stepTime: 0.1, to: 7);
|
||||||
|
final spriteSize = Vector2(80.0, 90.0);
|
||||||
|
|
||||||
final vampireComponent =
|
final vampireComponent =
|
||||||
SpriteAnimationComponent(spriteSize, vampireAnimation)
|
SpriteAnimationComponent(spriteSize, vampireAnimation)
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flame/extensions/vector2.dart';
|
||||||
import 'package:flutter/material.dart' hide Animation;
|
import 'package:flutter/material.dart' hide Animation;
|
||||||
import 'package:flame/flame.dart';
|
import 'package:flame/flame.dart';
|
||||||
import 'package:flame/sprite.dart';
|
import 'package:flame/sprite.dart';
|
||||||
@ -64,10 +65,7 @@ void main() async {
|
|||||||
final buttonsImage = await Flame.images.load('buttons.png');
|
final buttonsImage = await Flame.images.load('buttons.png');
|
||||||
final _buttons = SpriteSheet(
|
final _buttons = SpriteSheet(
|
||||||
image: buttonsImage,
|
image: buttonsImage,
|
||||||
textureHeight: 20,
|
srcSize: Vector2(60, 20),
|
||||||
textureWidth: 60,
|
|
||||||
columns: 1,
|
|
||||||
rows: 2,
|
|
||||||
);
|
);
|
||||||
dashbook.storiesOf('SpriteButton').decorator(CenterDecorator()).add(
|
dashbook.storiesOf('SpriteButton').decorator(CenterDecorator()).add(
|
||||||
'default',
|
'default',
|
||||||
@ -119,13 +117,10 @@ void main() async {
|
|||||||
final pteroImage = await Flame.images.load('bomb_ptero.png');
|
final pteroImage = await Flame.images.load('bomb_ptero.png');
|
||||||
final _animationSpriteSheet = SpriteSheet(
|
final _animationSpriteSheet = SpriteSheet(
|
||||||
image: pteroImage,
|
image: pteroImage,
|
||||||
textureHeight: 32,
|
srcSize: Vector2(48, 32),
|
||||||
textureWidth: 48,
|
|
||||||
columns: 4,
|
|
||||||
rows: 1,
|
|
||||||
);
|
);
|
||||||
final _animation = _animationSpriteSheet.createAnimation(
|
final _animation = _animationSpriteSheet.createAnimation(
|
||||||
0,
|
row: 0,
|
||||||
stepTime: 0.2,
|
stepTime: 0.2,
|
||||||
to: 3,
|
to: 3,
|
||||||
loop: true,
|
loop: true,
|
||||||
|
|||||||
@ -281,10 +281,7 @@ import 'package:flame/spritesheet.dart';
|
|||||||
|
|
||||||
final spritesheet = SpriteSheet(
|
final spritesheet = SpriteSheet(
|
||||||
image: imageInstance,
|
image: imageInstance,
|
||||||
textureWidth: 16,
|
srcSize: Vector2.all(16.0),
|
||||||
textureHeight: 16,
|
|
||||||
columns: 10,
|
|
||||||
rows: 2,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
final animation = spritesheet.createAnimation(0, stepTime: 0.1);
|
final animation = spritesheet.createAnimation(0, stepTime: 0.1);
|
||||||
|
|||||||
@ -259,10 +259,7 @@ A `Particle` which embeds a Flame `Animation`. By default, aligns `Animation`s `
|
|||||||
```dart
|
```dart
|
||||||
final spritesheet = SpriteSheet(
|
final spritesheet = SpriteSheet(
|
||||||
imageName: 'spritesheet.png',
|
imageName: 'spritesheet.png',
|
||||||
textureWidth: 16,
|
srcSize: Vector2.all(16.0),
|
||||||
textureHeight: 16,
|
|
||||||
columns: 10,
|
|
||||||
rows: 2
|
|
||||||
);
|
);
|
||||||
|
|
||||||
game.add(
|
game.add(
|
||||||
|
|||||||
@ -1,56 +1,11 @@
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flame/components/position_component.dart';
|
import 'position_component.dart';
|
||||||
|
|
||||||
import '../sprite.dart';
|
|
||||||
import '../extensions/vector2.dart';
|
import '../extensions/vector2.dart';
|
||||||
|
import '../spritesheet.dart';
|
||||||
|
|
||||||
/// This represents an isometric tileset to be used in a tilemap.
|
/// This is just a pair of <int, int>.
|
||||||
///
|
|
||||||
/// It's basically a grid of squares, each square has a tile, in order.
|
|
||||||
/// The block ids are calculated going row per row, left to right, top to
|
|
||||||
/// bottom.
|
|
||||||
///
|
|
||||||
/// This class will cache the usage of sprites to improve performance.
|
|
||||||
class IsometricTileset {
|
|
||||||
/// The image for this tileset.
|
|
||||||
final Image tileset;
|
|
||||||
|
|
||||||
/// The size of each square block within the image.
|
|
||||||
///
|
|
||||||
/// The image width and height must be multiples of this number.
|
|
||||||
final int size;
|
|
||||||
|
|
||||||
final Map<int, Sprite> _spriteCache = {};
|
|
||||||
|
|
||||||
IsometricTileset(this.tileset, this.size);
|
|
||||||
|
|
||||||
/// Compute the number of columns the image has
|
|
||||||
/// by using the image width and tile size.
|
|
||||||
int get columns => tileset.width ~/ size;
|
|
||||||
|
|
||||||
/// Compute the number of rows the image has
|
|
||||||
/// by using the image height and tile size.
|
|
||||||
int get rows => tileset.height ~/ size;
|
|
||||||
|
|
||||||
/// Get a sprite to render one specific tile given its id.
|
|
||||||
///
|
|
||||||
/// The ids are assigned left to right, top to bottom, row per row.
|
|
||||||
/// The returned sprite will be cached, so don't modify it!
|
|
||||||
Sprite getTile(int tileId) {
|
|
||||||
return _spriteCache[tileId] ??= _computeTile(tileId);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sprite _computeTile(int tileId) {
|
|
||||||
final i = tileId % columns;
|
|
||||||
final j = tileId ~/ columns;
|
|
||||||
final s = size.toDouble();
|
|
||||||
return Sprite(tileset,
|
|
||||||
srcPosition: Vector2(s * i, s * j), srcSize: Vector2.all(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This is just a pair of int, int.
|
|
||||||
///
|
///
|
||||||
/// Represents a position in a matrix, or in this case, on the tilemap.
|
/// Represents a position in a matrix, or in this case, on the tilemap.
|
||||||
class Block {
|
class Block {
|
||||||
@ -70,29 +25,29 @@ class Block {
|
|||||||
/// property.
|
/// property.
|
||||||
class IsometricTileMapComponent extends PositionComponent {
|
class IsometricTileMapComponent extends PositionComponent {
|
||||||
/// This is the tileset that will be used to render this map.
|
/// This is the tileset that will be used to render this map.
|
||||||
IsometricTileset tileset;
|
SpriteSheet tileset;
|
||||||
|
|
||||||
/// The positions of each block will be placed respecting this matrix.
|
/// The positions of each block will be placed respecting this matrix.
|
||||||
List<List<int>> matrix;
|
List<List<int>> matrix;
|
||||||
|
|
||||||
/// Optionally provide a new tile size to render it scaled.
|
/// Optionally provide a new tile size to render it scaled.
|
||||||
int destTileSize;
|
Vector2 destTileSize;
|
||||||
|
|
||||||
IsometricTileMapComponent(this.tileset, this.matrix, {this.destTileSize});
|
IsometricTileMapComponent(this.tileset, this.matrix, {this.destTileSize});
|
||||||
|
|
||||||
/// This is the size the tiles will be drawn (either original or overwritten).
|
/// This is the size the tiles will be drawn (either original or overwritten).
|
||||||
int get effectiveTileSize => destTileSize ?? tileset.size;
|
Vector2 get effectiveTileSize => destTileSize ?? tileset.srcSize;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void render(Canvas c) {
|
void render(Canvas c) {
|
||||||
super.render(c);
|
super.render(c);
|
||||||
|
|
||||||
final size = Vector2.all(effectiveTileSize.toDouble());
|
final size = effectiveTileSize;
|
||||||
for (int i = 0; i < matrix.length; i++) {
|
for (int i = 0; i < matrix.length; i++) {
|
||||||
for (int j = 0; j < matrix[i].length; j++) {
|
for (int j = 0; j < matrix[i].length; j++) {
|
||||||
final element = matrix[i][j];
|
final element = matrix[i][j];
|
||||||
if (element != -1) {
|
if (element != -1) {
|
||||||
final sprite = tileset.getTile(element);
|
final sprite = tileset.getSpriteById(element);
|
||||||
final p = getBlockPositionInts(j, i);
|
final p = getBlockPositionInts(j, i);
|
||||||
sprite.renderRect(c, p.toPositionedRect(size));
|
sprite.renderRect(c, p.toPositionedRect(size));
|
||||||
}
|
}
|
||||||
@ -108,8 +63,9 @@ class IsometricTileMapComponent extends PositionComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vector2 getBlockPositionInts(int i, int j) {
|
Vector2 getBlockPositionInts(int i, int j) {
|
||||||
final s = effectiveTileSize.toDouble() / 2;
|
final pos = Vector2(i.toDouble(), j.toDouble())
|
||||||
return cartToIso(Vector2(i * s, j * s)) - Vector2(s, 0);
|
..multiply(effectiveTileSize / 2);
|
||||||
|
return cartToIso(pos) - Vector2(effectiveTileSize.x / 2, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a coordinate from the isometric space to the cartesian space.
|
/// Converts a coordinate from the isometric space to the cartesian space.
|
||||||
@ -130,10 +86,9 @@ class IsometricTileMapComponent extends PositionComponent {
|
|||||||
///
|
///
|
||||||
/// This can be used to handle clicks or hovers.
|
/// This can be used to handle clicks or hovers.
|
||||||
Block getBlock(Vector2 p) {
|
Block getBlock(Vector2 p) {
|
||||||
final s = effectiveTileSize.toDouble() / 2;
|
|
||||||
final cart = isoToCart(p - position);
|
final cart = isoToCart(p - position);
|
||||||
final px = cart.x ~/ s;
|
final px = cart.x ~/ (effectiveTileSize.x / 2);
|
||||||
final py = cart.y ~/ s;
|
final py = cart.y ~/ (effectiveTileSize.y / 2);
|
||||||
return Block(px, py);
|
return Block(px, py);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -48,8 +48,11 @@ class SpriteAnimation {
|
|||||||
/// Creates an animation based on the parameters.
|
/// Creates an animation based on the parameters.
|
||||||
///
|
///
|
||||||
/// All frames have the same [stepTime].
|
/// All frames have the same [stepTime].
|
||||||
SpriteAnimation.spriteList(List<Sprite> sprites,
|
SpriteAnimation.spriteList(
|
||||||
{double stepTime, this.loop = true}) {
|
List<Sprite> sprites, {
|
||||||
|
double stepTime,
|
||||||
|
this.loop = true,
|
||||||
|
}) {
|
||||||
if (sprites.isEmpty) {
|
if (sprites.isEmpty) {
|
||||||
throw Exception('You must have at least one frame!');
|
throw Exception('You must have at least one frame!');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,66 +6,95 @@ import 'sprite.dart';
|
|||||||
import 'sprite_animation.dart';
|
import 'sprite_animation.dart';
|
||||||
import 'extensions/vector2.dart';
|
import 'extensions/vector2.dart';
|
||||||
|
|
||||||
/// Utility class to help extract animations and sprites from a spritesheet image
|
/// Utility class to help extract animations and sprites from a sprite sheet image.
|
||||||
|
///
|
||||||
|
/// A sprite sheet is a single image in which several regions can be defined as individual sprites.
|
||||||
|
/// For the purposes of this class, all of these regions must be identically sized rectangles.
|
||||||
|
/// You can use the [Sprite] class directly if you want to have varying shapes.
|
||||||
|
///
|
||||||
|
/// Each sprite in this sheet can be identified either by it's (row, col) pair or
|
||||||
|
/// by it's "id", which is basically it's sequenced index if the image is put in a
|
||||||
|
/// single line. The sprites can be used to compose an animation easily if they
|
||||||
|
/// all the frames happen to be sequentially on the same row.
|
||||||
|
/// Sprites are lazily generated but cached.
|
||||||
class SpriteSheet {
|
class SpriteSheet {
|
||||||
int textureWidth;
|
/// The src image from which each sprite will be generated.
|
||||||
int textureHeight;
|
final Image image;
|
||||||
int columns;
|
|
||||||
int rows;
|
|
||||||
|
|
||||||
List<List<Sprite>> _sprites;
|
/// The size of each rectangle within the image that define each sprite.
|
||||||
|
///
|
||||||
|
/// For example, if this sprite sheet is a tile map, this would be the tile size.
|
||||||
|
/// If it's an animation sheet, this would be the frame size.
|
||||||
|
final Vector2 srcSize;
|
||||||
|
|
||||||
|
final Map<int, Sprite> _spriteCache = {};
|
||||||
|
|
||||||
|
/// Creates a sprite sheet given the image and the tile size.
|
||||||
SpriteSheet({
|
SpriteSheet({
|
||||||
@required Image image,
|
@required this.image,
|
||||||
@required this.textureWidth,
|
@required this.srcSize,
|
||||||
@required this.textureHeight,
|
});
|
||||||
@required this.columns,
|
|
||||||
@required this.rows,
|
SpriteSheet.fromColsAndRows({
|
||||||
}) {
|
@required this.image,
|
||||||
_sprites = List.generate(
|
@required int columns,
|
||||||
rows,
|
@required int rows,
|
||||||
(y) => List.generate(
|
}) : srcSize = Vector2(
|
||||||
columns,
|
image.width / columns,
|
||||||
(x) => _mapImagePath(image, textureWidth, textureHeight, x, y),
|
image.height / rows,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Compute the number of columns the image has
|
||||||
|
/// by using the image width and tile size.
|
||||||
|
int get columns => image.width ~/ srcSize.x;
|
||||||
|
|
||||||
|
/// Compute the number of rows the image has
|
||||||
|
/// by using the image height and tile size.
|
||||||
|
int get rows => image.height ~/ srcSize.y;
|
||||||
|
|
||||||
|
/// Gets the sprite in the position (row, column) on the sprite sheet grid.
|
||||||
|
///
|
||||||
|
/// This is lazily computed and cached for your convenience.
|
||||||
|
Sprite getSprite(int row, int column) {
|
||||||
|
return getSpriteById(row * columns + column);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sprite _mapImagePath(
|
/// Gets teh sprite with id [spriteId] from the grid.
|
||||||
Image image,
|
///
|
||||||
int textureWidth,
|
/// The ids are defined as starting at 0 on the top left and going
|
||||||
int textureHeight,
|
/// sequentially on each row.
|
||||||
int x,
|
/// This is lazily computed and cached for your convenience.
|
||||||
int y,
|
Sprite getSpriteById(int spriteId) {
|
||||||
) {
|
return _spriteCache[spriteId] ??= _computeSprite(spriteId);
|
||||||
final size = Vector2(textureWidth.toDouble(), textureHeight.toDouble());
|
}
|
||||||
|
|
||||||
|
Sprite _computeSprite(int spriteId) {
|
||||||
|
final i = (spriteId % columns).toDouble();
|
||||||
|
final j = (spriteId ~/ columns).toDouble();
|
||||||
return Sprite(
|
return Sprite(
|
||||||
image,
|
image,
|
||||||
srcPosition: Vector2(x.toDouble(), y.toDouble())..multiply(size),
|
srcPosition: Vector2(i, j)..multiply(srcSize),
|
||||||
srcSize: size,
|
srcSize: srcSize,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sprite getSprite(int row, int column) {
|
/// Creates a [SpriteAnimation] from this SpriteSheet, using the sequence
|
||||||
final Sprite s = _sprites[row][column];
|
/// of sprites on a given row.
|
||||||
|
|
||||||
assert(s != null, 'No sprite found for row $row and column $column');
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a sprite animation from this SpriteSheet
|
|
||||||
///
|
///
|
||||||
/// An [from] and a [to] parameter can be specified to create an animation from a subset of the columns on the row
|
/// [from] and [to] can be specified to create an animation
|
||||||
SpriteAnimation createAnimation(int row,
|
/// from a subset of the columns on the row
|
||||||
{double stepTime, bool loop = true, int from = 0, int to}) {
|
SpriteAnimation createAnimation({
|
||||||
final spriteRow = _sprites[row];
|
@required int row,
|
||||||
|
@required double stepTime,
|
||||||
|
bool loop = true,
|
||||||
|
int from = 0,
|
||||||
|
int to,
|
||||||
|
}) {
|
||||||
|
to ??= columns;
|
||||||
|
|
||||||
assert(spriteRow != null, 'There is no row for $row index');
|
final spriteList = List<int>.generate(to - from, (i) => from + i)
|
||||||
|
.map((e) => getSprite(row, e))
|
||||||
to ??= spriteRow.length;
|
.toList();
|
||||||
|
|
||||||
final spriteList = spriteRow.sublist(from, to);
|
|
||||||
|
|
||||||
return SpriteAnimation.spriteList(
|
return SpriteAnimation.spriteList(
|
||||||
spriteList,
|
spriteList,
|
||||||
|
|||||||
Reference in New Issue
Block a user