mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-01 10:38:17 +08:00
* rename animation stuff * rename sprite animation component * pr stuff
This commit is contained in:
@ -5,6 +5,7 @@
|
||||
|
||||
## [next]
|
||||
- Preventing some crashed that could happen on web when some methods were called
|
||||
- Rename Animation to SpriteAnimation
|
||||
|
||||
## 0.24.0
|
||||
- Outsourcing SVG support to an external package
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
# Sprite Sheet Animations in Flutter
|
||||
|
||||
### UPDATE 05/27/2020
|
||||
### UPDATE 09/04/2020
|
||||
|
||||
As for Flame 0.22.0 there is a new way to use Animations and Sprites inside your widget tree.
|
||||
As for Flame 1.0, the `animationAsWidget` has been removed in favor of a direct usage of `SpriteAnimationWidget`.
|
||||
|
||||
Flame now includes a widget catalog and inside it you will find `AnimationWidget` and `SpriteWidget`.
|
||||
Flame now includes a widget catalog and inside it you will find `SpriteAnimationWidget` and `SpriteWidget`.
|
||||
|
||||
Check the example mentioned on this article to see the updated version.
|
||||
|
||||
## Introduction
|
||||
|
||||
Flutter provides lots of cool and slick animations out of the box, most related to movement and tweens (continuous changes in size, position, color, et cetera). However, one particular thing that it's really hard to do using only the native APIs is a simple sprite sheet animation. Or any sprite sheet handling, for that matter.
|
||||
Flutter provides lots of cool and slick animations out of the box, most related to movement and tweens (continuous changes in size, position, color, etc). However, one particular thing that it's really hard to do using only the native APIs is a simple sprite sheet animation. Or any sprite sheet handling, for that matter.
|
||||
|
||||
A sprite sheet is a single image that has multiple images (sprites) inside, each one being accessed via it's defining rectangle (x, y, width, and height). Maybe every sprite inside has the same size, like a tileset; for example:
|
||||
|
||||
@ -118,10 +118,10 @@ Let's you have your `build` method in one of your pages; pretty normal Flutter s
|
||||
}
|
||||
```
|
||||
|
||||
Note that it could be any component, however complex, inside your widgets tree. Note also that I have omitted the "magic" of the equation here. How is it that we create a component for an animation? Very basically (more details in the flame tutorial), Flame provides components, one of which is the `AnimationComponent` that receives an `Animation` object describing the animation and does exactly what we want. All components live inside a `Game` instance, that can add custom logic relating to the game loop. For our case, we just want to create a simple, empty game and add a single `AnimationComponent` with a simple `Animation` inside. So Flame provides a helper to do that, the `Flame.util.animationAsWidget` method. It takes the size of the object as a Flame's `Position` instance (a generic class to represent a pair of doubles), and also takes in an `Animation` instance representing our frame list. To use that, let's import both `Flame` and the `Animation` class. However, since Flutter adds it's own animation classes, let's use an alias in order to not mess up the names. Therefore, add these imports to the top of the file:
|
||||
Note that it could be any component, however complex, inside your widgets tree. Note also that I have omitted the "magic" of the equation here. How is it that we create a component for an animation? Very basically (more details in the flame tutorial), Flame provides components, one of which is the `SpriteAnimationComponent` that receives a `SpriteAnimation` object describing the animation and does exactly what we want. All components live inside a `Game` instance, that can add custom logic relating to the game loop. For our case, we just want to create a simple, empty game and add a single `AnimationComponent` with a simple `Animation` inside. So Flame provides a helper to do that, the `Flame.util.animationAsWidget` method. It takes the size of the object as a Flame's `Position` instance (a generic class to represent a pair of doubles), and also takes in an `Animation` instance representing our frame list. To use that, let's import both `Flame` and the `Animation` class. However, since Flutter adds it's own animation classes, let's use an alias in order to not mess up the names. Therefore, add these imports to the top of the file:
|
||||
|
||||
```dart
|
||||
import 'package:flame/animation.dart' as animation; // imports the Animation class under animation.Animation
|
||||
import 'package:flame/sprite_animation.dart'; // imports the SpriteAnimation class
|
||||
import 'package:flame/flame.dart'; // imports the Flame helper class
|
||||
import 'package:flame/position.dart'; // imports the Position class
|
||||
```
|
||||
@ -129,7 +129,7 @@ import 'package:flame/position.dart'; // imports the Position class
|
||||
How we do the magic then? Just add the following to your widget tree:
|
||||
|
||||
```dart
|
||||
Flame.util.animationAsWidget(Position(WIDTH, HEIGHT), animation.Animation.sequenced('minotaur.png', AMOUNT, textureWidth: FRAME_WIDTH))
|
||||
Flame.util.animationAsWidget(Position(WIDTH, HEIGHT), SpriteAnimation.sequenced('minotaur.png', AMOUNT, textureWidth: FRAME_WIDTH))
|
||||
```
|
||||
|
||||
The first parameter's `WIDTH` and `HEIGHT` are the actual size of the widget on the screen. This does not need to match the sprite size, as Flame will scale it for you. You might, however, wanna keep the aspect, so things don't get distorted. In your case, the minotaur asset is a row of 96x96 pixels, so squares, therefore we can scale keeping `WIDTH/HEIGHT = 1`. We will choose the size as 256 px. The `sequenced` constructor is a helper that easily creates the animation assuming equal-sized frames in a row, in order. You can configure the start x, start y, texture width and height, but those will default gracefully to (0,0) and the actual width and height of the file. You can create your animation passing in the frame list, each frame with a different step time and sprite (source rectangle).
|
||||
|
||||
1
doc/examples/.gitignore
vendored
1
doc/examples/.gitignore
vendored
@ -2,5 +2,6 @@ web/
|
||||
ios/
|
||||
android/
|
||||
test/
|
||||
macos/
|
||||
|
||||
generated_plugin_registrant.dart
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# animation_widget
|
||||
|
||||
A sample Flame project to showcase the animationAsWidget method to render easy sprite sheet animations on regular (non-game) Flutter apps.
|
||||
A sample Flame project to showcase the SpriteAnimationWidget to render easy sprite sheet animations on regular (non-game) Flutter apps.
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/animation.dart' as animation;
|
||||
import 'package:flame/sprite_animation.dart';
|
||||
import 'package:flame/sprite.dart';
|
||||
import 'package:flame/spritesheet.dart';
|
||||
import 'package:flame/position.dart';
|
||||
@ -10,7 +10,7 @@ import 'package:flame/widgets/sprite_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Sprite _sprite;
|
||||
animation.Animation _animation;
|
||||
SpriteAnimation _animation;
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
@ -91,7 +91,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
Container(
|
||||
width: 200,
|
||||
height: 200,
|
||||
child: AnimationWidget(animation: _animation),
|
||||
child: SpriteAnimationWidget(animation: _animation),
|
||||
),
|
||||
const Text('Neat, hum?'),
|
||||
const Text(
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
name: animation_widget
|
||||
description: A sample Flame project to showcase the animationAsWidget method.
|
||||
description: A sample Flame project to showcase the SpriteAnimationWidget widget.
|
||||
|
||||
version: 0.1.0
|
||||
|
||||
|
||||
@ -2,8 +2,8 @@ import 'package:flame/gestures.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/animation.dart' as flame_animation;
|
||||
import 'package:flame/components/animation_component.dart';
|
||||
import 'package:flame/sprite_animation.dart';
|
||||
import 'package:flame/components/sprite_animation_component.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() async {
|
||||
@ -16,7 +16,7 @@ void main() async {
|
||||
}
|
||||
|
||||
class MyGame extends BaseGame with TapDetector {
|
||||
final animation = flame_animation.Animation.sequenced(
|
||||
final animation = SpriteAnimation.sequenced(
|
||||
'chopper.png',
|
||||
4,
|
||||
textureWidth: 48,
|
||||
@ -28,7 +28,8 @@ class MyGame extends BaseGame with TapDetector {
|
||||
void addAnimation(double x, double y) {
|
||||
const textureWidth = 291.0;
|
||||
const textureHeight = 178.0;
|
||||
final animationComponent = AnimationComponent.sequenced(
|
||||
|
||||
final animationComponent = SpriteAnimationComponent.sequenced(
|
||||
291,
|
||||
178,
|
||||
'creature.png',
|
||||
@ -40,6 +41,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
loop: false,
|
||||
destroyOnFinish: true,
|
||||
);
|
||||
|
||||
animationComponent.x = x - textureWidth / 2;
|
||||
animationComponent.y = y - textureHeight / 2;
|
||||
|
||||
@ -55,12 +57,15 @@ class MyGame extends BaseGame with TapDetector {
|
||||
size = screenSize;
|
||||
|
||||
const s = 100.0;
|
||||
final animationComponent = AnimationComponent(s, s, animation);
|
||||
final animationComponent = SpriteAnimationComponent(s, s, animation);
|
||||
animationComponent.x = size.width / 2 - s;
|
||||
animationComponent.y = s;
|
||||
|
||||
final reversedAnimationComponent =
|
||||
AnimationComponent(s, s, animation.reversed());
|
||||
final reversedAnimationComponent = SpriteAnimationComponent(
|
||||
s,
|
||||
s,
|
||||
animation.reversed(),
|
||||
);
|
||||
reversedAnimationComponent.x = size.width / 2;
|
||||
reversedAnimationComponent.y = s;
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/animation.dart' as flame_animation;
|
||||
import 'package:flame/components/animation_component.dart';
|
||||
import 'package:flame/sprite_animation.dart';
|
||||
import 'package:flame/components/sprite_animation_component.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() async {
|
||||
@ -17,11 +17,11 @@ class MyGame extends BaseGame {
|
||||
}
|
||||
|
||||
void _start() async {
|
||||
final animation = await flame_animation.Animation.fromAsepriteData(
|
||||
final animation = await SpriteAnimation.fromAsepriteData(
|
||||
'chopper.png',
|
||||
'chopper.json',
|
||||
);
|
||||
final animationComponent = AnimationComponent(200, 200, animation);
|
||||
final animationComponent = SpriteAnimationComponent(200, 200, animation);
|
||||
|
||||
animationComponent.x = (size.width / 2) - 100;
|
||||
animationComponent.y = (size.height / 2) - 100;
|
||||
|
||||
@ -2,7 +2,7 @@ import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/animation.dart';
|
||||
import 'package:flame/sprite_animation.dart';
|
||||
import 'package:flame/components/component.dart';
|
||||
import 'package:flame/flare_animation.dart';
|
||||
import 'package:flame/particles/circle_particle.dart';
|
||||
@ -392,10 +392,10 @@ class MyGame extends BaseGame {
|
||||
);
|
||||
}
|
||||
|
||||
/// An [AnimationParticle] takes a Flame [Animation]
|
||||
/// An [SpriteAnimationParticle] takes a Flame [SpriteAnimation]
|
||||
/// and plays it during the particle lifespan.
|
||||
Particle animationParticle() {
|
||||
return AnimationParticle(
|
||||
return SpriteAnimationParticle(
|
||||
animation: getBoomAnimation(),
|
||||
size: Position(128, 128),
|
||||
);
|
||||
@ -550,8 +550,8 @@ class MyGame extends BaseGame {
|
||||
return list[rnd.nextInt(list.length)];
|
||||
}
|
||||
|
||||
/// Sample "explosion" animation for [AnimationParticle] example
|
||||
Animation getBoomAnimation() {
|
||||
/// Sample "explosion" animation for [SpriteAnimationParticle] example
|
||||
SpriteAnimation getBoomAnimation() {
|
||||
const columns = 8;
|
||||
const rows = 8;
|
||||
const frames = columns * rows;
|
||||
@ -569,7 +569,7 @@ class MyGame extends BaseGame {
|
||||
(i) => spritesheet.getSprite(i ~/ rows, i % columns),
|
||||
);
|
||||
|
||||
return Animation.spriteList(sprites);
|
||||
return SpriteAnimation.spriteList(sprites);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import 'package:flame/animation.dart' as flame_animation;
|
||||
import 'package:flame/components/animation_component.dart';
|
||||
import 'package:flame/sprite_animation.dart';
|
||||
import 'package:flame/components/sprite_animation_component.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -12,7 +12,7 @@ void main() async {
|
||||
}
|
||||
|
||||
class MyGame extends BaseGame {
|
||||
final animation = flame_animation.Animation.sequenced(
|
||||
final animation = SpriteAnimation.sequenced(
|
||||
'chopper.png',
|
||||
4,
|
||||
textureWidth: 48,
|
||||
@ -20,8 +20,8 @@ class MyGame extends BaseGame {
|
||||
stepTime: 0.15,
|
||||
);
|
||||
|
||||
AnimationComponent buildAnimation() {
|
||||
final ac = AnimationComponent(100, 100, animation);
|
||||
SpriteAnimationComponent buildAnimation() {
|
||||
final ac = SpriteAnimationComponent(100, 100, animation);
|
||||
ac.x = size.width / 2 - ac.width / 2;
|
||||
return ac;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flame/components/animation_component.dart';
|
||||
import 'package:flame/components/sprite_animation_component.dart';
|
||||
import 'package:flame/components/sprite_component.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
@ -56,11 +56,11 @@ class MyGame extends BaseGame {
|
||||
spriteSheet.createAnimation(0, stepTime: 0.1, to: 7);
|
||||
final ghostAnimation = spriteSheet.createAnimation(1, stepTime: 0.1, to: 7);
|
||||
|
||||
final vampireComponent = AnimationComponent(80, 90, vampireAnimation)
|
||||
final vampireComponent = SpriteAnimationComponent(80, 90, vampireAnimation)
|
||||
..x = 150
|
||||
..y = 100;
|
||||
|
||||
final ghostComponent = AnimationComponent(80, 90, ghostAnimation)
|
||||
final ghostComponent = SpriteAnimationComponent(80, 90, ghostAnimation)
|
||||
..x = 150
|
||||
..y = 220;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import 'package:flame/animation.dart';
|
||||
import 'package:flame/components/animation_component.dart';
|
||||
import 'package:flame/sprite_animation.dart';
|
||||
import 'package:flame/components/sprite_animation_component.dart';
|
||||
import 'package:flame/components/tiled_component.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
@ -27,10 +27,10 @@ class TiledGame extends BaseGame {
|
||||
return;
|
||||
}
|
||||
objGroup.tmxObjects.forEach((TmxObject obj) {
|
||||
final comp = AnimationComponent(
|
||||
final comp = SpriteAnimationComponent(
|
||||
20.0,
|
||||
20.0,
|
||||
Animation.sequenced(
|
||||
SpriteAnimation.sequenced(
|
||||
'coins.png',
|
||||
8,
|
||||
textureWidth: 20,
|
||||
|
||||
@ -129,7 +129,7 @@ void main() async {
|
||||
(ctx) => Container(
|
||||
width: ctx.numberProperty('container width', 400),
|
||||
height: ctx.numberProperty('container height', 200),
|
||||
child: AnimationWidget(
|
||||
child: SpriteAnimationWidget(
|
||||
animation: _animation,
|
||||
playing: ctx.boolProperty('playing', true),
|
||||
anchor: parseAnchor(
|
||||
|
||||
@ -48,7 +48,7 @@ The render method will do nothing while the sprite has not been loaded, so you d
|
||||
|
||||
All render methods from the Sprite class can receive a `Paint` instance as the optional named parameter `overridePaint` that parameter will override the current `Sprite` paint instance for that render call.
|
||||
|
||||
Sprites can also be used as widgets, to do so just use `Flame.util.spriteAsWidget`
|
||||
Sprites can also be used as widgets, to do so just use `SpriteWidget` class.
|
||||
|
||||
A complete example using sprite as widgets can be found [here](/doc/examples/animation_widget).
|
||||
|
||||
@ -178,9 +178,6 @@ Animations, after created, have an update and render method; the latter renders
|
||||
|
||||
Animations are normally used inside `AnimationComponent`s, but custom components with several Animations can be created as well.
|
||||
|
||||
|
||||
Animations can also be used as widgets, to do so, just use `Flame.util.animationAsWidget`
|
||||
|
||||
A complete example of using animations as widgets can be found [here](/doc/examples/animation_widget).
|
||||
|
||||
## FlareAnimation
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import '../animation.dart';
|
||||
import '../sprite_animation.dart';
|
||||
import 'position_component.dart';
|
||||
|
||||
class AnimationComponent extends PositionComponent {
|
||||
Animation animation;
|
||||
class SpriteAnimationComponent extends PositionComponent {
|
||||
SpriteAnimation animation;
|
||||
Paint overridePaint;
|
||||
bool destroyOnFinish = false;
|
||||
|
||||
AnimationComponent(
|
||||
SpriteAnimationComponent(
|
||||
double width,
|
||||
double height,
|
||||
this.animation, {
|
||||
@ -18,9 +18,9 @@ class AnimationComponent extends PositionComponent {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
AnimationComponent.empty();
|
||||
SpriteAnimationComponent.empty();
|
||||
|
||||
AnimationComponent.sequenced(
|
||||
SpriteAnimationComponent.sequenced(
|
||||
double width,
|
||||
double height,
|
||||
String imagePath,
|
||||
@ -36,7 +36,7 @@ class AnimationComponent extends PositionComponent {
|
||||
}) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
animation = Animation.sequenced(
|
||||
animation = SpriteAnimation.sequenced(
|
||||
imagePath,
|
||||
amount,
|
||||
amountPerRow: amountPerRow,
|
||||
@ -2,17 +2,17 @@ import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../animation.dart';
|
||||
import '../sprite_animation.dart';
|
||||
import '../particle.dart';
|
||||
import '../position.dart';
|
||||
|
||||
class AnimationParticle extends Particle {
|
||||
final Animation animation;
|
||||
class SpriteAnimationParticle extends Particle {
|
||||
final SpriteAnimation animation;
|
||||
final Position size;
|
||||
final Paint overridePaint;
|
||||
final bool alignAnimationTime;
|
||||
|
||||
AnimationParticle({
|
||||
SpriteAnimationParticle({
|
||||
@required this.animation,
|
||||
this.size,
|
||||
this.overridePaint,
|
||||
|
||||
@ -3,8 +3,8 @@ import 'dart:convert';
|
||||
import 'flame.dart';
|
||||
import 'sprite.dart';
|
||||
|
||||
/// Represents a single animation frame.
|
||||
class Frame {
|
||||
/// Represents a single sprite animation frame.
|
||||
class SpriteAnimationFrame {
|
||||
/// The [Sprite] to be displayed.
|
||||
Sprite sprite;
|
||||
|
||||
@ -12,15 +12,15 @@ class Frame {
|
||||
double stepTime;
|
||||
|
||||
/// Create based on the parameters.
|
||||
Frame(this.sprite, this.stepTime);
|
||||
SpriteAnimationFrame(this.sprite, this.stepTime);
|
||||
}
|
||||
|
||||
typedef OnCompleteAnimation = void Function();
|
||||
typedef OnCompleteSpriteAnimation = void Function();
|
||||
|
||||
/// Represents an animation, that is, a list of sprites that change with time.
|
||||
class Animation {
|
||||
/// Represents a sprite animation, that is, a list of sprites that change with time.
|
||||
class SpriteAnimation {
|
||||
/// The frames that compose this animation.
|
||||
List<Frame> frames = [];
|
||||
List<SpriteAnimationFrame> frames = [];
|
||||
|
||||
/// Index of the current frame that should be displayed.
|
||||
int currentIndex = 0;
|
||||
@ -37,23 +37,23 @@ class Animation {
|
||||
bool loop = true;
|
||||
|
||||
/// Registered method to be triggered when the animation complete.
|
||||
OnCompleteAnimation onCompleteAnimation;
|
||||
OnCompleteSpriteAnimation onComplete;
|
||||
|
||||
/// Creates an animation given a list of frames.
|
||||
Animation(this.frames, {this.loop = true});
|
||||
SpriteAnimation(this.frames, {this.loop = true});
|
||||
|
||||
/// Creates an empty animation
|
||||
Animation.empty();
|
||||
SpriteAnimation.empty();
|
||||
|
||||
/// Creates an animation based on the parameters.
|
||||
///
|
||||
/// All frames have the same [stepTime].
|
||||
Animation.spriteList(List<Sprite> sprites,
|
||||
SpriteAnimation.spriteList(List<Sprite> sprites,
|
||||
{double stepTime, this.loop = true}) {
|
||||
if (sprites.isEmpty) {
|
||||
throw Exception('You must have at least one frame!');
|
||||
}
|
||||
frames = sprites.map((s) => Frame(s, stepTime)).toList();
|
||||
frames = sprites.map((s) => SpriteAnimationFrame(s, stepTime)).toList();
|
||||
}
|
||||
|
||||
/// Automatically creates a sequenced animation, that is, an animation based on a sprite sheet.
|
||||
@ -71,7 +71,7 @@ class Animation {
|
||||
/// For example, if you have a sprite sheet where each row is an animation, and each frame is 32x32
|
||||
/// Animation.sequenced('sheet.png', 8, textureY: 32.0 * i, textureWidth: 32.0, textureHeight: 32.0);
|
||||
/// This will create the i-th animation on the 'sheet.png', given it has 8 frames.
|
||||
Animation.sequenced(
|
||||
SpriteAnimation.sequenced(
|
||||
String imagePath,
|
||||
int amount, {
|
||||
int amountPerRow,
|
||||
@ -83,7 +83,7 @@ class Animation {
|
||||
this.loop = true,
|
||||
}) : assert(amountPerRow == null || amount >= amountPerRow) {
|
||||
amountPerRow ??= amount;
|
||||
frames = List<Frame>(amount);
|
||||
frames = List<SpriteAnimationFrame>(amount);
|
||||
for (var i = 0; i < amount; i++) {
|
||||
final Sprite sprite = Sprite(
|
||||
imagePath,
|
||||
@ -92,12 +92,12 @@ class Animation {
|
||||
width: textureWidth,
|
||||
height: textureHeight,
|
||||
);
|
||||
frames[i] = Frame(sprite, stepTime);
|
||||
frames[i] = SpriteAnimationFrame(sprite, stepTime);
|
||||
}
|
||||
}
|
||||
|
||||
/// Works just like [Animation.sequenced], but it takes a list of variable [stepTimes], associating each one with one frame in the sequence.
|
||||
Animation.variableSequenced(
|
||||
/// Works just like [SpriteAnimation.sequenced], but it takes a list of variable [stepTimes], associating each one with one frame in the sequence.
|
||||
SpriteAnimation.variableSequenced(
|
||||
String imagePath,
|
||||
int amount,
|
||||
List<double> stepTimes, {
|
||||
@ -109,7 +109,7 @@ class Animation {
|
||||
this.loop = true,
|
||||
}) : assert(amountPerRow == null || amount >= amountPerRow) {
|
||||
amountPerRow ??= amount;
|
||||
frames = List<Frame>(amount);
|
||||
frames = List<SpriteAnimationFrame>(amount);
|
||||
for (var i = 0; i < amount; i++) {
|
||||
final Sprite sprite = Sprite(
|
||||
imagePath,
|
||||
@ -118,7 +118,7 @@ class Animation {
|
||||
width: textureWidth,
|
||||
height: textureHeight,
|
||||
);
|
||||
frames[i] = Frame(sprite, stepTimes[i]);
|
||||
frames[i] = SpriteAnimationFrame(sprite, stepTimes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,7 +127,7 @@ class Animation {
|
||||
///
|
||||
/// [imagePath]: Source of the sprite sheet animation
|
||||
/// [dataPath]: Animation's exported data in json format
|
||||
static Future<Animation> fromAsepriteData(
|
||||
static Future<SpriteAnimation> fromAsepriteData(
|
||||
String imagePath, String dataPath) async {
|
||||
final String content = await Flame.assets.readFile(dataPath);
|
||||
final Map<String, dynamic> json = jsonDecode(content);
|
||||
@ -151,14 +151,14 @@ class Animation {
|
||||
height: height.toDouble(),
|
||||
);
|
||||
|
||||
return Frame(sprite, stepTime);
|
||||
return SpriteAnimationFrame(sprite, stepTime);
|
||||
});
|
||||
|
||||
return Animation(frames.toList(), loop: true);
|
||||
return SpriteAnimation(frames.toList(), loop: true);
|
||||
}
|
||||
|
||||
/// The current frame that should be displayed.
|
||||
Frame get currentFrame => frames[currentIndex];
|
||||
SpriteAnimationFrame get currentFrame => frames[currentIndex];
|
||||
|
||||
/// Returns whether the animation is on the last frame.
|
||||
bool get isLastFrame => currentIndex == frames.length - 1;
|
||||
@ -209,7 +209,7 @@ class Animation {
|
||||
return;
|
||||
}
|
||||
if (!loop && isLastFrame) {
|
||||
onCompleteAnimation?.call();
|
||||
onComplete?.call();
|
||||
return;
|
||||
}
|
||||
while (clock > currentFrame.stepTime) {
|
||||
@ -226,8 +226,8 @@ class Animation {
|
||||
}
|
||||
|
||||
/// Returns a new Animation based on this animation, but with its frames in reversed order
|
||||
Animation reversed() {
|
||||
return Animation(frames.reversed.toList(), loop: loop);
|
||||
SpriteAnimation reversed() {
|
||||
return SpriteAnimation(frames.reversed.toList(), loop: loop);
|
||||
}
|
||||
|
||||
/// Whether all sprites composing this animation are loaded.
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:meta/meta.dart';
|
||||
import 'sprite.dart';
|
||||
import 'animation.dart';
|
||||
import 'sprite_animation.dart';
|
||||
|
||||
import 'dart:ui';
|
||||
|
||||
@ -85,10 +85,10 @@ class SpriteSheet {
|
||||
return s;
|
||||
}
|
||||
|
||||
/// Creates an animation from this SpriteSheet
|
||||
/// 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
|
||||
Animation createAnimation(int row,
|
||||
SpriteAnimation createAnimation(int row,
|
||||
{double stepTime, bool loop = true, int from = 0, int to}) {
|
||||
final spriteRow = _sprites[row];
|
||||
|
||||
@ -98,7 +98,7 @@ class SpriteSheet {
|
||||
|
||||
final spriteList = spriteRow.sublist(from, to);
|
||||
|
||||
return Animation.spriteList(
|
||||
return SpriteAnimation.spriteList(
|
||||
spriteList,
|
||||
stepTime: stepTime,
|
||||
loop: loop,
|
||||
|
||||
@ -4,13 +4,7 @@ import 'dart:ui';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart' as widgets;
|
||||
|
||||
import 'animation.dart';
|
||||
import 'game/base_game.dart';
|
||||
import 'game/embedded_game_widget.dart';
|
||||
import 'sprite.dart';
|
||||
import 'components/animation_component.dart';
|
||||
import 'position.dart';
|
||||
|
||||
/// Some utilities that did not fit anywhere else.
|
||||
@ -159,43 +153,4 @@ class Util {
|
||||
fn(c);
|
||||
c.translate(-p.x, -p.y);
|
||||
}
|
||||
|
||||
/// Returns a regular Flutter widget representing this animation, rendered with the specified size.
|
||||
///
|
||||
/// This actually creates an [EmbeddedGameWidget] with a [SimpleGame] whose only content is an [AnimationComponent] created from the provided [animation].
|
||||
/// You can use this implementation as base to easily create your own widgets based on more complex games.
|
||||
/// This is intended to be used by non-game apps that want to add a sprite sheet animation.
|
||||
///
|
||||
@Deprecated('Use SpriteAnimation instead')
|
||||
widgets.Widget animationAsWidget(Position size, Animation animation) {
|
||||
return EmbeddedGameWidget(
|
||||
BaseGame()..add(AnimationComponent(size.x, size.y, animation)),
|
||||
size: size,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns a regular Flutter widget representing this sprite, rendered with the specified size.
|
||||
///
|
||||
/// This will create a [CustomPaint] widget using a [CustomPainter] for rendering the [Sprite]
|
||||
/// Be aware that the Sprite must have been loaded, otherwise it can't be rendered
|
||||
///
|
||||
@Deprecated('Use SpriteWidget instead')
|
||||
widgets.CustomPaint spriteAsWidget(Size size, Sprite sprite) =>
|
||||
widgets.CustomPaint(size: size, painter: _SpriteCustomPainter(sprite));
|
||||
}
|
||||
|
||||
class _SpriteCustomPainter extends widgets.CustomPainter {
|
||||
final Sprite _sprite;
|
||||
|
||||
_SpriteCustomPainter(this._sprite);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
if (_sprite.loaded()) {
|
||||
_sprite.render(canvas, width: size.width, height: size.height);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(widgets.CustomPainter old) => false;
|
||||
}
|
||||
|
||||
@ -1,17 +1,23 @@
|
||||
import 'package:flutter/material.dart' hide Animation;
|
||||
import 'package:flame/animation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flame/sprite_animation.dart';
|
||||
|
||||
import 'dart:math';
|
||||
|
||||
import '../anchor.dart';
|
||||
import './sprite_widget.dart';
|
||||
|
||||
class AnimationWidget extends StatefulWidget {
|
||||
final Animation animation;
|
||||
/// A [StatefulWidget] that render a [SpriteAnimation].
|
||||
class SpriteAnimationWidget extends StatefulWidget {
|
||||
/// The [SpriteAnimation] to be rendered
|
||||
final SpriteAnimation animation;
|
||||
|
||||
/// The positioning [Anchor]
|
||||
final Anchor anchor;
|
||||
|
||||
/// Should the [animation] be playing or not
|
||||
final bool playing;
|
||||
|
||||
AnimationWidget({
|
||||
SpriteAnimationWidget({
|
||||
this.animation,
|
||||
this.playing = true,
|
||||
this.anchor = Anchor.topLeft,
|
||||
@ -21,7 +27,7 @@ class AnimationWidget extends StatefulWidget {
|
||||
State createState() => _AnimationWidget();
|
||||
}
|
||||
|
||||
class _AnimationWidget extends State<AnimationWidget>
|
||||
class _AnimationWidget extends State<SpriteAnimationWidget>
|
||||
with SingleTickerProviderStateMixin {
|
||||
AnimationController _controller;
|
||||
double _lastUpdated;
|
||||
@ -52,7 +58,7 @@ class _AnimationWidget extends State<AnimationWidget>
|
||||
});
|
||||
});
|
||||
|
||||
widget.animation.onCompleteAnimation = _pauseAnimation;
|
||||
widget.animation.onComplete = _pauseAnimation;
|
||||
|
||||
if (widget.playing) {
|
||||
_initAnimation();
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import 'package:flame/widgets/animation_widget.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'dart:math';
|
||||
@ -5,8 +6,14 @@ import 'dart:math';
|
||||
import '../sprite.dart';
|
||||
import '../anchor.dart';
|
||||
|
||||
/// A [StatefulWidget] that renders a still [Sprite].
|
||||
///
|
||||
/// To render an animation, use [SpriteAnimationWidget].
|
||||
class SpriteWidget extends StatelessWidget {
|
||||
/// The [Sprite] to be rendered
|
||||
final Sprite sprite;
|
||||
|
||||
/// The positioning [Anchor] for the [sprite]
|
||||
final Anchor anchor;
|
||||
|
||||
SpriteWidget({
|
||||
@ -17,19 +24,19 @@ class SpriteWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(_) {
|
||||
return Container(
|
||||
child: CustomPaint(painter: _SpritePainer(sprite, anchor)),
|
||||
child: CustomPaint(painter: _SpritePainter(sprite, anchor)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SpritePainer extends CustomPainter {
|
||||
class _SpritePainter extends CustomPainter {
|
||||
final Sprite _sprite;
|
||||
final Anchor _anchor;
|
||||
|
||||
_SpritePainer(this._sprite, this._anchor);
|
||||
_SpritePainter(this._sprite, this._anchor);
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_SpritePainer old) {
|
||||
bool shouldRepaint(_SpritePainter old) {
|
||||
return old._sprite != _sprite || old._anchor != _anchor;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user