mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-01 10:38:17 +08:00
Move from Position to Vector2
This commit is contained in:
@ -123,13 +123,13 @@ Note that it could be any component, however complex, inside your widgets tree.
|
||||
```dart
|
||||
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
|
||||
import 'package:flame/vector.dart'; // imports the Vector2 class
|
||||
```
|
||||
|
||||
How we do the magic then? Just add the following to your widget tree:
|
||||
How do we do the magic then? Just add the following to your widget tree:
|
||||
|
||||
```dart
|
||||
Flame.util.animationAsWidget(Position(WIDTH, HEIGHT), SpriteAnimation.sequenced('minotaur.png', AMOUNT, textureWidth: FRAME_WIDTH))
|
||||
Flame.util.animationAsWidget(Vector2(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).
|
||||
|
||||
@ -4,7 +4,7 @@ import 'package:flame/flame.dart';
|
||||
import 'package:flame/sprite_animation.dart';
|
||||
import 'package:flame/sprite.dart';
|
||||
import 'package:flame/spritesheet.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/widgets/animation_widget.dart';
|
||||
import 'package:flame/widgets/sprite_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -50,7 +50,7 @@ class MyHomePage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
Position _position = Position(256.0, 256.0);
|
||||
Vector2 _position = Vector2(256.0, 256.0);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -61,7 +61,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
void changePosition() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
setState(() {
|
||||
_position = Position(10 + _position.x, 10 + _position.y);
|
||||
_position = Vector2(10 + _position.x, 10 + _position.y);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ import 'package:flame/gestures.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/sprite_animation.dart';
|
||||
import 'package:flame/components/sprite_animation_component.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -10,7 +11,7 @@ void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Flame.images.loadAll(['creature.png', 'chopper.png']);
|
||||
|
||||
final Size size = await Flame.util.initialDimensions();
|
||||
final Vector2 size = await Flame.util.initialDimensions();
|
||||
final game = MyGame(size);
|
||||
runApp(game.widget);
|
||||
}
|
||||
@ -53,12 +54,12 @@ class MyGame extends BaseGame with TapDetector {
|
||||
addAnimation(evt.globalPosition.dx, evt.globalPosition.dy);
|
||||
}
|
||||
|
||||
MyGame(Size screenSize) {
|
||||
MyGame(Vector2 screenSize) {
|
||||
size = screenSize;
|
||||
|
||||
const s = 100.0;
|
||||
final animationComponent = SpriteAnimationComponent(s, s, animation);
|
||||
animationComponent.x = size.width / 2 - s;
|
||||
animationComponent.x = size.x / 2 - s;
|
||||
animationComponent.y = s;
|
||||
|
||||
final reversedAnimationComponent = SpriteAnimationComponent(
|
||||
@ -66,7 +67,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
s,
|
||||
animation.reversed(),
|
||||
);
|
||||
reversedAnimationComponent.x = size.width / 2;
|
||||
reversedAnimationComponent.x = size.x / 2;
|
||||
reversedAnimationComponent.y = s;
|
||||
|
||||
add(animationComponent);
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/sprite_animation.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/components/sprite_animation_component.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final Size size = await Flame.util.initialDimensions();
|
||||
final Vector2 size = await Flame.util.initialDimensions();
|
||||
runApp(MyGame(size).widget);
|
||||
}
|
||||
|
||||
class MyGame extends BaseGame {
|
||||
MyGame(Size screenSize) {
|
||||
MyGame(Vector2 screenSize) {
|
||||
size = screenSize;
|
||||
_start();
|
||||
}
|
||||
@ -23,8 +24,8 @@ class MyGame extends BaseGame {
|
||||
);
|
||||
final animationComponent = SpriteAnimationComponent(200, 200, animation);
|
||||
|
||||
animationComponent.x = (size.width / 2) - 100;
|
||||
animationComponent.y = (size.height / 2) - 100;
|
||||
animationComponent.x = (size.x / 2) - 100;
|
||||
animationComponent.y = (size.y / 2) - 100;
|
||||
|
||||
add(animationComponent);
|
||||
}
|
||||
|
||||
@ -5,14 +5,14 @@ import 'package:flame/audio_pool.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/palette.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/text_config.dart';
|
||||
import 'package:flame/gestures.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final Size size = await Flame.util.initialDimensions();
|
||||
final Vector2 size = await Flame.util.initialDimensions();
|
||||
final MyGame game = MyGame(size);
|
||||
runApp(game.widget);
|
||||
}
|
||||
@ -23,14 +23,14 @@ AudioPool pool = AudioPool('laser.mp3');
|
||||
class MyGame extends BaseGame with TapDetector {
|
||||
static final black = BasicPalette.black.paint;
|
||||
|
||||
MyGame(Size screenSize) {
|
||||
MyGame(Vector2 screenSize) {
|
||||
size = screenSize;
|
||||
}
|
||||
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
canvas.drawRect(Rect.fromLTWH(0.0, 0.0, size.width, size.height), black);
|
||||
final p = Position.fromSize(size).div(2);
|
||||
canvas.drawRect(Rect.fromLTWH(0.0, 0.0, size.x, size.y), black);
|
||||
final p = size / 2;
|
||||
regular.render(canvas, 'hit me!', p, anchor: Anchor.center);
|
||||
super.render(canvas);
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/components/sprite_component.dart';
|
||||
import 'package:flame/components/mixins/resizable.dart';
|
||||
import 'package:flame/text_config.dart';
|
||||
@ -34,14 +34,14 @@ class AndroidComponent extends SpriteComponent with Resizable {
|
||||
final rect = toRect();
|
||||
|
||||
if ((x <= 0 && xDirection == -1) ||
|
||||
(rect.right >= size.width && xDirection == 1)) {
|
||||
(rect.right >= size.x && xDirection == 1)) {
|
||||
xDirection = xDirection * -1;
|
||||
}
|
||||
|
||||
y += yDirection * SPEED * dt;
|
||||
|
||||
if ((y <= 0 && yDirection == -1) ||
|
||||
(rect.bottom >= size.height && yDirection == 1)) {
|
||||
(rect.bottom >= size.y && yDirection == 1)) {
|
||||
yDirection = yDirection * -1;
|
||||
}
|
||||
}
|
||||
@ -81,7 +81,7 @@ class MyGame extends BaseGame {
|
||||
super.render(canvas);
|
||||
|
||||
if (debugMode()) {
|
||||
fpsTextConfig.render(canvas, fps(120).toString(), Position(0, 50));
|
||||
fpsTextConfig.render(canvas, fps(120).toString(), Vector2(0, 50));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import 'package:flame/effects/move_effect.dart';
|
||||
import 'package:flame/effects/scale_effect.dart';
|
||||
import 'package:flame/effects/rotate_effect.dart';
|
||||
import 'package:flame/gestures.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -37,7 +37,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
greenSquare.clearEffects();
|
||||
|
||||
final move = MoveEffect(
|
||||
destination: Position(dx, dy),
|
||||
destination: Vector2(dx, dy),
|
||||
speed: 250.0,
|
||||
curve: Curves.linear,
|
||||
isInfinite: false,
|
||||
@ -45,7 +45,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
);
|
||||
|
||||
final scale = ScaleEffect(
|
||||
size: Size(dx, dy),
|
||||
size: Vector2(dx, dy),
|
||||
speed: 250.0,
|
||||
curve: Curves.linear,
|
||||
isInfinite: false,
|
||||
|
||||
@ -2,7 +2,7 @@ import 'package:flame/effects/move_effect.dart';
|
||||
import 'package:flame/effects/scale_effect.dart';
|
||||
import 'package:flame/effects/rotate_effect.dart';
|
||||
import 'package:flame/gestures.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -44,7 +44,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
orangeSquare.clearEffects();
|
||||
|
||||
greenSquare.addEffect(MoveEffect(
|
||||
destination: Position(dx, dy),
|
||||
destination: Vector2(dx, dy),
|
||||
speed: 250.0,
|
||||
curve: Curves.bounceInOut,
|
||||
isInfinite: true,
|
||||
@ -52,7 +52,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
));
|
||||
|
||||
redSquare.addEffect(ScaleEffect(
|
||||
size: Size(dx, dy),
|
||||
size: Vector2(dx, dy),
|
||||
speed: 250.0,
|
||||
curve: Curves.easeInCubic,
|
||||
isInfinite: true,
|
||||
|
||||
@ -3,7 +3,7 @@ import 'package:flame/effects/scale_effect.dart';
|
||||
import 'package:flame/effects/rotate_effect.dart';
|
||||
import 'package:flame/effects/sequence_effect.dart';
|
||||
import 'package:flame/gestures.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -34,7 +34,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
greenSquare.clearEffects();
|
||||
|
||||
final move1 = MoveEffect(
|
||||
destination: Position(dx, dy),
|
||||
destination: Vector2(dx, dy),
|
||||
speed: 250.0,
|
||||
curve: Curves.bounceInOut,
|
||||
isInfinite: false,
|
||||
@ -42,7 +42,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
);
|
||||
|
||||
final move2 = MoveEffect(
|
||||
destination: Position(dx, dy + 150),
|
||||
destination: Vector2(dx, dy + 150),
|
||||
speed: 150.0,
|
||||
curve: Curves.easeIn,
|
||||
isInfinite: false,
|
||||
@ -50,7 +50,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
);
|
||||
|
||||
final scale = ScaleEffect(
|
||||
size: Size(dx, dy),
|
||||
size: Vector2(dx, dy),
|
||||
speed: 250.0,
|
||||
curve: Curves.easeInCubic,
|
||||
isInfinite: false,
|
||||
|
||||
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/gestures.dart';
|
||||
import 'package:flame/effects/effects.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
|
||||
import './square.dart';
|
||||
|
||||
@ -17,10 +17,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
@override
|
||||
void onTapUp(details) {
|
||||
square.addEffect(MoveEffect(
|
||||
destination: Position(
|
||||
details.localPosition.dx,
|
||||
details.localPosition.dy,
|
||||
),
|
||||
destination: VectorUtil.fromOffset(details.localPosition),
|
||||
speed: 250.0,
|
||||
curve: Curves.bounceInOut,
|
||||
));
|
||||
|
||||
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/gestures.dart';
|
||||
import 'package:flame/anchor.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/effects/effects.dart';
|
||||
|
||||
import './square.dart';
|
||||
@ -23,7 +24,7 @@ class MyGame extends BaseGame with TapDetector {
|
||||
|
||||
grow = !grow;
|
||||
square.addEffect(ScaleEffect(
|
||||
size: Size(s, s),
|
||||
size: Vector2(s, s),
|
||||
speed: 250.0,
|
||||
curve: Curves.bounceInOut,
|
||||
));
|
||||
|
||||
@ -5,6 +5,7 @@ import 'package:flame/components/component.dart';
|
||||
import 'package:flame/components/joystick/joystick_component.dart';
|
||||
import 'package:flame/components/joystick/joystick_events.dart';
|
||||
import 'package:flame/palette.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
|
||||
class Player extends Component implements JoystickListener {
|
||||
final _whitePaint = BasicPalette.white.paint;
|
||||
@ -42,10 +43,10 @@ class Player extends Component implements JoystickListener {
|
||||
}
|
||||
|
||||
@override
|
||||
void resize(Size size) {
|
||||
void resize(Vector2 size) {
|
||||
_rect = Rect.fromLTWH(
|
||||
(size.width / 2) - 25,
|
||||
(size.height / 2) - 25,
|
||||
(size.x / 2) - 25,
|
||||
(size.y / 2) - 25,
|
||||
50,
|
||||
50,
|
||||
);
|
||||
|
||||
@ -2,6 +2,7 @@ import 'package:flame/game.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/nine_tile_box.dart';
|
||||
import 'package:flame/sprite.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@ -14,7 +15,7 @@ void main() async {
|
||||
}
|
||||
|
||||
class MyGame extends Game {
|
||||
Size size;
|
||||
Vector2 size;
|
||||
NineTileBox nineTileBox;
|
||||
|
||||
MyGame(this.size) {
|
||||
@ -25,8 +26,8 @@ class MyGame extends Game {
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
const length = 300.0;
|
||||
final x = (size.width - length) / 2;
|
||||
final y = (size.height - length) / 2;
|
||||
final x = (size.x - length) / 2;
|
||||
final y = (size.y - length) / 2;
|
||||
nineTileBox.draw(canvas, x, y, length, length);
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/time.dart' as flame_time;
|
||||
import 'package:flame/particle.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/sprite.dart';
|
||||
import 'package:flame/spritesheet.dart';
|
||||
import 'package:flame/text_config.dart';
|
||||
@ -33,7 +33,7 @@ class MyGame extends BaseGame {
|
||||
/// Defines dimensions of the sample
|
||||
/// grid to be displayed on the screen,
|
||||
/// 5x5 in this particular case
|
||||
static const gridSize = 5;
|
||||
static const gridSize = 5.0;
|
||||
static const steps = 5;
|
||||
|
||||
/// Miscellaneous values used
|
||||
@ -48,17 +48,17 @@ class MyGame extends BaseGame {
|
||||
/// Defines the lifespan of all the particles in these examples
|
||||
final sceneDuration = const Duration(seconds: 1);
|
||||
|
||||
Offset cellSize;
|
||||
Offset halfCellSize;
|
||||
Vector2 cellSize;
|
||||
Vector2 halfCellSize;
|
||||
|
||||
@override
|
||||
bool recordFps() => true;
|
||||
|
||||
MyGame({
|
||||
Size screenSize,
|
||||
Vector2 screenSize,
|
||||
}) {
|
||||
size = screenSize;
|
||||
cellSize = Offset(size.width / gridSize, size.height / gridSize);
|
||||
cellSize = size / gridSize;
|
||||
halfCellSize = cellSize * .5;
|
||||
|
||||
// Spawn new particles every second
|
||||
@ -98,17 +98,17 @@ class MyGame extends BaseGame {
|
||||
// as per defined grid parameters
|
||||
do {
|
||||
final particle = particles.removeLast();
|
||||
final col = particles.length % gridSize;
|
||||
final row = particles.length ~/ gridSize;
|
||||
final double col = particles.length % gridSize;
|
||||
final double row = (particles.length ~/ gridSize).toDouble();
|
||||
final cellCenter =
|
||||
cellSize.scale(col.toDouble(), row.toDouble()) + (cellSize * .5);
|
||||
(cellSize.clone()..multiply(Vector2(col, row))) + (cellSize * .5);
|
||||
|
||||
add(
|
||||
// Bind all the particles to a [Component] update
|
||||
// lifecycle from the [BaseGame].
|
||||
TranslatedParticle(
|
||||
lifespan: 1,
|
||||
offset: cellCenter,
|
||||
offset: VectorUtil.toOffset(cellCenter),
|
||||
child: particle,
|
||||
).asComponent(),
|
||||
);
|
||||
@ -162,10 +162,10 @@ class MyGame extends BaseGame {
|
||||
return Particle.generate(
|
||||
count: 5,
|
||||
generator: (i) {
|
||||
final currentColumn = (cellSize.dx / 5) * i - halfCellSize.dx;
|
||||
final currentColumn = (cellSize.x / 5) * i - halfCellSize.x;
|
||||
return MovingParticle(
|
||||
from: Offset(currentColumn, -halfCellSize.dy),
|
||||
to: Offset(currentColumn, halfCellSize.dy),
|
||||
from: Offset(currentColumn, -halfCellSize.y),
|
||||
to: Offset(currentColumn, halfCellSize.y),
|
||||
child: CircleParticle(
|
||||
radius: 2.0,
|
||||
paint: Paint()..color = Colors.blue,
|
||||
@ -234,7 +234,7 @@ class MyGame extends BaseGame {
|
||||
return ComputedParticle(
|
||||
renderer: (canvas, particle) => canvas.drawCircle(
|
||||
Offset.zero,
|
||||
particle.progress * halfCellSize.dx,
|
||||
particle.progress * halfCellSize.x,
|
||||
Paint()
|
||||
..color = Color.lerp(
|
||||
Colors.red,
|
||||
@ -258,7 +258,7 @@ class MyGame extends BaseGame {
|
||||
|
||||
canvas.drawCircle(
|
||||
Offset.zero,
|
||||
(1 - steppedProgress) * halfCellSize.dx,
|
||||
(1 - steppedProgress) * halfCellSize.x,
|
||||
Paint()
|
||||
..color = Color.lerp(
|
||||
Colors.red,
|
||||
@ -294,7 +294,7 @@ class MyGame extends BaseGame {
|
||||
/// be reused across particles. See example below for more details.
|
||||
Particle imageParticle() {
|
||||
return ImageParticle(
|
||||
size: const Size.square(24),
|
||||
size: Vector2.all(24),
|
||||
image: Flame.images.loadedFiles['zap.png'].loadedImage,
|
||||
);
|
||||
}
|
||||
@ -309,8 +309,8 @@ class MyGame extends BaseGame {
|
||||
const count = 9;
|
||||
const perLine = 3;
|
||||
const imageSize = 24.0;
|
||||
final colWidth = cellSize.dx / perLine;
|
||||
final rowHeight = cellSize.dy / perLine;
|
||||
final colWidth = cellSize.x / perLine;
|
||||
final rowHeight = cellSize.y / perLine;
|
||||
|
||||
reusableImageParticle ??= imageParticle();
|
||||
|
||||
@ -318,8 +318,8 @@ class MyGame extends BaseGame {
|
||||
count: count,
|
||||
generator: (i) => TranslatedParticle(
|
||||
offset: Offset(
|
||||
(i % perLine) * colWidth - halfCellSize.dx + imageSize,
|
||||
(i ~/ perLine) * rowHeight - halfCellSize.dy + imageSize,
|
||||
(i % perLine) * colWidth - halfCellSize.x + imageSize,
|
||||
(i ~/ perLine) * rowHeight - halfCellSize.y + imageSize,
|
||||
),
|
||||
child: reusableImageParticle),
|
||||
);
|
||||
@ -386,7 +386,7 @@ class MyGame extends BaseGame {
|
||||
Particle spriteParticle() {
|
||||
return SpriteParticle(
|
||||
sprite: Sprite('zap.png'),
|
||||
size: Position.fromOffset(cellSize * .5),
|
||||
size: cellSize * .5,
|
||||
);
|
||||
}
|
||||
|
||||
@ -395,7 +395,7 @@ class MyGame extends BaseGame {
|
||||
Particle animationParticle() {
|
||||
return SpriteAnimationParticle(
|
||||
animation: getBoomAnimation(),
|
||||
size: Position(128, 128),
|
||||
size: Vector2(128, 128),
|
||||
);
|
||||
}
|
||||
|
||||
@ -405,8 +405,8 @@ class MyGame extends BaseGame {
|
||||
/// which is independent from the parent [Particle].
|
||||
Particle componentParticle() {
|
||||
return MovingParticle(
|
||||
from: -halfCellSize * .2,
|
||||
to: halfCellSize * .2,
|
||||
from: VectorUtil.toOffset(-halfCellSize * .2),
|
||||
to: VectorUtil.toOffset(halfCellSize * .2),
|
||||
curve: SineCurve(),
|
||||
child: ComponentParticle(component: trafficLight),
|
||||
);
|
||||
@ -473,19 +473,22 @@ class MyGame extends BaseGame {
|
||||
),
|
||||
);
|
||||
|
||||
final cellSizeOffset = VectorUtil.toOffset(cellSize);
|
||||
final halfCellSizeOffset = VectorUtil.toOffset(halfCellSize);
|
||||
|
||||
return ComposedParticle(children: <Particle>[
|
||||
rect
|
||||
.rotating(to: pi / 2)
|
||||
.moving(to: -cellSize)
|
||||
.moving(to: -cellSizeOffset)
|
||||
.scaled(2)
|
||||
.accelerated(acceleration: halfCellSize * 5)
|
||||
.translated(halfCellSize),
|
||||
.accelerated(acceleration: halfCellSizeOffset * 5)
|
||||
.translated(halfCellSizeOffset),
|
||||
rect
|
||||
.rotating(to: -pi)
|
||||
.moving(to: cellSize.scale(1, -1))
|
||||
.moving(to: cellSizeOffset.scale(1, -1))
|
||||
.scaled(2)
|
||||
.translated(halfCellSize.scale(-1, 1))
|
||||
.accelerated(acceleration: halfCellSize.scale(-5, 5))
|
||||
.translated(halfCellSizeOffset.scale(-1, 1))
|
||||
.accelerated(acceleration: halfCellSizeOffset.scale(-5, 5))
|
||||
]);
|
||||
}
|
||||
|
||||
@ -497,15 +500,18 @@ class MyGame extends BaseGame {
|
||||
super.render(canvas);
|
||||
|
||||
if (debugMode()) {
|
||||
fpsTextConfig.render(canvas, '${fps(120).toStringAsFixed(2)}fps',
|
||||
Position(0, size.height - 24));
|
||||
fpsTextConfig.render(
|
||||
canvas, '${fps(120).toStringAsFixed(2)}fps', Vector2(0, size.y - 24));
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns random [Offset] within a virtual
|
||||
/// grid cell
|
||||
Offset randomCellOffset() {
|
||||
return cellSize.scale(rnd.nextDouble(), rnd.nextDouble()) - halfCellSize;
|
||||
return Offset(
|
||||
cellSize.x * rnd.nextDouble() - halfCellSize.x,
|
||||
cellSize.y * rnd.nextDouble() - halfCellSize.y,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns random [Color] from primary swatches
|
||||
@ -543,7 +549,7 @@ class MyGame extends BaseGame {
|
||||
}
|
||||
|
||||
Future<BaseGame> loadGame() async {
|
||||
Size gameSize;
|
||||
Vector2 gameSize;
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
await Future.wait([
|
||||
|
||||
@ -2,11 +2,12 @@ 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:flame/vector.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final Size size = await Flame.util.initialDimensions();
|
||||
final Vector2 size = await Flame.util.initialDimensions();
|
||||
final game = MyGame(size);
|
||||
runApp(game.widget);
|
||||
}
|
||||
@ -22,11 +23,11 @@ class MyGame extends BaseGame {
|
||||
|
||||
SpriteAnimationComponent buildAnimation() {
|
||||
final ac = SpriteAnimationComponent(100, 100, animation);
|
||||
ac.x = size.width / 2 - ac.width / 2;
|
||||
ac.x = size.x / 2 - ac.width / 2;
|
||||
return ac;
|
||||
}
|
||||
|
||||
MyGame(Size screenSize) {
|
||||
MyGame(Vector2 screenSize) {
|
||||
size = screenSize;
|
||||
|
||||
final regular = buildAnimation();
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/components/position_component.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final Size size = await Flame.util.initialDimensions();
|
||||
final Vector2 size = await Flame.util.initialDimensions();
|
||||
runApp(MyGame(size).widget);
|
||||
}
|
||||
|
||||
class Ball extends PositionComponent {
|
||||
final Size gameSize;
|
||||
final Vector2 gameSize;
|
||||
final paint = Paint()..color = const Color(0xFFFFFFFF);
|
||||
|
||||
bool forward = true;
|
||||
@ -28,9 +29,9 @@ class Ball extends PositionComponent {
|
||||
super.update(dt);
|
||||
x += (forward ? 1 : -1) * 100 * dt;
|
||||
|
||||
if (x <= 0 || x + width >= gameSize.width) {
|
||||
if (x <= 0 || x + width >= gameSize.x) {
|
||||
if (forward) {
|
||||
x = gameSize.width - width - 1;
|
||||
x = gameSize.x - width - 1;
|
||||
} else {
|
||||
x = 1;
|
||||
}
|
||||
@ -42,7 +43,7 @@ class Ball extends PositionComponent {
|
||||
}
|
||||
|
||||
class MyGame extends BaseGame {
|
||||
MyGame(Size screenSize) {
|
||||
MyGame(Vector2 screenSize) {
|
||||
size = screenSize;
|
||||
|
||||
Flame.audio.disableLog();
|
||||
@ -51,7 +52,7 @@ class MyGame extends BaseGame {
|
||||
|
||||
add(
|
||||
Ball(size)
|
||||
..y = (size.height / 2) - 50
|
||||
..y = (size.y / 2) - 50
|
||||
..width = 100
|
||||
..height = 100,
|
||||
);
|
||||
|
||||
@ -4,11 +4,12 @@ import 'package:flame/flame.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/sprite_batch.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/components/sprite_batch_component.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final Size size = await Flame.util.initialDimensions();
|
||||
final Vector2 size = await Flame.util.initialDimensions();
|
||||
final game = MyGame(size);
|
||||
runApp(game.widget);
|
||||
}
|
||||
@ -16,7 +17,7 @@ void main() async {
|
||||
class MyGame extends BaseGame {
|
||||
SpriteBatch spriteBatch;
|
||||
|
||||
MyGame(Size screenSize) {
|
||||
MyGame(Vector2 screenSize) {
|
||||
size = screenSize;
|
||||
|
||||
initData();
|
||||
@ -44,8 +45,8 @@ class MyGame extends BaseGame {
|
||||
for (int i = 0; i < NUM; ++i) {
|
||||
final sx = r.nextInt(8) * 128.0;
|
||||
final sy = r.nextInt(8) * 128.0;
|
||||
final x = r.nextInt(size.width.toInt()).toDouble();
|
||||
final y = r.nextInt(size.height ~/ 2).toDouble() + size.height / 2.0;
|
||||
final x = r.nextInt(size.x.toInt()).toDouble();
|
||||
final y = r.nextInt(size.y ~/ 2).toDouble() + size.y / 2.0;
|
||||
spriteBatch.add(
|
||||
rect: Rect.fromLTWH(sx, sy, 128, 128),
|
||||
offset: Offset(x - 64, y - 64),
|
||||
|
||||
@ -3,17 +3,18 @@ import 'dart:math';
|
||||
import 'package:flame/components/sprite_component.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final Size size = await Flame.util.initialDimensions();
|
||||
final Vector2 size = await Flame.util.initialDimensions();
|
||||
final game = MyGame(size);
|
||||
runApp(game.widget);
|
||||
}
|
||||
|
||||
class MyGame extends BaseGame {
|
||||
MyGame(Size screenSize) {
|
||||
MyGame(Vector2 screenSize) {
|
||||
size = screenSize;
|
||||
}
|
||||
|
||||
@ -28,8 +29,8 @@ class MyGame extends BaseGame {
|
||||
final r = Random();
|
||||
List.generate(500, (i) => SpriteComponent.square(32, 'test.png'))
|
||||
.forEach((sprite) {
|
||||
sprite.x = r.nextInt(size.width.toInt()).toDouble();
|
||||
sprite.y = r.nextInt(size.height.toInt()).toDouble();
|
||||
sprite.x = r.nextInt(size.x.toInt()).toDouble();
|
||||
sprite.y = r.nextInt(size.y.toInt()).toDouble();
|
||||
add(sprite);
|
||||
});
|
||||
}
|
||||
|
||||
@ -7,10 +7,11 @@ import 'package:flame/flame.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/palette.dart';
|
||||
import 'package:flame/text_config.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() async {
|
||||
final Size size = await Flame.util.initialDimensions();
|
||||
final Vector2 size = await Flame.util.initialDimensions();
|
||||
runApp(MyGame(size).widget);
|
||||
}
|
||||
|
||||
@ -34,27 +35,27 @@ class MyTextBox extends TextBoxComponent {
|
||||
}
|
||||
|
||||
class MyGame extends BaseGame {
|
||||
MyGame(Size screenSize) {
|
||||
MyGame(Vector2 screenSize) {
|
||||
size = screenSize;
|
||||
add(TextComponent('Hello, Flame', config: regular)
|
||||
..anchor = Anchor.topCenter
|
||||
..x = size.width / 2
|
||||
..x = size.x / 2
|
||||
..y = 32.0);
|
||||
|
||||
add(TextComponent('center', config: tiny)
|
||||
..anchor = Anchor.center
|
||||
..x = size.width / 2
|
||||
..y = size.height / 2);
|
||||
..x = size.x / 2
|
||||
..y = size.y / 2);
|
||||
|
||||
add(TextComponent('bottomRight', config: tiny)
|
||||
..anchor = Anchor.bottomRight
|
||||
..x = size.width
|
||||
..y = size.height);
|
||||
..x = size.x
|
||||
..y = size.y);
|
||||
|
||||
add(MyTextBox(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eget ligula eu lectus lobortis condimentum.',
|
||||
)
|
||||
..anchor = Anchor.bottomLeft
|
||||
..y = size.height);
|
||||
..y = size.y);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/time.dart';
|
||||
import 'package:flame/text_config.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/gestures.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flame/components/timer_component.dart';
|
||||
|
||||
void main() {
|
||||
@ -42,7 +42,7 @@ class RenderedTimeComponent extends TimerComponent {
|
||||
textConfig.render(
|
||||
canvas,
|
||||
'Elapsed time: ${timer.current}',
|
||||
Position(10, 150),
|
||||
Vector2(10, 150),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -90,8 +90,8 @@ class MyGame extends Game with TapDetector {
|
||||
textConfig.render(
|
||||
canvas,
|
||||
'Countdown: ${countdown.current}',
|
||||
Position(10, 100),
|
||||
Vector2(10, 100),
|
||||
);
|
||||
textConfig.render(canvas, 'Elapsed time: $elapsedSecs', Position(10, 150));
|
||||
textConfig.render(canvas, 'Elapsed time: $elapsedSecs', Vector2(10, 150));
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,9 +58,9 @@ __Countdown example:__
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/text_config.dart';
|
||||
import 'package:flame/time.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
|
||||
class MyGame extends Game {
|
||||
final TextConfig textConfig = TextConfig(color: const Color(0xFFFFFFFF));
|
||||
@ -81,7 +81,7 @@ class MyGame extends Game {
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
textConfig.render(canvas, "Countdown: ${countdown.current.toString()}",
|
||||
Position(10, 100));
|
||||
Vector2(10, 100));
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,9 +93,9 @@ __Interval example:__
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/text_config.dart';
|
||||
import 'package:flame/time.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
|
||||
class MyGame extends Game {
|
||||
final TextConfig textConfig = TextConfig(color: const Color(0xFFFFFFFF));
|
||||
@ -117,7 +117,7 @@ class MyGame extends Game {
|
||||
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
textConfig.render(canvas, "Elapsed time: $elapsedSecs", Position(10, 150));
|
||||
textConfig.render(canvas, "Elapsed time: $elapsedSecs", Vector2(10, 150));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,25 +1,25 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'position.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
class Anchor {
|
||||
static const Anchor topLeft = Anchor(Offset(0.0, 0.0));
|
||||
static const Anchor topCenter = Anchor(Offset(0.5, 0.0));
|
||||
static const Anchor topRight = Anchor(Offset(1.0, 0.0));
|
||||
static const Anchor centerLeft = Anchor(Offset(0.0, 0.5));
|
||||
static const Anchor center = Anchor(Offset(0.5, 0.5));
|
||||
static const Anchor centerRight = Anchor(Offset(1.0, 0.5));
|
||||
static const Anchor bottomLeft = Anchor(Offset(0.0, 1.0));
|
||||
static const Anchor bottomCenter = Anchor(Offset(0.5, 1.0));
|
||||
static const Anchor bottomRight = Anchor(Offset(1.0, 1.0));
|
||||
static const Anchor topLeft = Anchor(0.0, 0.0);
|
||||
static const Anchor topCenter = Anchor(0.5, 0.0);
|
||||
static const Anchor topRight = Anchor(1.0, 0.0);
|
||||
static const Anchor centerLeft = Anchor(0.0, 0.5);
|
||||
static const Anchor center = Anchor(0.5, 0.5);
|
||||
static const Anchor centerRight = Anchor(1.0, 0.5);
|
||||
static const Anchor bottomLeft = Anchor(0.0, 1.0);
|
||||
static const Anchor bottomCenter = Anchor(0.5, 1.0);
|
||||
static const Anchor bottomRight = Anchor(1.0, 1.0);
|
||||
|
||||
final Offset relativePosition;
|
||||
final double x;
|
||||
final double y;
|
||||
|
||||
const Anchor(this.relativePosition);
|
||||
Vector2 get relativePosition => Vector2(x, y);
|
||||
|
||||
Position translate(Position p, Position size) {
|
||||
return p.clone().minus(
|
||||
Position(size.x * relativePosition.dx, size.y * relativePosition.dy),
|
||||
);
|
||||
const Anchor(this.x, this.y);
|
||||
|
||||
Vector2 translate(Vector2 p, Vector2 size) {
|
||||
return p - size.clone()
|
||||
..multiply(relativePosition);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
/// This represents a Component for your game.
|
||||
///
|
||||
@ -22,7 +23,7 @@ abstract class Component {
|
||||
///
|
||||
/// It receives the new size.
|
||||
/// You can use the [Resizable] mixin if you want an implementation of this hook that keeps track of the current size.
|
||||
void resize(Size size) {}
|
||||
void resize(Vector2 size) {}
|
||||
|
||||
/// Whether this component has been loaded yet. If not loaded, [BaseGame] will not try to render it.
|
||||
///
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:box2d_flame/box2d.dart';
|
||||
import 'package:flame/components/joystick/joystick_component.dart';
|
||||
import 'package:flame/components/joystick/joystick_events.dart';
|
||||
import 'package:flame/gestures.dart';
|
||||
import 'package:flame/sprite.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import '../../position.dart';
|
||||
import '../../vector.dart';
|
||||
|
||||
enum JoystickActionAlign { TOP_LEFT, BOTTOM_LEFT, TOP_RIGHT, BOTTOM_RIGHT }
|
||||
|
||||
@ -58,7 +61,7 @@ class JoystickAction {
|
||||
_tileSize = _sizeBackgroundDirection / 2;
|
||||
}
|
||||
|
||||
void initialize(Size _screenSize, JoystickController joystickController) {
|
||||
void initialize(Vector2 _screenSize, JoystickController joystickController) {
|
||||
_joystickController = joystickController;
|
||||
final double radius = size / 2;
|
||||
double dx = 0, dy = 0;
|
||||
@ -69,15 +72,15 @@ class JoystickAction {
|
||||
break;
|
||||
case JoystickActionAlign.BOTTOM_LEFT:
|
||||
dx = margin.left + radius;
|
||||
dy = _screenSize.height - (margin.bottom + radius);
|
||||
dy = _screenSize.y - (margin.bottom + radius);
|
||||
break;
|
||||
case JoystickActionAlign.TOP_RIGHT:
|
||||
dx = _screenSize.width - (margin.right + radius);
|
||||
dx = _screenSize.x - (margin.right + radius);
|
||||
dy = margin.top + radius;
|
||||
break;
|
||||
case JoystickActionAlign.BOTTOM_RIGHT:
|
||||
dx = _screenSize.width - (margin.right + radius);
|
||||
dy = _screenSize.height - (margin.bottom + radius);
|
||||
dx = _screenSize.x - (margin.right + radius);
|
||||
dy = _screenSize.y - (margin.bottom + radius);
|
||||
break;
|
||||
}
|
||||
_rectAction = Rect.fromCircle(
|
||||
@ -153,9 +156,9 @@ class JoystickAction {
|
||||
|
||||
// Distance between the center of joystick background & drag position
|
||||
final centerPosition =
|
||||
Position.fromOffset(_rectBackgroundDirection.center);
|
||||
final dragPosition = Position.fromOffset(_dragPosition);
|
||||
double dist = centerPosition.distance(dragPosition);
|
||||
VectorUtil.fromOffset(_rectBackgroundDirection.center);
|
||||
final dragPosition = VectorUtil.fromOffset(_dragPosition);
|
||||
double dist = centerPosition.distanceTo(dragPosition);
|
||||
|
||||
// The maximum distance for the knob position the edge of
|
||||
// the background + half of its own size. The knob can wander in the
|
||||
|
||||
@ -7,6 +7,7 @@ import 'package:flame/components/joystick/joystick_events.dart';
|
||||
import 'package:flame/components/mixins/has_game_ref.dart';
|
||||
import 'package:flame/game/base_game.dart';
|
||||
import 'package:flame/gestures.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
|
||||
mixin JoystickListener {
|
||||
void joystickChangeDirectional(JoystickDirectionalEvent event);
|
||||
@ -69,7 +70,7 @@ class JoystickComponent extends JoystickController {
|
||||
}
|
||||
|
||||
@override
|
||||
void resize(Size size) {
|
||||
void resize(Vector2 size) {
|
||||
directional?.initialize(size, this);
|
||||
actions?.forEach((action) => action.initialize(size, this));
|
||||
super.resize(size);
|
||||
|
||||
@ -6,7 +6,7 @@ import 'package:flame/gestures.dart';
|
||||
import 'package:flame/sprite.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../position.dart';
|
||||
import '../../vector.dart';
|
||||
|
||||
class JoystickDirectional {
|
||||
final double size;
|
||||
@ -33,7 +33,7 @@ class JoystickDirectional {
|
||||
|
||||
JoystickController _joystickController;
|
||||
|
||||
Size _screenSize;
|
||||
Vector2 _screenSize;
|
||||
|
||||
DragEvent _currentDragEvent;
|
||||
|
||||
@ -65,11 +65,11 @@ class JoystickDirectional {
|
||||
_tileSize = size / 2;
|
||||
}
|
||||
|
||||
void initialize(Size _screenSize, JoystickController joystickController) {
|
||||
void initialize(Vector2 _screenSize, JoystickController joystickController) {
|
||||
this._screenSize = _screenSize;
|
||||
_joystickController = joystickController;
|
||||
final Offset osBackground =
|
||||
Offset(margin.left, _screenSize.height - margin.bottom);
|
||||
Offset(margin.left, _screenSize.y - margin.bottom);
|
||||
_backgroundRect = Rect.fromCircle(center: osBackground, radius: size / 2);
|
||||
|
||||
final Offset osKnob =
|
||||
@ -117,9 +117,9 @@ class JoystickDirectional {
|
||||
final double degrees = _radAngle * 180 / pi;
|
||||
|
||||
// Distance between the center of joystick background & drag position
|
||||
final centerPosition = Position.fromOffset(_backgroundRect.center);
|
||||
final dragPosition = Position.fromOffset(_dragPosition);
|
||||
double dist = centerPosition.distance(dragPosition);
|
||||
final centerPosition = VectorUtil.fromOffset(_backgroundRect.center);
|
||||
final dragPosition = VectorUtil.fromOffset(_dragPosition);
|
||||
double dist = centerPosition.distanceTo(dragPosition);
|
||||
|
||||
// The maximum distance for the knob position the edge of
|
||||
// the background + half of its own size. The knob can wander in the
|
||||
@ -186,8 +186,8 @@ class JoystickDirectional {
|
||||
|
||||
void _updateDirectionalRect(Offset position) {
|
||||
if (_screenSize != null &&
|
||||
(position.dx > _screenSize.width / 2 ||
|
||||
position.dy < _screenSize.height / 2 ||
|
||||
(position.dx > _screenSize.x / 2 ||
|
||||
position.dy < _screenSize.y / 2 ||
|
||||
isFixed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
/// Useful mixin to add to your components if you want to hold a reference to the current screen size.
|
||||
///
|
||||
/// This mixin implements the resize method in order to hold an updated reference to the current screen [size].
|
||||
/// Also, it updates its [children], if any.
|
||||
class Resizable {
|
||||
/// This is the current updated screen size.
|
||||
Size size;
|
||||
Vector2 size;
|
||||
|
||||
/// Implementation provided by this mixin to the resize hook.
|
||||
void resize(Size size) {
|
||||
void resize(Vector2 size) {
|
||||
this.size = size;
|
||||
resizableChildren().where((e) => e != null).forEach((e) => e.resize(size));
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../flame.dart';
|
||||
import 'position_component.dart';
|
||||
@ -37,7 +38,7 @@ class ParallaxLayer {
|
||||
Future<Image> future;
|
||||
|
||||
Image _image;
|
||||
Size _screenSize;
|
||||
Vector2 _screenSize;
|
||||
Rect _paintArea;
|
||||
Offset _scroll;
|
||||
Offset _imageSize;
|
||||
@ -51,7 +52,7 @@ class ParallaxLayer {
|
||||
|
||||
Offset currentOffset() => _scroll;
|
||||
|
||||
void resize(Size size) {
|
||||
void resize(Vector2 size) {
|
||||
if (!loaded()) {
|
||||
_screenSize = size;
|
||||
return;
|
||||
@ -60,9 +61,9 @@ class ParallaxLayer {
|
||||
double scale(LayerFill fill) {
|
||||
switch (fill) {
|
||||
case LayerFill.height:
|
||||
return _image.height / size.height;
|
||||
return _image.height / size.y;
|
||||
case LayerFill.width:
|
||||
return _image.width / size.width;
|
||||
return _image.width / size.x;
|
||||
default:
|
||||
return _scale;
|
||||
}
|
||||
@ -75,12 +76,12 @@ class ParallaxLayer {
|
||||
|
||||
// Number of images that can fit on the canvas plus one
|
||||
// to have something to scroll to without leaving canvas empty
|
||||
final countX = 1 + size.width / _imageSize.dx;
|
||||
final countY = 1 + size.height / _imageSize.dy;
|
||||
final countX = 1 + size.x / _imageSize.dx;
|
||||
final countY = 1 + size.y / _imageSize.dy;
|
||||
|
||||
// Percentage of the image size that will overflow
|
||||
final overflowX = (_imageSize.dx * countX - size.width) / _imageSize.dx;
|
||||
final overflowY = (_imageSize.dy * countY - size.height) / _imageSize.dy;
|
||||
final overflowX = (_imageSize.dx * countX - size.x) / _imageSize.dx;
|
||||
final overflowY = (_imageSize.dy * countY - size.y) / _imageSize.dy;
|
||||
|
||||
// Align image to correct side of the screen
|
||||
final alignment = parallaxImage.alignment;
|
||||
@ -175,7 +176,7 @@ class ParallaxComponent extends PositionComponent {
|
||||
|
||||
@mustCallSuper
|
||||
@override
|
||||
void resize(Size size) {
|
||||
void resize(Vector2 size) {
|
||||
super.resize(size);
|
||||
_layers.forEach((layer) => layer.resize(size));
|
||||
}
|
||||
|
||||
@ -4,11 +4,11 @@ import 'dart:math';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:ordered_set/comparing.dart';
|
||||
import 'package:ordered_set/ordered_set.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../anchor.dart';
|
||||
import '../effects/effects.dart';
|
||||
import '../game.dart';
|
||||
import '../position.dart';
|
||||
import '../text_config.dart';
|
||||
import 'component.dart';
|
||||
|
||||
@ -72,14 +72,14 @@ abstract class PositionComponent extends Component {
|
||||
|
||||
TextConfig get debugTextConfig => TextConfig(color: debugColor, fontSize: 12);
|
||||
|
||||
Position toPosition() => Position(x, y);
|
||||
void setByPosition(Position position) {
|
||||
Vector2 toPosition() => Vector2(x, y);
|
||||
void setByPosition(Vector2 position) {
|
||||
x = position.x;
|
||||
y = position.y;
|
||||
}
|
||||
|
||||
Position toSize() => Position(width, height);
|
||||
void setBySize(Position size) {
|
||||
Vector2 toSize() => Vector2(width, height);
|
||||
void setBySize(Vector2 size) {
|
||||
width = size.x;
|
||||
height = size.y;
|
||||
}
|
||||
@ -92,8 +92,8 @@ abstract class PositionComponent extends Component {
|
||||
/// 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.dx * width,
|
||||
y - anchor.relativePosition.dy * height,
|
||||
x - anchor.relativePosition.x * width,
|
||||
y - anchor.relativePosition.y * height,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
@ -101,8 +101,8 @@ abstract class PositionComponent extends Component {
|
||||
/// 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.dx * rect.width;
|
||||
y = rect.top + anchor.relativePosition.dy * rect.height;
|
||||
x = rect.left + anchor.relativePosition.x * rect.width;
|
||||
y = rect.top + anchor.relativePosition.y * rect.height;
|
||||
width = rect.width;
|
||||
height = rect.height;
|
||||
}
|
||||
@ -112,7 +112,7 @@ abstract class PositionComponent extends Component {
|
||||
}
|
||||
|
||||
double distance(PositionComponent c) {
|
||||
return c.toPosition().distance(toPosition());
|
||||
return c.toPosition().distanceTo(toPosition());
|
||||
}
|
||||
|
||||
void renderDebugMode(Canvas canvas) {
|
||||
@ -120,7 +120,7 @@ abstract class PositionComponent extends Component {
|
||||
debugTextConfig.render(
|
||||
canvas,
|
||||
'x: ${x.toStringAsFixed(2)} y:${y.toStringAsFixed(2)}',
|
||||
Position(-50, -15));
|
||||
Vector2(-50, -15));
|
||||
|
||||
final Rect rect = toRect();
|
||||
final dx = rect.right;
|
||||
@ -128,15 +128,15 @@ abstract class PositionComponent extends Component {
|
||||
debugTextConfig.render(
|
||||
canvas,
|
||||
'x:${dx.toStringAsFixed(2)} y:${dy.toStringAsFixed(2)}',
|
||||
Position(width - 50, height));
|
||||
Vector2(width - 50, height));
|
||||
}
|
||||
|
||||
void _prepareCanvas(Canvas canvas) {
|
||||
canvas.translate(x, y);
|
||||
|
||||
canvas.rotate(angle);
|
||||
final double dx = -anchor.relativePosition.dx * width;
|
||||
final double dy = -anchor.relativePosition.dy * height;
|
||||
final double dx = -anchor.relativePosition.x * width;
|
||||
final double dy = -anchor.relativePosition.y * height;
|
||||
canvas.translate(dx, dy);
|
||||
|
||||
// Handle inverted rendering by moving center and flipping.
|
||||
@ -193,7 +193,7 @@ abstract class PositionComponent extends Component {
|
||||
|
||||
@mustCallSuper
|
||||
@override
|
||||
void resize(Size size) {
|
||||
void resize(Vector2 size) {
|
||||
super.resize(size);
|
||||
_children.forEach((child) => child.resize(size));
|
||||
}
|
||||
|
||||
@ -3,9 +3,9 @@ import 'dart:math' as math;
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/widgets.dart' as widgets;
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../palette.dart';
|
||||
import '../position.dart';
|
||||
import '../text_config.dart';
|
||||
import 'mixins/resizable.dart';
|
||||
import 'position_component.dart';
|
||||
@ -28,7 +28,7 @@ class TextBoxComponent extends PositionComponent with Resizable {
|
||||
static final Paint _imagePaint = BasicPalette.white.paint
|
||||
..filterQuality = FilterQuality.high;
|
||||
|
||||
Position p = Position.empty();
|
||||
Vector2 p = Vector2.zero();
|
||||
|
||||
String _text;
|
||||
TextConfig _config;
|
||||
|
||||
@ -2,9 +2,9 @@ import 'dart:math';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../components/position_component.dart';
|
||||
import '../position.dart';
|
||||
|
||||
export './move_effect.dart';
|
||||
export './rotate_effect.dart';
|
||||
@ -31,9 +31,9 @@ abstract class PositionComponentEffect {
|
||||
int curveDirection = 1;
|
||||
|
||||
/// Used to be able to determine the end state of a sequence of effects
|
||||
Position endPosition;
|
||||
Vector2 endPosition;
|
||||
double endAngle;
|
||||
Position endSize;
|
||||
Vector2 endSize;
|
||||
|
||||
/// If the effect is alternating the travel time is double the normal
|
||||
/// travel time
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import 'dart:math';
|
||||
|
||||
import './effects.dart';
|
||||
import '../position.dart';
|
||||
|
||||
double _direction(double p, double d) => (p - d).sign;
|
||||
double _distance(double a, double b) => (a - b).abs();
|
||||
|
||||
class MoveEffect extends PositionComponentEffect {
|
||||
Position destination;
|
||||
Vector2 destination;
|
||||
double speed;
|
||||
Curve curve;
|
||||
|
||||
|
||||
@ -1,23 +1,22 @@
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import 'dart:ui';
|
||||
import 'dart:math';
|
||||
|
||||
import './effects.dart';
|
||||
import '../position.dart';
|
||||
|
||||
double _direction(double p, double d) => (p - d).sign;
|
||||
double _size(double a, double b) => (a - b).abs();
|
||||
|
||||
class ScaleEffect extends PositionComponentEffect {
|
||||
Size size;
|
||||
Vector2 size;
|
||||
double speed;
|
||||
Curve curve;
|
||||
|
||||
Size _original;
|
||||
Size _diff;
|
||||
final Position _dir = Position.empty();
|
||||
Vector2 _original;
|
||||
Vector2 _diff;
|
||||
final Vector2 _dir = Vector2.zero();
|
||||
|
||||
ScaleEffect({
|
||||
@required this.size,
|
||||
@ -32,19 +31,19 @@ class ScaleEffect extends PositionComponentEffect {
|
||||
void initialize(_comp) {
|
||||
super.initialize(_comp);
|
||||
if (!isAlternating) {
|
||||
endSize = Position.fromSize(size);
|
||||
endSize = size.clone();
|
||||
}
|
||||
|
||||
_original = Size(component.width, component.height);
|
||||
_diff = Size(
|
||||
_size(_original.width, size.width),
|
||||
_size(_original.height, size.height),
|
||||
_original = component.toSize();
|
||||
_diff = Vector2(
|
||||
_size(_original.x, size.x),
|
||||
_size(_original.y, size.y),
|
||||
);
|
||||
|
||||
_dir.x = _direction(size.width, _original.width);
|
||||
_dir.y = _direction(size.height, _original.height);
|
||||
_dir.x = _direction(size.x, _original.x);
|
||||
_dir.y = _direction(size.y, _original.y);
|
||||
|
||||
final scaleDistance = sqrt(pow(_diff.width, 2) + pow(_diff.height, 2));
|
||||
final scaleDistance = sqrt(pow(_diff.x, 2) + pow(_diff.y, 2));
|
||||
travelTime = scaleDistance / speed;
|
||||
}
|
||||
|
||||
@ -53,7 +52,7 @@ class ScaleEffect extends PositionComponentEffect {
|
||||
super.update(dt);
|
||||
final double c = curve?.transform(percentage) ?? 1.0;
|
||||
|
||||
component.width = _original.width + _diff.width * c * _dir.x;
|
||||
component.height = _original.height + _diff.height * c * _dir.y;
|
||||
component.width = _original.x + _diff.x * c * _dir.x;
|
||||
component.height = _original.y + _diff.y * c * _dir.y;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,18 +1,17 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flame/components/composed_component.dart';
|
||||
import 'package:flame/fps_counter.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart' hide WidgetBuilder;
|
||||
import 'package:ordered_set/comparing.dart';
|
||||
import 'package:ordered_set/ordered_set.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../components/component.dart';
|
||||
import '../components/mixins/has_game_ref.dart';
|
||||
import '../components/mixins/tapable.dart';
|
||||
import '../components/position_component.dart';
|
||||
import '../position.dart';
|
||||
import 'game.dart';
|
||||
|
||||
/// This is a more complete and opinionated implementation of Game.
|
||||
@ -32,10 +31,10 @@ class BaseGame extends Game with FPSCounter {
|
||||
final List<Component> _removeLater = [];
|
||||
|
||||
/// Current screen size, updated every resize via the [resize] method hook
|
||||
Size size;
|
||||
Vector2 size;
|
||||
|
||||
/// Camera position; every non-HUD component is translated so that the camera position is the top-left corner of the screen.
|
||||
Position camera = Position.empty();
|
||||
Vector2 camera = Vector2.zero();
|
||||
|
||||
/// This method is called for every component added, both via [add] and [addLater] methods.
|
||||
///
|
||||
@ -139,7 +138,7 @@ class BaseGame extends Game with FPSCounter {
|
||||
/// You can override it further to add more custom behaviour, but you should seriously consider calling the super implementation as well.
|
||||
@override
|
||||
@mustCallSuper
|
||||
void resize(Size size) {
|
||||
void resize(Vector2 size) {
|
||||
this.size = size;
|
||||
components.forEach((c) => c.resize(size));
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart' hide WidgetBuilder;
|
||||
|
||||
import '../position.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import 'game_render_box.dart';
|
||||
import 'game.dart';
|
||||
@ -14,7 +13,7 @@ import 'game.dart';
|
||||
/// You can bind Gesture Recognizers immediately around this to add controls to your widgets, with easy coordinate conversions.
|
||||
class EmbeddedGameWidget extends LeafRenderObjectWidget {
|
||||
final Game game;
|
||||
final Position size;
|
||||
final Vector2 size;
|
||||
|
||||
EmbeddedGameWidget(this.game, {this.size});
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import 'package:flutter/services.dart';
|
||||
|
||||
import '../keyboard.dart';
|
||||
|
||||
import '../vector.dart';
|
||||
import 'widget_builder.dart';
|
||||
|
||||
/// Represents a generic game.
|
||||
@ -35,7 +36,7 @@ abstract class Game {
|
||||
/// This is the resize hook; every time the game widget is resized, this hook is called.
|
||||
///
|
||||
/// The default implementation does nothing; override to use the hook.
|
||||
void resize(Size size) {}
|
||||
void resize(Vector2 size) {}
|
||||
|
||||
/// This is the lifecycle state change hook; every time the game is resumed, paused or suspended, this is called.
|
||||
///
|
||||
|
||||
@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/widgets.dart' hide WidgetBuilder;
|
||||
|
||||
import '../vector.dart';
|
||||
import 'game_loop.dart';
|
||||
import 'game.dart';
|
||||
|
||||
@ -23,7 +24,7 @@ class GameRenderBox extends RenderBox with WidgetsBindingObserver {
|
||||
@override
|
||||
void performResize() {
|
||||
super.performResize();
|
||||
game.resize(constraints.biggest);
|
||||
game.resize(VectorUtil.fromSize(constraints.biggest));
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../sprite_animation.dart';
|
||||
import '../particle.dart';
|
||||
import '../position.dart';
|
||||
|
||||
class SpriteAnimationParticle extends Particle {
|
||||
final SpriteAnimation animation;
|
||||
final Position size;
|
||||
final Vector2 size;
|
||||
final Paint overridePaint;
|
||||
final bool alignAnimationTime;
|
||||
|
||||
@ -36,7 +36,7 @@ class SpriteAnimationParticle extends Particle {
|
||||
void render(Canvas canvas) {
|
||||
animation.getSprite().renderCentered(
|
||||
canvas,
|
||||
Position.empty(),
|
||||
Vector2.zero(),
|
||||
overridePaint: overridePaint,
|
||||
size: size,
|
||||
);
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../particle.dart';
|
||||
import '../position.dart';
|
||||
import '../components/component.dart';
|
||||
|
||||
class ComponentParticle extends Particle {
|
||||
final Component component;
|
||||
final Position size;
|
||||
final Vector2 size;
|
||||
final Paint overridePaint;
|
||||
|
||||
ComponentParticle({
|
||||
|
||||
@ -3,6 +3,7 @@ import 'dart:ui';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../particle.dart';
|
||||
import '../vector.dart';
|
||||
|
||||
/// A [Particle] which renders given [Image] on a [Canvas]
|
||||
/// image is centered. If any other behavior is needed, consider
|
||||
@ -16,13 +17,13 @@ class ImageParticle extends Particle {
|
||||
|
||||
ImageParticle({
|
||||
@required this.image,
|
||||
Size size,
|
||||
Vector2 size,
|
||||
double lifespan,
|
||||
}) : super(lifespan: lifespan) {
|
||||
final srcWidth = image.width.toDouble();
|
||||
final srcHeight = image.height.toDouble();
|
||||
final destWidth = size?.width ?? srcWidth;
|
||||
final destHeight = size?.height ?? srcHeight;
|
||||
final destWidth = size?.x ?? srcWidth;
|
||||
final destHeight = size?.y ?? srcHeight;
|
||||
|
||||
src = Rect.fromLTWH(0, 0, srcWidth, srcHeight);
|
||||
dest =
|
||||
|
||||
@ -8,7 +8,7 @@ import '../components/mixins/single_child_particle.dart';
|
||||
import '../particles/curved_particle.dart';
|
||||
|
||||
/// Statically offset given child [Particle] by given [Offset]
|
||||
/// If you're loking to move the child, consider [MovingParticle]
|
||||
/// If you're looking to move the child, consider [MovingParticle]
|
||||
class MovingParticle extends CurvedParticle with SingleChildParticle {
|
||||
@override
|
||||
Particle child;
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../particle.dart';
|
||||
import '../position.dart';
|
||||
import '../sprite.dart';
|
||||
|
||||
class SpriteParticle extends Particle {
|
||||
final Sprite sprite;
|
||||
final Position size;
|
||||
final Vector2 size;
|
||||
final Paint overridePaint;
|
||||
|
||||
SpriteParticle({
|
||||
@ -24,7 +24,7 @@ class SpriteParticle extends Particle {
|
||||
void render(Canvas canvas) {
|
||||
sprite.renderCentered(
|
||||
canvas,
|
||||
Position.empty(),
|
||||
Vector2.zero(),
|
||||
overridePaint: overridePaint,
|
||||
size: size,
|
||||
);
|
||||
|
||||
@ -1,226 +0,0 @@
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:box2d_flame/box2d.dart' as b2d;
|
||||
|
||||
/// An ordered pair representation (point, position, offset).
|
||||
///
|
||||
/// It differs from the default implementations provided (math.Point and ui.Offset) as it's mutable.
|
||||
/// Also, it offers helpful converters and a some useful methods for manipulation.
|
||||
/// It always uses double values to store the coordinates.
|
||||
class Position {
|
||||
/// Coordinates
|
||||
double x, y;
|
||||
|
||||
/// Basic constructor
|
||||
Position(this.x, this.y);
|
||||
|
||||
/// Creates a point at the origin
|
||||
Position.empty() : this(0.0, 0.0);
|
||||
|
||||
/// Creates converting integers to double.
|
||||
///
|
||||
/// Internal representation is still using double, the conversion is made in the constructor only.
|
||||
Position.fromInts(int x, int y) : this(x.toDouble(), y.toDouble());
|
||||
|
||||
/// Creates using an [ui.Offset]
|
||||
Position.fromOffset(ui.Offset offset) : this(offset.dx, offset.dy);
|
||||
|
||||
/// Creates using an [ui.Size]
|
||||
Position.fromSize(ui.Size size) : this(size.width, size.height);
|
||||
|
||||
/// Creates using an [math.Point]
|
||||
Position.fromPoint(math.Point point) : this(point.x, point.y);
|
||||
|
||||
/// Creates using another [Position]; i.e., clones this position.
|
||||
///
|
||||
/// This is useful because this class is mutable, so beware of mutability issues.
|
||||
Position.fromPosition(Position position) : this(position.x, position.y);
|
||||
|
||||
/// Creates using a [b2d.Vector2]
|
||||
Position.fromVector(b2d.Vector2 vector) : this(vector.x, vector.y);
|
||||
|
||||
/// Adds the coordinates from another vector.
|
||||
///
|
||||
/// This method changes `this` instance and returns itself.
|
||||
Position add(Position other) {
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Substracts the coordinates from another vector.
|
||||
///
|
||||
/// This method changes `this` instance and returns itself.
|
||||
Position minus(Position other) {
|
||||
return add(other.clone().opposite());
|
||||
}
|
||||
|
||||
Position times(double scalar) {
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
return this;
|
||||
}
|
||||
|
||||
Position opposite() {
|
||||
return times(-1.0);
|
||||
}
|
||||
|
||||
Position div(double scalar) {
|
||||
return times(1 / scalar);
|
||||
}
|
||||
|
||||
double dotProduct(Position p) {
|
||||
return x * p.x + y * p.y;
|
||||
}
|
||||
|
||||
/// The length (or magnitude) of this vector.
|
||||
double length() {
|
||||
return math.sqrt(dotProduct(this));
|
||||
}
|
||||
|
||||
/// Rotate around origin; [angle] in radians.
|
||||
Position rotate(double angle) {
|
||||
final double nx = math.cos(angle) * x - math.sin(angle) * y;
|
||||
final double ny = math.sin(angle) * x + math.cos(angle) * y;
|
||||
x = nx;
|
||||
y = ny;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Rotate around origin; [angle] in degrees.
|
||||
Position rotateDeg(double angle) {
|
||||
return rotate(angle * math.pi / 180);
|
||||
}
|
||||
|
||||
/// Change current rotation by delta angle; [angle] in radians.
|
||||
Position rotateDelta(double radians) {
|
||||
return rotate(angle() + radians);
|
||||
}
|
||||
|
||||
/// Change current rotation by delta angle; [angle] in degrees.
|
||||
Position rotateDeltaDeg(double degrees) {
|
||||
return rotateDeg(angleDeg() + degrees);
|
||||
}
|
||||
|
||||
/// Returns the angle of this vector from origin in radians.
|
||||
double angle() {
|
||||
return math.atan2(y, x);
|
||||
}
|
||||
|
||||
/// Returns the angle of this vector from origin in degrees.
|
||||
double angleDeg() {
|
||||
return angle() * 180 / math.pi;
|
||||
}
|
||||
|
||||
/// Returns the angle of this vector from another [Position] in radians.
|
||||
double angleFrom(Position other) {
|
||||
// Technically the origin is not a vector so you cannot find the angle between
|
||||
// itself and another vector so just default to calculating the angle between
|
||||
// the non-origin point and the origin to avoid division by zero
|
||||
if (x == 0 && y == 0) {
|
||||
return other.angle();
|
||||
}
|
||||
if (other.x == 0 && other.y == 0) {
|
||||
return angle();
|
||||
}
|
||||
|
||||
return math.acos(dotProduct(other) / (length() * other.length()));
|
||||
}
|
||||
|
||||
/// Returns the angle of this vector from another [Position] in degrees.
|
||||
double angleFromDeg(Position other) {
|
||||
return angleFrom(other) * 180 / math.pi;
|
||||
}
|
||||
|
||||
double distance(Position other) {
|
||||
return clone().minus(other).length();
|
||||
}
|
||||
|
||||
/// Changes the [length] of this vector to the one provided, without chaning direction.
|
||||
///
|
||||
/// If you try to scale the zero (empty) vector, it will remain unchanged, and no error will be thrown.
|
||||
Position scaleTo(double newLength) {
|
||||
final l = length();
|
||||
if (l == 0) {
|
||||
return this;
|
||||
}
|
||||
return times(newLength.abs() / l);
|
||||
}
|
||||
|
||||
/// Normalizes this vector, without changing direction.
|
||||
Position normalize() {
|
||||
return scaleTo(1.0);
|
||||
}
|
||||
|
||||
/// Limits the [length] of this vector to the one provided, without changing direction.
|
||||
///
|
||||
/// If this vector's length is bigger than [maxLength], it becomes [maxLength]; otherwise, nothing changes.
|
||||
Position limit(double maxLength) {
|
||||
final newLength = length().clamp(0.0, maxLength.abs());
|
||||
return scaleTo(newLength);
|
||||
}
|
||||
|
||||
ui.Offset toOffset() {
|
||||
return ui.Offset(x, y);
|
||||
}
|
||||
|
||||
ui.Size toSize() {
|
||||
return ui.Size(x, y);
|
||||
}
|
||||
|
||||
math.Point toPoint() {
|
||||
return math.Point(x, y);
|
||||
}
|
||||
|
||||
b2d.Vector2 toVector() {
|
||||
return b2d.Vector2(x, y);
|
||||
}
|
||||
|
||||
Position clone() {
|
||||
return Position.fromPosition(this);
|
||||
}
|
||||
|
||||
bool equals(Position p) {
|
||||
return p.x == x && p.y == y;
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(other) {
|
||||
return other is Position && equals(other);
|
||||
}
|
||||
|
||||
/// Negate.
|
||||
Position operator -() => clone()..opposite();
|
||||
|
||||
/// Subtract two vectors.
|
||||
Position operator -(Position other) => clone()..minus(other);
|
||||
|
||||
/// Add two vectors.
|
||||
Position operator +(Position other) => clone()..add(other);
|
||||
|
||||
/// Scale.
|
||||
Position operator /(double scale) => clone()..div(scale);
|
||||
|
||||
/// Scale.
|
||||
Position operator *(double scale) => clone()..times(scale);
|
||||
|
||||
@override
|
||||
int get hashCode => toString().hashCode;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '($x, $y)';
|
||||
}
|
||||
|
||||
static ui.Rect rectFrom(Position topLeft, Position size) {
|
||||
return ui.Rect.fromLTWH(topLeft.x, topLeft.y, size.x, size.y);
|
||||
}
|
||||
|
||||
static ui.Rect bounds(List<Position> pts) {
|
||||
final double minx = pts.map((e) => e.x).reduce(math.min);
|
||||
final double maxx = pts.map((e) => e.x).reduce(math.max);
|
||||
final double miny = pts.map((e) => e.y).reduce(math.min);
|
||||
final double maxy = pts.map((e) => e.y).reduce(math.max);
|
||||
return ui.Rect.fromPoints(ui.Offset(minx, miny), ui.Offset(maxx, maxy));
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,12 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import 'flame.dart';
|
||||
import 'position.dart';
|
||||
import 'palette.dart';
|
||||
import 'vector.dart';
|
||||
|
||||
class Sprite {
|
||||
Paint paint = BasicPalette.white.paint;
|
||||
@ -62,15 +65,15 @@ class Sprite {
|
||||
|
||||
double get _imageHeight => image.height.toDouble();
|
||||
|
||||
Position get originalSize {
|
||||
Vector2 get originalSize {
|
||||
if (!loaded()) {
|
||||
return null;
|
||||
}
|
||||
return Position(_imageWidth, _imageHeight);
|
||||
return Vector2(_imageWidth, _imageHeight);
|
||||
}
|
||||
|
||||
Position get size {
|
||||
return Position(src.width, src.height);
|
||||
Vector2 get size {
|
||||
return Vector2(src.width, src.height);
|
||||
}
|
||||
|
||||
/// Renders this Sprite on the position [p], scaled by the [scale] factor provided.
|
||||
@ -78,22 +81,21 @@ class Sprite {
|
||||
/// It renders with src size multiplied by [scale] in both directions.
|
||||
/// Anchor is on top left as default.
|
||||
/// If not loaded, does nothing.
|
||||
void renderScaled(Canvas canvas, Position p,
|
||||
void renderScaled(Canvas canvas, Vector2 p,
|
||||
{double scale = 1.0, Paint overridePaint}) {
|
||||
if (!loaded()) {
|
||||
return;
|
||||
}
|
||||
renderPosition(canvas, p,
|
||||
size: size.times(scale), overridePaint: overridePaint);
|
||||
renderPosition(canvas, p, size: size * scale, overridePaint: overridePaint);
|
||||
}
|
||||
|
||||
void renderPosition(Canvas canvas, Position p,
|
||||
{Position size, Paint overridePaint}) {
|
||||
void renderPosition(Canvas canvas, Vector2 p,
|
||||
{Vector2 size, Paint overridePaint}) {
|
||||
if (!loaded()) {
|
||||
return;
|
||||
}
|
||||
size ??= this.size;
|
||||
renderRect(canvas, Position.rectFrom(p, size),
|
||||
renderRect(canvas, VectorUtil.rectFrom(p, size),
|
||||
overridePaint: overridePaint);
|
||||
}
|
||||
|
||||
@ -112,8 +114,8 @@ class Sprite {
|
||||
///
|
||||
/// If [size] is not provided, the original size of the src image is used.
|
||||
/// If the asset is not yet loaded, it does nothing.
|
||||
void renderCentered(Canvas canvas, Position p,
|
||||
{Position size, Paint overridePaint}) {
|
||||
void renderCentered(Canvas canvas, Vector2 p,
|
||||
{Vector2 size, Paint overridePaint}) {
|
||||
if (!loaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import 'dart:ui';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'flame.dart';
|
||||
import 'vector.dart';
|
||||
|
||||
/// sprite atlas with an image and a set of rects and transforms
|
||||
class SpriteBatch {
|
||||
@ -27,7 +28,7 @@ class SpriteBatch {
|
||||
|
||||
int get height => atlas.height;
|
||||
|
||||
Size get size => Size(width.toDouble(), height.toDouble());
|
||||
Vector2 get size => Vector2(width.toDouble(), height.toDouble());
|
||||
|
||||
void addTransform({
|
||||
@required Rect rect,
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import 'dart:ui';
|
||||
import 'package:flame/components/text_component.dart';
|
||||
import 'package:flutter/material.dart' as material;
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import 'position.dart';
|
||||
import 'anchor.dart';
|
||||
import 'memory_cache.dart';
|
||||
import 'vector.dart';
|
||||
|
||||
/// A Text Config contains all typographical information required to render texts; i.e., font size and color, family, etc.
|
||||
///
|
||||
@ -76,12 +77,12 @@ class TextConfig {
|
||||
///
|
||||
/// const TextConfig config = TextConfig(fontSize: 48.0, fontFamily: 'Awesome Font');
|
||||
/// config.render(c, Offset(size.width - 10, size.height - 10, anchor: Anchor.bottomRight);
|
||||
void render(Canvas canvas, String text, Position p,
|
||||
void render(Canvas canvas, String text, Vector2 p,
|
||||
{Anchor anchor = Anchor.topLeft}) {
|
||||
final material.TextPainter tp = toTextPainter(text);
|
||||
final Position translatedPosition =
|
||||
anchor.translate(p, Position.fromSize(tp.size));
|
||||
tp.paint(canvas, translatedPosition.toOffset());
|
||||
final Vector2 translatedPosition =
|
||||
anchor.translate(p, VectorUtil.fromSize(tp.size));
|
||||
tp.paint(canvas, VectorUtil.toOffset(translatedPosition));
|
||||
}
|
||||
|
||||
/// Returns a [material.TextPainter] that allows for text rendering and size measuring.
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'position.dart';
|
||||
|
||||
/// Some utilities that did not fit anywhere else.
|
||||
///
|
||||
/// To use this class, access it via [Flame.util].
|
||||
@ -98,20 +97,21 @@ class Util {
|
||||
///
|
||||
/// A best practice would be to implement there resize hooks on your game and components and don't use this at all.
|
||||
/// Make sure your components are able to render and update themselves for any possible screen size.
|
||||
Future<Size> initialDimensions() async {
|
||||
Future<Vector2> initialDimensions() async {
|
||||
// https://github.com/flutter/flutter/issues/5259
|
||||
// "In release mode we start off at 0x0 but we don't in debug mode"
|
||||
return await Future<Size>(() {
|
||||
return await Future<Vector2>(() {
|
||||
if (window.physicalSize.isEmpty) {
|
||||
final completer = Completer<Size>();
|
||||
final completer = Completer<Vector2>();
|
||||
window.onMetricsChanged = () {
|
||||
if (!window.physicalSize.isEmpty && !completer.isCompleted) {
|
||||
completer.complete(window.physicalSize / window.devicePixelRatio);
|
||||
completer.complete(VectorUtil.fromSize(
|
||||
window.physicalSize / window.devicePixelRatio));
|
||||
}
|
||||
};
|
||||
return completer.future;
|
||||
}
|
||||
return window.physicalSize / window.devicePixelRatio;
|
||||
return VectorUtil.fromSize(window.physicalSize / window.devicePixelRatio);
|
||||
});
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ class Util {
|
||||
///
|
||||
/// Some render methods don't allow to pass a offset.
|
||||
/// This method translate the canvas, draw what you want, and then translate back.
|
||||
void drawWhere(Canvas c, Position p, void Function(Canvas) fn) {
|
||||
void drawWhere(Canvas c, Vector2 p, void Function(Canvas) fn) {
|
||||
c.translate(p.x, p.y);
|
||||
fn(c);
|
||||
c.translate(-p.x, -p.y);
|
||||
|
||||
80
lib/vector.dart
Normal file
80
lib/vector.dart
Normal file
@ -0,0 +1,80 @@
|
||||
library flame.vector_math;
|
||||
|
||||
export 'package:vector_math/vector_math_64.dart' show Vector2;
|
||||
|
||||
import 'dart:math' as math;
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
class VectorUtil {
|
||||
/// Creates converting integers to double.
|
||||
///
|
||||
/// Internal representation is still using double, the conversion is made in the constructor only.
|
||||
static Vector2 fromInts(int x, int y) => Vector2(x.toDouble(), y.toDouble());
|
||||
|
||||
/// Creates using an [ui.Offset]
|
||||
static Vector2 fromOffset(ui.Offset offset) => Vector2(offset.dx, offset.dy);
|
||||
|
||||
/// Creates using an [ui.Size]
|
||||
static Vector2 fromSize(ui.Size size) => Vector2(size.width, size.height);
|
||||
|
||||
/// Creates using an [math.Point]
|
||||
static Vector2 fromPoint(math.Point point) => Vector2(point.x, point.y);
|
||||
|
||||
static ui.Offset toOffset(Vector2 v) => ui.Offset(v.x, v.y);
|
||||
|
||||
static ui.Size toSize(Vector2 v) => ui.Size(v.x, v.y);
|
||||
|
||||
static math.Point toPoint(Vector2 v) => math.Point(v.x, v.y);
|
||||
|
||||
// Used once in sprite
|
||||
static ui.Rect rectFrom(Vector2 topLeft, Vector2 size) {
|
||||
return ui.Rect.fromLTWH(topLeft.x, topLeft.y, size.x, size.y);
|
||||
}
|
||||
|
||||
static ui.Rect bounds(List<Vector2> pts) {
|
||||
final double minx = pts.map((e) => e.x).reduce(math.min);
|
||||
final double maxx = pts.map((e) => e.x).reduce(math.max);
|
||||
final double miny = pts.map((e) => e.y).reduce(math.min);
|
||||
final double maxy = pts.map((e) => e.y).reduce(math.max);
|
||||
return ui.Rect.fromPoints(ui.Offset(minx, miny), ui.Offset(maxx, maxy));
|
||||
}
|
||||
|
||||
/// Linearly interpolate between two vectors.
|
||||
static Vector2 lerp(Vector2 a, Vector2 b, double t) {
|
||||
return a + (b - a) * t;
|
||||
}
|
||||
|
||||
static void rotate(Vector2 v, double angle) {
|
||||
final double sin = math.sin(angle);
|
||||
final double cos = math.cos(angle);
|
||||
v.setValues(v.x * cos - v.y * sin, v.x * sin + v.y * cos);
|
||||
}
|
||||
|
||||
static Vector2 rotated(Vector2 v, double angle) {
|
||||
final double sin = math.sin(angle);
|
||||
final double cos = math.cos(angle);
|
||||
return Vector2(v.x * cos - v.y * sin, v.x * sin + v.y * cos);
|
||||
}
|
||||
|
||||
/// Returns a new vector with the [length] scaled to [newLength], without changing direction.
|
||||
///
|
||||
/// If you try to scale the zero (empty) vector, it will remain unchanged, and no error will be thrown.
|
||||
static Vector2 scaledTo(Vector2 v, double newLength) {
|
||||
final l = v.length;
|
||||
if (l == 0) {
|
||||
return v;
|
||||
}
|
||||
return v * (newLength.abs() / l);
|
||||
}
|
||||
|
||||
/// Changes the [length] of the vector to the length provided, without changing direction.
|
||||
///
|
||||
/// If you try to scale the zero (empty) vector, it will remain unchanged, and no error will be thrown.
|
||||
static void scaleTo(Vector2 v, double newLength) {
|
||||
final l = v.length;
|
||||
if (l != 0) {
|
||||
v.setFrom(v * (newLength.abs() / l));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -50,12 +50,12 @@ class _SpritePainter extends CustomPainter {
|
||||
final w = _sprite.size.x * rate;
|
||||
final h = _sprite.size.y * rate;
|
||||
|
||||
final double dx = _anchor.relativePosition.dx * size.width;
|
||||
final double dy = _anchor.relativePosition.dy * size.height;
|
||||
final double dx = _anchor.relativePosition.x * size.width;
|
||||
final double dy = _anchor.relativePosition.y * size.height;
|
||||
|
||||
canvas.translate(
|
||||
dx - w * _anchor.relativePosition.dx,
|
||||
dy - h * _anchor.relativePosition.dy,
|
||||
dx - w * _anchor.relativePosition.x,
|
||||
dy - h * _anchor.relativePosition.y,
|
||||
);
|
||||
|
||||
_sprite.render(canvas, width: w, height: h);
|
||||
|
||||
@ -14,6 +14,7 @@ dependencies:
|
||||
convert: ^2.0.1
|
||||
flare_flutter: ^2.0.1
|
||||
meta: ^1.1.8
|
||||
vector_math: '>=2.0.0 <3.0.0'
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@ -2,7 +2,7 @@ import 'dart:ui';
|
||||
|
||||
import 'package:flame/components/position_component.dart';
|
||||
import 'package:flame/components/sprite_component.dart';
|
||||
import 'package:flame/position.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
@ -14,7 +14,7 @@ void main() {
|
||||
expect(c.toPosition().x, 2.2);
|
||||
expect(c.toPosition().y, 3.4);
|
||||
|
||||
c.setByPosition(Position(1.0, 0.0));
|
||||
c.setByPosition(Vector2(1.0, 0.0));
|
||||
expect(c.x, 1.0);
|
||||
expect(c.y, 0.0);
|
||||
});
|
||||
@ -26,7 +26,7 @@ void main() {
|
||||
expect(c.toSize().x, 2.2);
|
||||
expect(c.toSize().y, 3.4);
|
||||
|
||||
c.setBySize(Position(1.0, 0.0));
|
||||
c.setBySize(Vector2(1.0, 0.0));
|
||||
expect(c.width, 1.0);
|
||||
expect(c.height, 0.0);
|
||||
});
|
||||
|
||||
@ -5,6 +5,7 @@ import 'package:flame/components/mixins/has_game_ref.dart';
|
||||
import 'package:flame/components/mixins/resizable.dart';
|
||||
import 'package:flame/components/mixins/tapable.dart';
|
||||
import 'package:flame/game/base_game.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
@ -29,7 +30,7 @@ class MyComposed extends PositionComponent with HasGameRef, Tapable {
|
||||
|
||||
class PositionComponentNoNeedForRect extends PositionComponent with Tapable {}
|
||||
|
||||
const Size size = Size(1.0, 1.0);
|
||||
Vector2 size = Vector2(1.0, 1.0);
|
||||
|
||||
void main() {
|
||||
group('composable component test', () {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flame/game/base_game.dart';
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'package:flame/components/position_component.dart';
|
||||
@ -18,7 +19,7 @@ class MyComponent extends PositionComponent with Resizable {
|
||||
|
||||
class MyGame extends BaseGame {}
|
||||
|
||||
Size size = const Size(1.0, 1.0);
|
||||
Vector2 size = Vector2(1.0, 1.0);
|
||||
|
||||
void main() {
|
||||
group('resizable test', () {
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import 'package:flame/vector.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flame/position.dart';
|
||||
|
||||
void expectDouble(double d1, double d2) {
|
||||
expect((d1 - d2).abs() <= 0.0001, true);
|
||||
}
|
||||
@ -10,95 +9,96 @@ void expectDouble(double d1, double d2) {
|
||||
void main() {
|
||||
group('position test', () {
|
||||
test('test add', () {
|
||||
final Position p = Position(0.0, 5.0);
|
||||
final Position p2 = p.add(Position(5.0, 5.0));
|
||||
final Vector2 p = Vector2(0.0, 5.0);
|
||||
final Vector2 p2 = p + Vector2(5.0, 5.0);
|
||||
expect(p, p2);
|
||||
expectDouble(p.x, 5.0);
|
||||
expectDouble(p.y, 10.0);
|
||||
});
|
||||
|
||||
test('test clone', () {
|
||||
final Position p = Position(1.0, 0.0);
|
||||
final Position clone = p.clone();
|
||||
final Vector2 p = Vector2(1.0, 0.0);
|
||||
final Vector2 clone = p.clone();
|
||||
|
||||
clone.times(2.0);
|
||||
clone.scale(2.0);
|
||||
expectDouble(p.x, 1.0);
|
||||
expectDouble(clone.x, 2.0);
|
||||
});
|
||||
|
||||
test('test rotate', () {
|
||||
final Position p = Position(1.0, 0.0).rotate(math.pi / 2);
|
||||
final Vector2 p = Vector2(1.0, 0.0);
|
||||
VectorUtil.rotate(p, math.pi / 2);
|
||||
expectDouble(p.x, 0.0);
|
||||
expectDouble(p.y, 1.0);
|
||||
});
|
||||
|
||||
test('test length', () {
|
||||
final Position p1 = Position(3.0, 4.0);
|
||||
expectDouble(p1.length(), 5.0);
|
||||
final Vector2 p1 = Vector2(3.0, 4.0);
|
||||
expectDouble(p1.length, 5.0);
|
||||
|
||||
final Position p2 = Position(2.0, 0.0);
|
||||
expectDouble(p2.length(), 2.0);
|
||||
final Vector2 p2 = Vector2(2.0, 0.0);
|
||||
expectDouble(p2.length, 2.0);
|
||||
|
||||
final Position p3 = Position(0.0, 1.5);
|
||||
expectDouble(p3.length(), 1.5);
|
||||
final Vector2 p3 = Vector2(0.0, 1.5);
|
||||
expectDouble(p3.length, 1.5);
|
||||
});
|
||||
|
||||
test('test distance', () {
|
||||
final Position p1 = Position(10.0, 20.0);
|
||||
final Position p2 = Position(13.0, 24.0);
|
||||
final double result = p1.distance(p2);
|
||||
final Vector2 p1 = Vector2(10.0, 20.0);
|
||||
final Vector2 p2 = Vector2(13.0, 24.0);
|
||||
final double result = p1.distanceTo(p2);
|
||||
expectDouble(result, 5.0);
|
||||
});
|
||||
|
||||
test('equality', () {
|
||||
final Position p1 = Position.empty();
|
||||
final Position p2 = Position.empty();
|
||||
final Vector2 p1 = Vector2.zero();
|
||||
final Vector2 p2 = Vector2.zero();
|
||||
expect(p1 == p2, true);
|
||||
});
|
||||
|
||||
test('non equality', () {
|
||||
final Position p1 = Position.empty();
|
||||
final Position p2 = Position(1.0, 0.0);
|
||||
final Vector2 p1 = Vector2.zero();
|
||||
final Vector2 p2 = Vector2(1.0, 0.0);
|
||||
expect(p1 == p2, false);
|
||||
});
|
||||
|
||||
test('hashCode', () {
|
||||
final Position p1 = Position(2.0, -1.0);
|
||||
final Position p2 = Position(1.0, 0.0);
|
||||
final Vector2 p1 = Vector2(2.0, -1.0);
|
||||
final Vector2 p2 = Vector2(1.0, 0.0);
|
||||
expect(p1.hashCode == p2.hashCode, false);
|
||||
});
|
||||
|
||||
test('scaleTo', () {
|
||||
final Position p = Position(1.0, 0.0);
|
||||
final Vector2 p = VectorUtil.rotated(Vector2(1.0, 0.0), math.pi / 4);
|
||||
VectorUtil.scaleTo(p, 2.0);
|
||||
|
||||
p.rotate(math.pi / 4).scaleTo(2.0);
|
||||
expect(p.length(), 2.0);
|
||||
expect(p.length, 2.0);
|
||||
|
||||
p.rotate(-math.pi / 4);
|
||||
expect(p.length(), 2.0);
|
||||
VectorUtil.rotate(p, -math.pi / 4);
|
||||
expect(p.length, 2.0);
|
||||
expect(p.x, 2.0);
|
||||
expect(p.y, 0.0);
|
||||
});
|
||||
|
||||
test('scaleTo the zero vector', () {
|
||||
final Position p = Position.empty();
|
||||
expect(p.scaleTo(1.0).length(), 0.0);
|
||||
final Vector2 p = Vector2.zero();
|
||||
expect(p.normalized().length, 0.0);
|
||||
});
|
||||
|
||||
test('limit', () {
|
||||
final Position p1 = Position(1.0, 0.0);
|
||||
p1.limit(0.75);
|
||||
expect(p1.length(), 0.75);
|
||||
final Vector2 p1 = Vector2(1.0, 0.0);
|
||||
p1.clampScalar(0, 0.75);
|
||||
expect(p1.length, 0.75);
|
||||
expect(p1.x, 0.75);
|
||||
expect(p1.y, 0.0);
|
||||
|
||||
final Position p2 = Position(1.0, 1.0);
|
||||
p2.limit(3.0);
|
||||
expectDouble(p2.length(), math.sqrt(2));
|
||||
final Vector2 p2 = Vector2(1.0, 1.0);
|
||||
p2.clampScalar(0, 3.0);
|
||||
expectDouble(p2.length, math.sqrt(2));
|
||||
expect(p2.x, 1.0);
|
||||
expect(p2.y, 1.0);
|
||||
p2.limit(1.0);
|
||||
expectDouble(p2.length(), 1.0);
|
||||
p2.clampScalar(0, 1.0);
|
||||
expectDouble(p2.length, 1.0);
|
||||
expect(p2.x, p2.y);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user