mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-02 20:13:50 +08:00
Merge pull request #473 from flame-engine/spydon.vector-for-position-component
Use 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,15 +13,14 @@ 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);
|
||||
|
||||
// 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
|
||||
player.render(canvas); // it will render only if the image is loaded and the position and size parameters are not null
|
||||
```
|
||||
|
||||
In the event that you want to easily change the direction of your components rendering, you can also use
|
||||
@ -55,14 +54,16 @@ This component uses an instance of the [Animation](/doc/images.md#Animation) cla
|
||||
This will create a simple three frame animation
|
||||
|
||||
```dart
|
||||
List<Sprite> sprites = [0, 1, 2].map((i) => new Sprite('player_${i}.png')).toList();
|
||||
this.player = AnimationComponent(64.0, 64.0, new Animation.spriteList(sprites, stepTime: 0.01));
|
||||
List<Sprite> sprites = [0, 1, 2].map((i) => Sprite('player_${i}.png')).toList();
|
||||
final size = Vector2.all(64.0);
|
||||
this.player = AnimationComponent(size, new Animation.spriteList(sprites, stepTime: 0.01));
|
||||
```
|
||||
|
||||
If you have a sprite sheet, you can use the `sequenced` constructor, identical to the one provided by the `Animation` class (check more details in [the appropriate section](/doc/images.md#Animation)):
|
||||
|
||||
```dart
|
||||
this.player = AnimationComponent.sequenced(64.0, 64.0, 'player.png', 2);
|
||||
final size = Vector2.all(64.0);
|
||||
this.player = AnimationComponent.sequenced(size, 'player.png', 2);
|
||||
```
|
||||
|
||||
If you are not using `BaseGame`, don't forget this component needs to be update'd even if static, because the animation object needs to be ticked to move the frames.
|
||||
@ -105,8 +106,7 @@ it also can receive a FlareController that can play multiple animations and cont
|
||||
}
|
||||
|
||||
final fileName = 'assets/george_washington.flr';
|
||||
final width = 1776;
|
||||
final height = 1804;
|
||||
final size = Vector2(1776, 1804);
|
||||
final controller = WashingtonController(); //instantiate controller
|
||||
|
||||
FlareActorComponent flareAnimation = FlareActorComponent(
|
||||
@ -190,8 +190,8 @@ This creates a static background, if you want it to move you have to set the nam
|
||||
You can set the baseSpeed and layerDelta at any time, for example if your character jumps or your game speeds up.
|
||||
|
||||
```dart
|
||||
this.bg.baseSpeed = Offset(100, 0);
|
||||
this.bg.layerDelta = Offset(40, 0);
|
||||
this.bg.baseSpeed = Vector2(100, 0);
|
||||
this.bg.layerDelta = Vector2(40, 0);
|
||||
```
|
||||
|
||||
By default the images are aligned to the bottom left, repeated along the X-axis and scaled proportionally so that the image covers the height of the screen. If you want to change this behaviour, for example if you are not making a side scrolling game, you can set the `repeat`, `alignment` and `fill` parameters for each ParallaxImage.
|
||||
@ -203,7 +203,7 @@ Advanced example:
|
||||
ParallaxImage('planets.jpg', repeat: ImageRepeat.repeatY, alignment: Alignment.bottomLeft, fill: LayerFill.none),
|
||||
ParallaxImage('dust.jpg', repeat: ImageRepeat.repeatX, alignment: Alignment.topRight, fill: LayerFill.height),
|
||||
];
|
||||
this.bg = ParallaxComponent(images, baseSpeed: Offset(50, 0), layerDelta: Offset(20, 0));
|
||||
this.bg = ParallaxComponent(images, baseSpeed: Vector2(50, 0), layerDelta: Vector2(20, 0));
|
||||
```
|
||||
|
||||
* The stars image in this example will be repeatedly drawn in both axis, align in the center and be scaled to fill the screen width.
|
||||
|
||||
@ -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.all(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);
|
||||
|
||||
@ -20,7 +20,7 @@ class AndroidComponent extends SpriteComponent with Resizable {
|
||||
int xDirection = 1;
|
||||
int yDirection = 1;
|
||||
|
||||
AndroidComponent() : super.square(100, 'android.png');
|
||||
AndroidComponent() : super.fromImagePath(Vector2.all(100), 'android.png');
|
||||
|
||||
@override
|
||||
void update(double dt) {
|
||||
|
||||
@ -24,8 +24,8 @@ class MyGame extends BaseGame with TapDetector {
|
||||
MyGame() {
|
||||
final green = Paint()..color = const Color(0xAA338833);
|
||||
final red = Paint()..color = const Color(0xAA883333);
|
||||
greenSquare = Square(green, 100, 100);
|
||||
final redSquare = Square(red, 100, 100);
|
||||
greenSquare = Square(green, Vector2.all(100));
|
||||
final redSquare = Square(red, Vector2.all(100));
|
||||
add(greenSquare);
|
||||
add(redSquare);
|
||||
}
|
||||
|
||||
@ -3,14 +3,14 @@ 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;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
Square(this._paint, Vector2 position, {double angle = 0.0}) {
|
||||
size = Vector2.all(100.0);
|
||||
this.position = position;
|
||||
this.angle = angle;
|
||||
anchor = Anchor.center;
|
||||
}
|
||||
@ -18,6 +18,6 @@ class Square extends PositionComponent {
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
super.render(canvas);
|
||||
canvas.drawRect(toOriginRect(), _paint);
|
||||
canvas.drawRect(size.toRect(), _paint);
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,9 +26,9 @@ class MyGame extends BaseGame with TapDetector {
|
||||
final green = Paint()..color = const Color(0xAA338833);
|
||||
final red = Paint()..color = const Color(0xAA883333);
|
||||
final orange = Paint()..color = const Color(0xAABB6633);
|
||||
greenSquare = Square(green, 100, 100);
|
||||
redSquare = Square(red, 200, 200);
|
||||
orangeSquare = Square(orange, 200, 400);
|
||||
greenSquare = Square(green, Vector2.all(100));
|
||||
redSquare = Square(red, Vector2.all(200));
|
||||
orangeSquare = Square(orange, Vector2(200, 400));
|
||||
add(greenSquare);
|
||||
add(redSquare);
|
||||
add(orangeSquare);
|
||||
|
||||
@ -3,14 +3,14 @@ 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;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
Square(this._paint, Vector2 position, {double angle = 0.0}) {
|
||||
size = Vector2.all(100.0);
|
||||
this.position = position;
|
||||
this.angle = angle;
|
||||
anchor = Anchor.center;
|
||||
}
|
||||
@ -18,6 +18,6 @@ class Square extends PositionComponent {
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
super.render(canvas);
|
||||
canvas.drawRect(toOriginRect(), _paint);
|
||||
canvas.drawRect(size.toRect(), _paint);
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
|
||||
MyGame() {
|
||||
final green = Paint()..color = const Color(0xAA338833);
|
||||
greenSquare = Square(green, 100, 100);
|
||||
greenSquare = Square(green, Vector2.all(100));
|
||||
add(greenSquare);
|
||||
}
|
||||
|
||||
|
||||
@ -3,14 +3,14 @@ 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;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
Square(this._paint, Vector2 position, {double angle = 0.0}) {
|
||||
size = Vector2.all(100.0);
|
||||
this.position = position;
|
||||
this.angle = angle;
|
||||
anchor = Anchor.center;
|
||||
}
|
||||
@ -18,6 +18,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';
|
||||
@ -21,16 +22,15 @@ class TapableSquare extends PositionComponent with Tapable {
|
||||
|
||||
bool _beenPressed = false;
|
||||
|
||||
TapableSquare({double y = 100, double x = 100}) {
|
||||
width = height = 100;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
TapableSquare({Vector2 position}) {
|
||||
size = Vector2.all(100);
|
||||
this.position = position ?? Vector2.all(100);
|
||||
}
|
||||
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
super.render(canvas);
|
||||
canvas.drawRect(toOriginRect(), _beenPressed ? _grey : _white);
|
||||
canvas.drawRect(size.toRect(), _beenPressed ? _grey : _white);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -51,7 +51,7 @@ class TapableSquare extends PositionComponent with Tapable {
|
||||
|
||||
class MyGame extends BaseGame with HasTapableComponents {
|
||||
MyGame() {
|
||||
add(TapableSquare(y: 100));
|
||||
add(TapableSquare(y: 250));
|
||||
add(TapableSquare());
|
||||
add(TapableSquare()..y = 250);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,8 @@ class Selector extends SpriteComponent {
|
||||
bool show = false;
|
||||
|
||||
Selector(double s)
|
||||
: super.fromSprite(s, s, Sprite('selector.png', width: 32, height: 32));
|
||||
: super.fromSprite(
|
||||
Vector2.all(s), Sprite('selector.png', size: Vector2.all(32.0)));
|
||||
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
@ -81,6 +82,6 @@ class MyGame extends BaseGame with MouseMovementDetector {
|
||||
final screenPosition = event.position.toVector2();
|
||||
final block = base.getBlock(screenPosition);
|
||||
selector.show = base.containsBlock(block);
|
||||
selector.setPosition(base.getBlockPosition(block) + topLeft);
|
||||
selector.position = base.getBlockPosition(block) + topLeft;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -50,11 +50,8 @@ class MyGame extends BaseGame {
|
||||
Flame.audio.load('boin.mp3');
|
||||
Flame.audio.loop('music.mp3', volume: 0.4);
|
||||
|
||||
add(
|
||||
Ball(size)
|
||||
..y = (size.y / 2) - 50
|
||||
..width = 100
|
||||
..height = 100,
|
||||
);
|
||||
add(Ball(size)
|
||||
..y = (size.y / 2) - 50
|
||||
..size = Vector2.all(100));
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,8 +27,10 @@ class MyGame extends BaseGame {
|
||||
|
||||
void initSprites() async {
|
||||
final r = Random();
|
||||
List.generate(500, (i) => SpriteComponent.square(32, 'test.png'))
|
||||
.forEach((sprite) {
|
||||
List.generate(
|
||||
500,
|
||||
(i) => SpriteComponent.fromImagePath(Vector2.all(32), 'test.png'),
|
||||
).forEach((sprite) {
|
||||
sprite.x = r.nextInt(size.x.toInt()).toDouble();
|
||||
sprite.y = r.nextInt(size.y.toInt()).toDouble();
|
||||
add(sprite);
|
||||
|
||||
@ -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,14 @@ 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)
|
||||
..x = 150
|
||||
..y = 100;
|
||||
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 +72,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,6 @@ class Anchor {
|
||||
const Anchor(this.x, this.y);
|
||||
|
||||
Vector2 translate(Vector2 p, Vector2 size) {
|
||||
return p - relativePosition
|
||||
..multiply(size);
|
||||
return p - (relativePosition..multiply(size));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,14 @@ class FlareComponent extends PositionComponent {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
set size(Vector2 newSize) {
|
||||
super.size = newSize;
|
||||
if (loaded()) {
|
||||
_flareAnimation.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool loaded() => _flareAnimation != null;
|
||||
|
||||
@ -50,20 +55,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,17 +93,14 @@ class IsometricTileMapComponent extends PositionComponent {
|
||||
void render(Canvas c) {
|
||||
super.render(c);
|
||||
|
||||
final size = Vector2(
|
||||
effectiveTileSize.toDouble(),
|
||||
effectiveTileSize.toDouble(),
|
||||
);
|
||||
final size = Vector2.all(effectiveTileSize.toDouble());
|
||||
for (int i = 0; i < matrix.length; i++) {
|
||||
for (int j = 0; j < matrix[i].length; j++) {
|
||||
final element = matrix[i][j];
|
||||
if (element != -1) {
|
||||
final sprite = tileset.getTile(element);
|
||||
final p = getBlockPositionInts(j, i);
|
||||
sprite.renderRect(c, p.toRect(size));
|
||||
sprite.renderRect(c, p.toPositionedRect(size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 'dart:ui' hide Offset;
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:ordered_set/comparing.dart';
|
||||
@ -9,14 +8,15 @@ import '../anchor.dart';
|
||||
import '../effects/effects.dart';
|
||||
import '../game.dart';
|
||||
import '../text_config.dart';
|
||||
import '../extensions/offset.dart';
|
||||
import '../extensions/vector2.dart';
|
||||
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,26 +25,43 @@ 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 {
|
||||
/// X position of this component on the screen (measured from the top left corner).
|
||||
double x = 0.0;
|
||||
/// The position of this component on the screen (relative to the anchor).
|
||||
Vector2 position = Vector2.zero();
|
||||
|
||||
/// Y position of this component on the screen (measured from the top left corner).
|
||||
double y = 0.0;
|
||||
/// X position of this component on the screen (relative to the anchor).
|
||||
double get x => position.x;
|
||||
set x(double x) => position.x = x;
|
||||
|
||||
/// Y position of this component on the screen (relative to the anchor).
|
||||
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;
|
||||
set width(double width) => size.x = width;
|
||||
|
||||
/// Height (size) that this component is rendered with.
|
||||
double get height => size.y;
|
||||
set height(double height) => size.y = height;
|
||||
|
||||
/// Get the top left position regardless of the anchor
|
||||
Vector2 get topLeftPosition => anchor.translate(position, size);
|
||||
|
||||
/// Set the top left position regardless of the anchor
|
||||
set topLeftPosition(Vector2 position) {
|
||||
this.position = position + (anchor.relativePosition..multiply(size));
|
||||
}
|
||||
|
||||
/// 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 [position] is relative to this point inside the component.
|
||||
/// The [angle] is rotated around this point.
|
||||
Anchor anchor = Anchor.topLeft;
|
||||
|
||||
@ -72,51 +89,23 @@ 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(
|
||||
x - anchor.relativePosition.x * width,
|
||||
y - anchor.relativePosition.y * height,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
Rect toRect() => topLeftPosition.toPositionedRect(size);
|
||||
|
||||
/// Mutates x, y, width and height using the provided [rect] as basis.
|
||||
/// Mutates position and size 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;
|
||||
size.setValues(rect.width, rect.height);
|
||||
topLeftPosition = rect.topLeft.toVector2();
|
||||
}
|
||||
|
||||
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)}',
|
||||
@ -137,9 +126,9 @@ abstract class PositionComponent extends Component {
|
||||
canvas.translate(x, y);
|
||||
|
||||
canvas.rotate(angle);
|
||||
final double dx = -anchor.relativePosition.x * width;
|
||||
final double dy = -anchor.relativePosition.y * height;
|
||||
canvas.translate(dx, dy);
|
||||
final Vector2 delta = -anchor.relativePosition
|
||||
..multiply(size);
|
||||
canvas.translate(delta.x, delta.y);
|
||||
|
||||
// Handle inverted rendering by moving center and flipping.
|
||||
if (renderFlipX || renderFlipY) {
|
||||
|
||||
@ -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';
|
||||
@ -22,15 +23,11 @@ class SpriteComponent extends PositionComponent {
|
||||
|
||||
SpriteComponent();
|
||||
|
||||
SpriteComponent.square(double size, String imagePath)
|
||||
: this.rectangle(size, size, imagePath);
|
||||
SpriteComponent.fromImagePath(Vector2 size, String imagePath)
|
||||
: this.fromSprite(size, Sprite(imagePath));
|
||||
|
||||
SpriteComponent.rectangle(double width, double height, String imagePath)
|
||||
: this.fromSprite(width, height, 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
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
@ -43,6 +41,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;
|
||||
|
||||
@ -16,11 +16,6 @@ extension RectExtension on Rect {
|
||||
// Until [extension] will allow static methods we need to keep these functions
|
||||
// in a utility class
|
||||
class RectFactory {
|
||||
/// Creates a [Rect] with the size of [Size]
|
||||
static Rect fromSize(Size size) {
|
||||
return Rect.fromLTWH(0, 0, size.width, size.height);
|
||||
}
|
||||
|
||||
/// 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 origin and going the [Vector2]
|
||||
Rect toRect() => Rect.fromLTWH(0, 0, x, y);
|
||||
|
||||
/// Linearly interpolate towards another Vector2
|
||||
void lerp(Vector2 to, double t) {
|
||||
@ -43,4 +44,7 @@ extension Vector2Extension on Vector2 {
|
||||
scale(newLength.abs() / l);
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a Vector2 with ints as input
|
||||
static Vector2 fromInts(int x, int y) => Vector2(x.toDouble(), y.toDouble());
|
||||
}
|
||||
|
||||
@ -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,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'extensions/vector2.dart';
|
||||
import 'flame.dart';
|
||||
import 'sprite.dart';
|
||||
|
||||
@ -75,22 +76,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++) {
|
||||
for (int 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 +104,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++) {
|
||||
for (int 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]);
|
||||
}
|
||||
@ -145,10 +147,8 @@ class SpriteAnimation {
|
||||
|
||||
final Sprite sprite = Sprite(
|
||||
imagePath,
|
||||
x: x.toDouble(),
|
||||
y: y.toDouble(),
|
||||
width: width.toDouble(),
|
||||
height: height.toDouble(),
|
||||
position: Vector2Extension.fromInts(x, y),
|
||||
size: Vector2Extension.fromInts(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,
|
||||
) {
|
||||
final 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,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/anchor.dart';
|
||||
import 'package:flame/components/position_component.dart';
|
||||
import 'package:flame/components/sprite_component.dart';
|
||||
import 'package:flame/extensions/vector2.dart';
|
||||
@ -9,38 +10,35 @@ 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;
|
||||
expect(c.toRect().left, 0.0);
|
||||
expect(c.toRect().top, 1.0);
|
||||
expect(c.toRect().width, 2.0);
|
||||
expect(c.toRect().height, 2.0);
|
||||
c.position = Vector2(0.0, 1.0);
|
||||
c.size = Vector2(2.0, 2.0);
|
||||
final rect = c.toRect();
|
||||
expect(rect.left, 0.0);
|
||||
expect(rect.top, 1.0);
|
||||
expect(rect.width, 2.0);
|
||||
expect(rect.height, 2.0);
|
||||
|
||||
c.setByRect(const Rect.fromLTWH(10.0, 10.0, 1.0, 1.0));
|
||||
expect(c.x, 10.0);
|
||||
@ -48,5 +46,33 @@ void main() {
|
||||
expect(c.width, 1.0);
|
||||
expect(c.height, 1.0);
|
||||
});
|
||||
|
||||
test('test get/set rect with anchor', () {
|
||||
final PositionComponent c = SpriteComponent();
|
||||
c.position = Vector2(0.0, 1.0);
|
||||
c.size = Vector2(2.0, 2.0);
|
||||
c.anchor = Anchor.center;
|
||||
final rect = c.toRect();
|
||||
expect(rect.left, -1.0);
|
||||
expect(rect.top, 0.0);
|
||||
expect(rect.width, 2.0);
|
||||
expect(rect.height, 2.0);
|
||||
|
||||
c.setByRect(const Rect.fromLTWH(10.0, 10.0, 1.0, 1.0));
|
||||
expect(c.x, 10.5);
|
||||
expect(c.y, 10.5);
|
||||
expect(c.width, 1.0);
|
||||
expect(c.height, 1.0);
|
||||
});
|
||||
|
||||
test('test get/set anchorPosition', () {
|
||||
final PositionComponent c = SpriteComponent();
|
||||
c.position = Vector2(0.0, 1.0);
|
||||
c.size = Vector2(2.0, 2.0);
|
||||
c.anchor = Anchor.center;
|
||||
final anchorPosition = c.topLeftPosition;
|
||||
expect(anchorPosition.x, -1.0);
|
||||
expect(anchorPosition.y, 0.0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user