mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-02 20:13:50 +08:00
Vector2 for position and size on PositionComponent
This commit is contained in:
@ -7,6 +7,7 @@
|
||||
- Remove Position class in favor of new Vector2 extension
|
||||
- Remove Box2D as a dependency
|
||||
- Use isRelative on effects
|
||||
- Use Vector2 for position and size on PositionComponent
|
||||
|
||||
## 0.27.0
|
||||
- Improved the accuracy of the `FPSCounter` by using Flutter's internal frame timings.
|
||||
|
||||
@ -4,7 +4,7 @@ This class represent a single object on the screen, being a floating rectangle o
|
||||
|
||||
The base abstract class has the common expected methods update and render to be implemented.
|
||||
|
||||
The intermediate inheritance `PositionComponent` adds `x`, `y`, `width`, `height` and `angle` to your Components, as well as some useful methods like distance and angleBetween.
|
||||
The intermediate inheritance `PositionComponent` adds `position`, `size` and `angle` to your Components, as well as some useful methods like distance and angleBetween.
|
||||
|
||||
The most commonly used implementation, `SpriteComponent`, can be created with a `Sprite`:
|
||||
|
||||
@ -13,12 +13,11 @@ The most commonly used implementation, `SpriteComponent`, can be created with a
|
||||
|
||||
Sprite sprite = Sprite('player.png');
|
||||
|
||||
const size = 128.0;
|
||||
var player = SpriteComponent.fromSprite(size, size, sprite); // width, height, sprite
|
||||
final size = Vector2.all(128.0);
|
||||
var player = SpriteComponent.fromSprite(size, sprite); // width, height, sprite
|
||||
|
||||
// screen coordinates
|
||||
player.x = ... // 0 by default
|
||||
player.y = ... // 0 by default
|
||||
player.position = ... // Vector2(0.0, 0,0) by default
|
||||
player.angle = ... // 0 by default
|
||||
|
||||
player.render(canvas); // it will render only if the image is loaded and the x, y, width and height parameters are not null
|
||||
|
||||
@ -20,32 +20,26 @@ class MyGame extends BaseGame with TapDetector {
|
||||
final animation = SpriteAnimation.sequenced(
|
||||
'chopper.png',
|
||||
4,
|
||||
textureWidth: 48,
|
||||
textureHeight: 48,
|
||||
textureSize: Vector2.all(48),
|
||||
stepTime: 0.15,
|
||||
loop: true,
|
||||
);
|
||||
|
||||
void addAnimation(double x, double y) {
|
||||
const textureWidth = 291.0;
|
||||
const textureHeight = 178.0;
|
||||
final size = Vector2(291, 178);
|
||||
|
||||
final animationComponent = SpriteAnimationComponent.sequenced(
|
||||
291,
|
||||
178,
|
||||
size,
|
||||
'creature.png',
|
||||
18,
|
||||
amountPerRow: 10,
|
||||
textureWidth: textureWidth,
|
||||
textureHeight: textureHeight,
|
||||
textureSize: size,
|
||||
stepTime: 0.15,
|
||||
loop: false,
|
||||
destroyOnFinish: true,
|
||||
);
|
||||
|
||||
animationComponent.x = x - textureWidth / 2;
|
||||
animationComponent.y = y - textureHeight / 2;
|
||||
|
||||
animationComponent.position = animationComponent.position - size / 2;
|
||||
add(animationComponent);
|
||||
}
|
||||
|
||||
@ -57,18 +51,17 @@ class MyGame extends BaseGame with TapDetector {
|
||||
MyGame(Vector2 screenSize) {
|
||||
size = screenSize;
|
||||
|
||||
const s = 100.0;
|
||||
final animationComponent = SpriteAnimationComponent(s, s, animation);
|
||||
animationComponent.x = size.x / 2 - s;
|
||||
animationComponent.y = s;
|
||||
final spriteSize = Vector2.all(100.0);
|
||||
final animationComponent = SpriteAnimationComponent(spriteSize, animation);
|
||||
animationComponent.x = size.x / 2 - spriteSize.x;
|
||||
animationComponent.y = spriteSize.y;
|
||||
|
||||
final reversedAnimationComponent = SpriteAnimationComponent(
|
||||
s,
|
||||
s,
|
||||
spriteSize,
|
||||
animation.reversed(),
|
||||
);
|
||||
reversedAnimationComponent.x = size.x / 2;
|
||||
reversedAnimationComponent.y = s;
|
||||
reversedAnimationComponent.y = spriteSize.y;
|
||||
|
||||
add(animationComponent);
|
||||
add(reversedAnimationComponent);
|
||||
|
||||
@ -22,8 +22,9 @@ class MyGame extends BaseGame {
|
||||
'chopper.png',
|
||||
'chopper.json',
|
||||
);
|
||||
final animationComponent = SpriteAnimationComponent(200, 200, animation)
|
||||
..setPosition(size / 2 - Vector2(100, 100));
|
||||
final spriteSize = Vector2.all(200);
|
||||
final animationComponent = SpriteAnimationComponent(spriteSize, animation)
|
||||
..position = size / 2 - Vector2(100, 100);
|
||||
|
||||
add(animationComponent);
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
canvas.drawRect(size.toOriginRect(), black);
|
||||
canvas.drawRect(size.toRect(), black);
|
||||
final p = size / 2;
|
||||
regular.render(canvas, 'hit me!', p, anchor: Anchor.center);
|
||||
super.render(canvas);
|
||||
|
||||
@ -3,12 +3,13 @@ import 'package:flame/components/position_component.dart';
|
||||
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
|
||||
class Square extends PositionComponent {
|
||||
final Paint _paint;
|
||||
|
||||
Square(this._paint, double x, double y, {double angle = 0.0}) {
|
||||
width = 100;
|
||||
height = 100;
|
||||
size = Vector2(width, height);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.angle = angle;
|
||||
@ -18,6 +19,6 @@ class Square extends PositionComponent {
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
super.render(canvas);
|
||||
canvas.drawRect(toOriginRect(), _paint);
|
||||
canvas.drawRect(size.toRect(), _paint);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,12 +3,13 @@ import 'package:flame/components/position_component.dart';
|
||||
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
|
||||
class Square extends PositionComponent {
|
||||
final Paint _paint;
|
||||
|
||||
Square(this._paint, double x, double y, {double angle = 0.0}) {
|
||||
width = 100;
|
||||
height = 100;
|
||||
size = Vector2(width, height);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.angle = angle;
|
||||
@ -18,6 +19,6 @@ class Square extends PositionComponent {
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
super.render(canvas);
|
||||
canvas.drawRect(toOriginRect(), _paint);
|
||||
canvas.drawRect(size.toRect(), _paint);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,12 +3,13 @@ import 'package:flame/components/position_component.dart';
|
||||
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
|
||||
class Square extends PositionComponent {
|
||||
final Paint _paint;
|
||||
|
||||
Square(this._paint, double x, double y, {double angle = 0.0}) {
|
||||
width = 100;
|
||||
height = 100;
|
||||
size = Vector2(width, height);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.angle = angle;
|
||||
@ -18,6 +19,6 @@ class Square extends PositionComponent {
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
super.render(canvas);
|
||||
canvas.drawRect(toOriginRect(), _paint);
|
||||
canvas.drawRect(size.toRect(), _paint);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,18 +3,19 @@ import 'package:flame/components/position_component.dart';
|
||||
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
|
||||
class Square extends PositionComponent {
|
||||
static final _paint = Paint()..color = const Color(0xFFFFFFFF);
|
||||
|
||||
Square() {
|
||||
width = 100;
|
||||
height = 100;
|
||||
size = Vector2.all(100);
|
||||
anchor = Anchor.center;
|
||||
}
|
||||
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
super.render(canvas);
|
||||
canvas.drawRect(toOriginRect(), _paint);
|
||||
canvas.drawRect(size.toRect(), _paint);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/components/position_component.dart';
|
||||
@ -22,7 +23,7 @@ class TapableSquare extends PositionComponent with Tapable {
|
||||
bool _beenPressed = false;
|
||||
|
||||
TapableSquare({double y = 100, double x = 100}) {
|
||||
width = height = 100;
|
||||
size = Vector2.all(100);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
@ -30,7 +31,7 @@ class TapableSquare extends PositionComponent with Tapable {
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
super.render(canvas);
|
||||
canvas.drawRect(toOriginRect(), _beenPressed ? _grey : _white);
|
||||
canvas.drawRect(size.toRect(), _beenPressed ? _grey : _white);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -16,13 +16,12 @@ class MyGame extends BaseGame {
|
||||
final animation = SpriteAnimation.sequenced(
|
||||
'chopper.png',
|
||||
4,
|
||||
textureWidth: 48,
|
||||
textureHeight: 48,
|
||||
textureSize: Vector2.all(48),
|
||||
stepTime: 0.15,
|
||||
);
|
||||
|
||||
SpriteAnimationComponent buildAnimation() {
|
||||
final ac = SpriteAnimationComponent(100, 100, animation);
|
||||
final ac = SpriteAnimationComponent(Vector2.all(100), animation);
|
||||
ac.x = size.x / 2 - ac.width / 2;
|
||||
return ac;
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ class Ball extends PositionComponent {
|
||||
@override
|
||||
void render(Canvas c) {
|
||||
super.render(c);
|
||||
c.drawOval(toOriginRect(), paint);
|
||||
c.drawOval(size.toRect(), paint);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -53,8 +53,7 @@ class MyGame extends BaseGame {
|
||||
add(
|
||||
Ball(size)
|
||||
..y = (size.y / 2) - 50
|
||||
..width = 100
|
||||
..height = 100,
|
||||
..size = Vector2(100, 100)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flame/components/sprite_animation_component.dart';
|
||||
import 'package:flame/components/sprite_component.dart';
|
||||
@ -55,12 +56,13 @@ class MyGame extends BaseGame {
|
||||
final vampireAnimation =
|
||||
spriteSheet.createAnimation(0, stepTime: 0.1, to: 7);
|
||||
final ghostAnimation = spriteSheet.createAnimation(1, stepTime: 0.1, to: 7);
|
||||
final spriteSize = Vector2(80, 90);
|
||||
|
||||
final vampireComponent = SpriteAnimationComponent(80, 90, vampireAnimation)
|
||||
final vampireComponent = SpriteAnimationComponent(spriteSize, vampireAnimation)
|
||||
..x = 150
|
||||
..y = 100;
|
||||
|
||||
final ghostComponent = SpriteAnimationComponent(80, 90, ghostAnimation)
|
||||
final ghostComponent = SpriteAnimationComponent(spriteSize, ghostAnimation)
|
||||
..x = 150
|
||||
..y = 220;
|
||||
|
||||
@ -69,12 +71,12 @@ class MyGame extends BaseGame {
|
||||
|
||||
// Some plain sprites
|
||||
final vampireSpriteComponent =
|
||||
SpriteComponent.fromSprite(80, 90, spriteSheet.getSprite(0, 0))
|
||||
SpriteComponent.fromSprite(spriteSize, spriteSheet.getSprite(0, 0))
|
||||
..x = 50
|
||||
..y = 100;
|
||||
|
||||
final ghostSpriteComponent =
|
||||
SpriteComponent.fromSprite(80, 90, spriteSheet.getSprite(1, 0))
|
||||
SpriteComponent.fromSprite(spriteSize, spriteSheet.getSprite(1, 0))
|
||||
..x = 50
|
||||
..y = 220;
|
||||
|
||||
|
||||
@ -44,11 +44,11 @@ class MyGame extends BaseGame {
|
||||
|
||||
add(TextComponent('center', config: tiny)
|
||||
..anchor = Anchor.center
|
||||
..setPosition(size / 2));
|
||||
..position = size / 2);
|
||||
|
||||
add(TextComponent('bottomRight', config: tiny)
|
||||
..anchor = Anchor.bottomRight
|
||||
..setPosition(size));
|
||||
..position = size);
|
||||
|
||||
add(MyTextBox(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eget ligula eu lectus lobortis condimentum.',
|
||||
|
||||
@ -2,6 +2,7 @@ import 'dart:math' as math;
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/anchor.dart';
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
import 'package:flame/gestures.dart';
|
||||
import 'package:flame/components/position_component.dart';
|
||||
import 'package:flame/components/mixins/has_game_ref.dart';
|
||||
@ -31,7 +32,7 @@ class Square extends PositionComponent with HasGameRef<MyGame> {
|
||||
void render(Canvas c) {
|
||||
super.render(c);
|
||||
|
||||
c.drawRect(toOriginRect(), white);
|
||||
c.drawRect(size.toRect(), white);
|
||||
c.drawRect(const Rect.fromLTWH(0, 0, 3, 3), red);
|
||||
c.drawRect(Rect.fromLTWH(width / 2, height / 2, 3, 3), blue);
|
||||
}
|
||||
@ -45,7 +46,7 @@ class Square extends PositionComponent with HasGameRef<MyGame> {
|
||||
|
||||
@override
|
||||
void onMount() {
|
||||
width = height = gameRef.squareSize;
|
||||
size = Vector2.all(gameRef.squareSize);
|
||||
anchor = Anchor.center;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../flare_animation.dart';
|
||||
@ -12,18 +13,14 @@ class FlareComponent extends PositionComponent {
|
||||
FlareComponent(
|
||||
String fileName,
|
||||
String animation,
|
||||
double width,
|
||||
double height,
|
||||
Vector2 size,
|
||||
) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
super.size = size;
|
||||
|
||||
FlareAnimation.load(fileName).then((loadedFlareAnimation) {
|
||||
_flareAnimation = loadedFlareAnimation;
|
||||
|
||||
_flareAnimation.updateAnimation(animation);
|
||||
_flareAnimation.width = width;
|
||||
_flareAnimation.height = height;
|
||||
_flareAnimation.size = size;
|
||||
});
|
||||
}
|
||||
|
||||
@ -33,6 +30,13 @@ class FlareComponent extends PositionComponent {
|
||||
}
|
||||
}
|
||||
|
||||
void updateSize(Vector2 newSize) {
|
||||
super.size = newSize;
|
||||
if (loaded()) {
|
||||
_flareAnimation.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool loaded() => _flareAnimation != null;
|
||||
|
||||
@ -50,20 +54,4 @@ class FlareComponent extends PositionComponent {
|
||||
_flareAnimation.update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
set width(_width) {
|
||||
super.width = _width;
|
||||
if (loaded()) {
|
||||
_flareAnimation.width = width;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
set height(_height) {
|
||||
super.height = _height;
|
||||
if (loaded()) {
|
||||
_flareAnimation.height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../extensions/vector2.dart';
|
||||
import '../nine_tile_box.dart';
|
||||
import 'position_component.dart';
|
||||
|
||||
@ -18,6 +19,6 @@ class NineTileBoxComponent extends PositionComponent {
|
||||
@override
|
||||
void render(Canvas c) {
|
||||
super.render(c);
|
||||
nineTileBox.drawRect(c, toOriginRect());
|
||||
nineTileBox.drawRect(c, size.toRect());
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ class ParallaxLayer {
|
||||
|
||||
// Size of the area to paint the images on
|
||||
final paintSize = count..multiply(_imageSize);
|
||||
_paintArea = paintSize.toOriginRect();
|
||||
_paintArea = paintSize.toRect();
|
||||
}
|
||||
|
||||
void update(Vector2 delta) {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import 'dart:ui';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:ordered_set/comparing.dart';
|
||||
@ -15,8 +14,8 @@ import 'component.dart';
|
||||
/// A [Component] implementation that represents a component that has a
|
||||
/// specific, possibly dynamic position on the screen.
|
||||
///
|
||||
/// It represents a rectangle of dimension ([width], [height]), on the position
|
||||
/// ([x], [y]), rotate around its center with angle [angle].
|
||||
/// It represents a rectangle of dimension [size], on the [position],
|
||||
/// rotated around its [anchor] with angle [angle].
|
||||
///
|
||||
/// It also uses the [anchor] property to properly position itself.
|
||||
///
|
||||
@ -25,24 +24,31 @@ import 'component.dart';
|
||||
/// They are translated by this component's (x,y). They do not need to fit
|
||||
/// within this component's (width, height).
|
||||
abstract class PositionComponent extends Component {
|
||||
/// The position of this component on the screen (measured from the top left corner).
|
||||
Vector2 position = Vector2.zero();
|
||||
|
||||
/// X position of this component on the screen (measured from the top left corner).
|
||||
double x = 0.0;
|
||||
double get x => position.x;
|
||||
set x(double x) => position.x = x;
|
||||
|
||||
/// Y position of this component on the screen (measured from the top left corner).
|
||||
double y = 0.0;
|
||||
double get y => position.y;
|
||||
set y(double y) => position.y = y;
|
||||
|
||||
/// The size that this component is rendered with.
|
||||
/// This is not necessarily the source size of the asset.
|
||||
Vector2 size = Vector2.zero();
|
||||
|
||||
/// Width (size) that this component is rendered with.
|
||||
double get width => size.x;
|
||||
|
||||
/// Height (size) that this component is rendered with.
|
||||
double get height => size.y;
|
||||
|
||||
/// Angle (with respect to the x-axis) this component should be rendered with.
|
||||
/// It is rotated around its anchor.
|
||||
double angle = 0.0;
|
||||
|
||||
/// Width (size) that this component is rendered with.
|
||||
/// This is not necessarily the source width of the asset.
|
||||
double width = 0.0;
|
||||
|
||||
/// Height (size) that this component is rendered with.
|
||||
/// This is not necessarily the source height of the asset.
|
||||
double height = 0.0;
|
||||
|
||||
/// Anchor point for this component. This is where flame "grabs it".
|
||||
/// The [x], [y] coordinates are relative to this point inside the component.
|
||||
/// The [angle] is rotated around this point.
|
||||
@ -72,51 +78,33 @@ abstract class PositionComponent extends Component {
|
||||
|
||||
TextConfig get debugTextConfig => TextConfig(color: debugColor, fontSize: 12);
|
||||
|
||||
Vector2 get position => Vector2(x, y);
|
||||
void setPosition(Vector2 position) {
|
||||
x = position.x;
|
||||
y = position.y;
|
||||
}
|
||||
|
||||
Vector2 get size => Vector2(width, height);
|
||||
void setBySize(Vector2 size) {
|
||||
width = size.x;
|
||||
height = size.y;
|
||||
}
|
||||
|
||||
/// Returns the size of this component starting at (0, 0).
|
||||
/// Effectively this is it's position with respect to itself.
|
||||
/// Use this if the canvas is already translated by (x, y).
|
||||
Rect toOriginRect() => Rect.fromLTWH(0, 0, width, height);
|
||||
|
||||
/// Returns the relative position/size of this component.
|
||||
/// Relative because it might be translated by their parents (which is not considered here).
|
||||
Rect toRect() => Rect.fromLTWH(
|
||||
Rect toRect() {
|
||||
return Rect.fromLTWH(
|
||||
x - anchor.relativePosition.x * width,
|
||||
y - anchor.relativePosition.y * height,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
}
|
||||
|
||||
/// Mutates x, y, width and height using the provided [rect] as basis.
|
||||
/// This is a relative rect, same definition that [toRect] use (therefore both methods are compatible, i.e. setByRect ∘ toRect = identity).
|
||||
void setByRect(Rect rect) {
|
||||
x = rect.left + anchor.relativePosition.x * rect.width;
|
||||
y = rect.top + anchor.relativePosition.y * rect.height;
|
||||
width = rect.width;
|
||||
height = rect.height;
|
||||
position.setValues(
|
||||
rect.left + anchor.relativePosition.x * rect.width,
|
||||
rect.top + anchor.relativePosition.y * rect.height,
|
||||
);
|
||||
size.setValues(rect.width, rect.height);
|
||||
}
|
||||
|
||||
double angleBetween(PositionComponent c) {
|
||||
return (atan2(c.x - x, y - c.y) - pi / 2) % (2 * pi);
|
||||
}
|
||||
double angleTo(PositionComponent c) => position.angleTo(c.position);
|
||||
|
||||
double distance(PositionComponent c) {
|
||||
return c.position.distanceTo(position);
|
||||
}
|
||||
double distance(PositionComponent c) => position.distanceTo(c.position);
|
||||
|
||||
void renderDebugMode(Canvas canvas) {
|
||||
canvas.drawRect(toOriginRect(), _debugPaint);
|
||||
canvas.drawRect(size.toRect(), _debugPaint);
|
||||
debugTextConfig.render(
|
||||
canvas,
|
||||
'x: ${x.toStringAsFixed(2)} y:${y.toStringAsFixed(2)}',
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../sprite_animation.dart';
|
||||
@ -11,41 +12,34 @@ class SpriteAnimationComponent extends PositionComponent {
|
||||
bool destroyOnFinish = false;
|
||||
|
||||
SpriteAnimationComponent(
|
||||
double width,
|
||||
double height,
|
||||
Vector2 size,
|
||||
this.animation, {
|
||||
this.destroyOnFinish = false,
|
||||
}) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
super.size.setFrom(size);
|
||||
}
|
||||
|
||||
SpriteAnimationComponent.empty();
|
||||
|
||||
SpriteAnimationComponent.sequenced(
|
||||
double width,
|
||||
double height,
|
||||
Vector2 size,
|
||||
String imagePath,
|
||||
int amount, {
|
||||
int amountPerRow,
|
||||
double textureX = 0.0,
|
||||
double textureY = 0.0,
|
||||
double textureWidth,
|
||||
double textureHeight,
|
||||
Vector2 texturePosition,
|
||||
Vector2 textureSize,
|
||||
double stepTime,
|
||||
bool loop = true,
|
||||
this.destroyOnFinish = false,
|
||||
}) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
super.size.setFrom(size);
|
||||
texturePosition ??= Vector2.zero();
|
||||
animation = SpriteAnimation.sequenced(
|
||||
imagePath,
|
||||
amount,
|
||||
amountPerRow: amountPerRow,
|
||||
textureX: textureX,
|
||||
textureY: textureY,
|
||||
textureWidth: textureWidth,
|
||||
textureHeight: textureHeight,
|
||||
texturePosition: texturePosition,
|
||||
textureSize: textureSize,
|
||||
stepTime: stepTime ?? 0.1,
|
||||
loop: loop,
|
||||
);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../sprite.dart';
|
||||
@ -23,14 +24,13 @@ class SpriteComponent extends PositionComponent {
|
||||
SpriteComponent();
|
||||
|
||||
SpriteComponent.square(double size, String imagePath)
|
||||
: this.rectangle(size, size, imagePath);
|
||||
: this.rectangle(Vector2(size, size), imagePath);
|
||||
|
||||
SpriteComponent.rectangle(double width, double height, String imagePath)
|
||||
: this.fromSprite(width, height, Sprite(imagePath));
|
||||
SpriteComponent.rectangle(Vector2 size, String imagePath)
|
||||
: this.fromSprite(size, Sprite(imagePath));
|
||||
|
||||
SpriteComponent.fromSprite(double width, double height, this.sprite) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
SpriteComponent.fromSprite(Vector2 size, this.sprite) {
|
||||
super.size.setFrom(size);
|
||||
}
|
||||
|
||||
@mustCallSuper
|
||||
|
||||
@ -148,7 +148,7 @@ class TextBoxComponent extends PositionComponent with Resizable {
|
||||
|
||||
Future<Image> _redrawCache() {
|
||||
final PictureRecorder recorder = PictureRecorder();
|
||||
final Canvas c = Canvas(recorder, toOriginRect());
|
||||
final Canvas c = Canvas(recorder, size.toRect());
|
||||
_fullRender(c);
|
||||
return recorder.endRecording().toImage(width.toInt(), height.toInt());
|
||||
}
|
||||
|
||||
@ -35,8 +35,7 @@ class TextComponent extends PositionComponent {
|
||||
|
||||
void _updateBox() {
|
||||
_tp = config.toTextPainter(_text);
|
||||
width = _tp.width;
|
||||
height = _tp.height;
|
||||
size.setValues(_tp.width, _tp.height);
|
||||
}
|
||||
|
||||
@mustCallSuper
|
||||
|
||||
@ -43,6 +43,6 @@ class MoveEffect extends PositionComponentEffect {
|
||||
void update(double dt) {
|
||||
super.update(dt);
|
||||
final double progress = curve?.transform(percentage) ?? 1.0;
|
||||
component.setPosition(_startPosition + _delta * progress);
|
||||
component.position = _startPosition + _delta * progress;
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +41,6 @@ class ScaleEffect extends PositionComponentEffect {
|
||||
void update(double dt) {
|
||||
super.update(dt);
|
||||
final double progress = curve?.transform(percentage) ?? 1.0;
|
||||
component.setBySize(_startSize + _delta * progress);
|
||||
component.size = _startSize + _delta * progress;
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,8 +31,8 @@ class SequenceEffect extends PositionComponentEffect {
|
||||
final originalAngle = _comp.angle;
|
||||
effects.forEach((effect) {
|
||||
effect.reset();
|
||||
_comp.setBySize(endSize);
|
||||
_comp.setPosition(endPosition);
|
||||
_comp.size = endSize;
|
||||
_comp.position = endPosition;
|
||||
_comp.angle = endAngle;
|
||||
effect.initialize(_comp);
|
||||
endSize = effect.endSize;
|
||||
@ -43,8 +43,8 @@ class SequenceEffect extends PositionComponentEffect {
|
||||
0,
|
||||
(time, effect) => time + effect.totalTravelTime,
|
||||
);
|
||||
component.setBySize(originalSize);
|
||||
component.setPosition(originalPosition);
|
||||
component.size = originalSize;
|
||||
component.position = originalPosition;
|
||||
component.angle = originalAngle;
|
||||
currentEffect = effects.first;
|
||||
_currentWasAlternating = currentEffect.isAlternating;
|
||||
|
||||
@ -21,6 +21,12 @@ class RectFactory {
|
||||
return Rect.fromLTWH(0, 0, size.width, size.height);
|
||||
}
|
||||
|
||||
/// Creates a [Rect] having its left upper corner in start and its right
|
||||
/// bottom corner in end
|
||||
static Rect fromVectors(Vector2 start, Vector2 end) {
|
||||
return Rect.fromLTWH(start.x, start.y, end.x, end.y);
|
||||
}
|
||||
|
||||
/// Creates bounds in from of a [Rect] from a list of [Vector2]
|
||||
static Rect fromBounds(List<Vector2> pts) {
|
||||
final double minx = pts.map((e) => e.x).reduce(min);
|
||||
|
||||
@ -15,11 +15,12 @@ extension Vector2Extension on Vector2 {
|
||||
/// Creates a [Point] from the [Vector2]
|
||||
Point toPoint() => Point(x, y);
|
||||
|
||||
/// Creates a [Rect] starting from [x, y] and having size [to].
|
||||
Rect toRect(Vector2 to) => Rect.fromLTWH(x, y, to.x, to.y);
|
||||
/// Creates a [Rect] starting from [x, y] and having the size of the
|
||||
/// argument [Vector2]
|
||||
Rect toPositionedRect(Vector2 size) => Rect.fromLTWH(x, y, size.x, size.y);
|
||||
|
||||
/// Creates a [Rect] starting in origin and having size [to].
|
||||
Rect toOriginRect() => Rect.fromLTWH(0, 0, x, y);
|
||||
/// Creates a [Rect] starting in origo and going the [Vector2]
|
||||
Rect toRect() => Rect.fromLTWH(0, 0, x, y);
|
||||
|
||||
/// Linearly interpolate towards another Vector2
|
||||
void lerp(Vector2 to, double t) {
|
||||
|
||||
@ -5,6 +5,7 @@ import "package:flare_flutter/flare.dart";
|
||||
import "package:flare_flutter/flare_actor.dart";
|
||||
|
||||
import "flame.dart";
|
||||
import "extensions/vector2.dart";
|
||||
|
||||
@Deprecated("Use flame_flare package instead")
|
||||
class FlareAnimation {
|
||||
@ -13,7 +14,8 @@ class FlareAnimation {
|
||||
String _animationName;
|
||||
final List<FlareAnimationLayer> _animationLayers = [];
|
||||
|
||||
double _width = 0.0, _height = 0.0, _xScale = 0.0, _yScale = 0.0;
|
||||
final Vector2 _size = Vector2.zero();
|
||||
final Vector2 _scale = Vector2.zero();
|
||||
|
||||
Picture _picture;
|
||||
|
||||
@ -32,23 +34,15 @@ class FlareAnimation {
|
||||
return FlareAnimation(artboard);
|
||||
}
|
||||
|
||||
double get width {
|
||||
return _width;
|
||||
double get width => size.x;
|
||||
double get height => size.y;
|
||||
|
||||
set size(Vector2 newSize) {
|
||||
_size.setFrom(newSize);
|
||||
_scale.setValues(_size.x / _artboard.width, _size.y / _artboard.height);
|
||||
}
|
||||
|
||||
double get height {
|
||||
return _height;
|
||||
}
|
||||
|
||||
set width(double newWidth) {
|
||||
_width = newWidth;
|
||||
_xScale = _width / _artboard.width;
|
||||
}
|
||||
|
||||
set height(double newHeight) {
|
||||
_height = newHeight;
|
||||
_yScale = _height / _artboard.height;
|
||||
}
|
||||
Vector2 get size => _size;
|
||||
|
||||
void updateAnimation(String animation) {
|
||||
_animationName = animation;
|
||||
@ -73,10 +67,8 @@ class FlareAnimation {
|
||||
if (_picture == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(x, y);
|
||||
|
||||
canvas.drawPicture(_picture);
|
||||
canvas.restore();
|
||||
}
|
||||
@ -125,7 +117,7 @@ class FlareAnimation {
|
||||
final r = PictureRecorder();
|
||||
final c = Canvas(r);
|
||||
|
||||
c.scale(_xScale, _yScale);
|
||||
c.scale(_scale.x, _scale.y);
|
||||
_artboard.draw(c);
|
||||
|
||||
_picture = r.endRecording();
|
||||
|
||||
@ -12,16 +12,14 @@ class Sprite {
|
||||
|
||||
Sprite(
|
||||
String fileName, {
|
||||
double x = 0.0,
|
||||
double y = 0.0,
|
||||
double width,
|
||||
double height,
|
||||
Vector2 position,
|
||||
Vector2 size,
|
||||
}) {
|
||||
position ??= Vector2.zero();
|
||||
Flame.images.load(fileName).then((img) {
|
||||
width ??= img.width.toDouble();
|
||||
height ??= img.height.toDouble();
|
||||
size ??= Vector2(img.width.toDouble(), img.height.toDouble());
|
||||
image = img;
|
||||
src = Rect.fromLTWH(x, y, width, height);
|
||||
src = position.toPositionedRect(size);
|
||||
});
|
||||
}
|
||||
|
||||
@ -100,7 +98,7 @@ class Sprite {
|
||||
return;
|
||||
}
|
||||
size ??= this.size;
|
||||
renderRect(canvas, p.toRect(size), overridePaint: overridePaint);
|
||||
renderRect(canvas, p.toPositionedRect(size), overridePaint: overridePaint);
|
||||
}
|
||||
|
||||
void render(
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
|
||||
import 'flame.dart';
|
||||
import 'sprite.dart';
|
||||
|
||||
@ -75,22 +77,23 @@ class SpriteAnimation {
|
||||
String imagePath,
|
||||
int amount, {
|
||||
int amountPerRow,
|
||||
double textureX = 0.0,
|
||||
double textureY = 0.0,
|
||||
double textureWidth,
|
||||
double textureHeight,
|
||||
Vector2 texturePosition,
|
||||
Vector2 textureSize,
|
||||
double stepTime = 0.1,
|
||||
this.loop = true,
|
||||
}) : assert(amountPerRow == null || amount >= amountPerRow) {
|
||||
amountPerRow ??= amount;
|
||||
texturePosition ??= Vector2.zero();
|
||||
frames = List<SpriteAnimationFrame>(amount);
|
||||
for (var i = 0; i < amount; i++) {
|
||||
final position = Vector2(
|
||||
texturePosition.x + (i % amountPerRow) * textureSize.x,
|
||||
texturePosition.y + (i ~/ amountPerRow) * textureSize.y,
|
||||
);
|
||||
final Sprite sprite = Sprite(
|
||||
imagePath,
|
||||
x: textureX + (i % amountPerRow) * textureWidth,
|
||||
y: textureY + (i ~/ amountPerRow) * textureHeight,
|
||||
width: textureWidth,
|
||||
height: textureHeight,
|
||||
position: position,
|
||||
size: textureSize,
|
||||
);
|
||||
frames[i] = SpriteAnimationFrame(sprite, stepTime);
|
||||
}
|
||||
@ -102,21 +105,21 @@ class SpriteAnimation {
|
||||
int amount,
|
||||
List<double> stepTimes, {
|
||||
int amountPerRow,
|
||||
double textureX = 0.0,
|
||||
double textureY = 0.0,
|
||||
double textureWidth,
|
||||
double textureHeight,
|
||||
Vector2 texturePosition,
|
||||
Vector2 textureSize,
|
||||
this.loop = true,
|
||||
}) : assert(amountPerRow == null || amount >= amountPerRow) {
|
||||
amountPerRow ??= amount;
|
||||
frames = List<SpriteAnimationFrame>(amount);
|
||||
for (var i = 0; i < amount; i++) {
|
||||
final position = Vector2(
|
||||
texturePosition.x + (i % amountPerRow) * textureSize.x,
|
||||
texturePosition.y + (i ~/ amountPerRow) * textureSize.y,
|
||||
);
|
||||
final Sprite sprite = Sprite(
|
||||
imagePath,
|
||||
x: textureX + (i % amountPerRow) * textureWidth,
|
||||
y: textureY + (i ~/ amountPerRow) * textureHeight,
|
||||
width: textureWidth,
|
||||
height: textureHeight,
|
||||
position: position,
|
||||
size: textureSize,
|
||||
);
|
||||
frames[i] = SpriteAnimationFrame(sprite, stepTimes[i]);
|
||||
}
|
||||
@ -136,19 +139,17 @@ class SpriteAnimation {
|
||||
|
||||
final frames = jsonFrames.values.map((value) {
|
||||
final frameData = value['frame'];
|
||||
final int x = frameData['x'];
|
||||
final int y = frameData['y'];
|
||||
final int width = frameData['w'];
|
||||
final int height = frameData['h'];
|
||||
final double x = frameData['x'];
|
||||
final double y = frameData['y'];
|
||||
final double width = frameData['w'];
|
||||
final double height = frameData['h'];
|
||||
|
||||
final stepTime = value['duration'] / 1000;
|
||||
|
||||
final Sprite sprite = Sprite(
|
||||
imagePath,
|
||||
x: x.toDouble(),
|
||||
y: y.toDouble(),
|
||||
width: width.toDouble(),
|
||||
height: height.toDouble(),
|
||||
position: Vector2(x, y),
|
||||
size: Vector2(width, height),
|
||||
);
|
||||
|
||||
return SpriteAnimationFrame(sprite, stepTime);
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'sprite.dart';
|
||||
import 'sprite_animation.dart';
|
||||
import 'extensions/vector2.dart';
|
||||
|
||||
/// Utility class to help extract animations and sprites from a spritesheet image
|
||||
class SpriteSheet {
|
||||
@ -36,12 +38,11 @@ class SpriteSheet {
|
||||
int x,
|
||||
int y,
|
||||
) {
|
||||
Vector2 size = Vector2(textureWidth.toDouble(), textureHeight.toDouble());
|
||||
return Sprite(
|
||||
imageName,
|
||||
x: (x * textureWidth).toDouble(),
|
||||
y: (y * textureHeight).toDouble(),
|
||||
width: textureWidth.toDouble(),
|
||||
height: textureHeight.toDouble(),
|
||||
position: Vector2(x.toDouble(), y.toDouble())..multiply(size),
|
||||
size: size,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -9,34 +9,30 @@ void main() {
|
||||
group('component test', () {
|
||||
test('test get/set x/y or position', () {
|
||||
final PositionComponent c = SpriteComponent();
|
||||
c.x = 2.2;
|
||||
c.y = 3.4;
|
||||
expect(c.position.x, 2.2);
|
||||
expect(c.position.y, 3.4);
|
||||
c.position = Vector2(2.2, 3.4);
|
||||
expect(c.x, 2.2);
|
||||
expect(c.y, 3.4);
|
||||
|
||||
c.setPosition(Vector2(1.0, 0.0));
|
||||
c.position = Vector2(1.0, 0.0);
|
||||
expect(c.x, 1.0);
|
||||
expect(c.y, 0.0);
|
||||
});
|
||||
|
||||
test('test get/set width/height or size', () {
|
||||
final PositionComponent c = SpriteComponent();
|
||||
c.width = 2.2;
|
||||
c.height = 3.4;
|
||||
c.size = Vector2(2.2, 3.4);
|
||||
expect(c.size.x, 2.2);
|
||||
expect(c.size.y, 3.4);
|
||||
|
||||
c.setBySize(Vector2(1.0, 0.0));
|
||||
c.size = Vector2(1.0, 0.0);
|
||||
expect(c.width, 1.0);
|
||||
expect(c.height, 0.0);
|
||||
});
|
||||
|
||||
test('test get/set rect', () {
|
||||
final PositionComponent c = SpriteComponent();
|
||||
c.x = 0.0;
|
||||
c.y = 1.0;
|
||||
c.width = 2.0;
|
||||
c.height = 2.0;
|
||||
c.position = Vector2(0.0, 1.0);
|
||||
c.size = Vector2(2.0, 2.0);
|
||||
expect(c.toRect().left, 0.0);
|
||||
expect(c.toRect().top, 1.0);
|
||||
expect(c.toRect().width, 2.0);
|
||||
|
||||
Reference in New Issue
Block a user