Follow a Vector2 in Camera and add onPositionUpdate (#716)

* No setter for position and size

* Use setter for position and size

* Add onPositionUpdate and snapTo to Camera

* Fix formatting

* Fix size in test

* Update packages/flame/CHANGELOG.md

Co-authored-by: Jochum van der Ploeg <jochum@vdploeg.net>

* Update packages/flame/CHANGELOG.md

Co-authored-by: Jochum van der Ploeg <jochum@vdploeg.net>

* Better naming for internal position state

* Anchor and angle defaults on effect test utils

* No setter for position and size

* Fix scale effect

* Fix formatting

Co-authored-by: Jochum van der Ploeg <jochum@vdploeg.net>
Co-authored-by: Erick Zanardo <erickzanardoo@gmail.com>
This commit is contained in:
Lukas Klingsbo
2021-03-31 20:48:44 +02:00
committed by GitHub
parent b6fa44a7a1
commit 23a72f5f39
26 changed files with 169 additions and 154 deletions

View File

@ -6,9 +6,7 @@ import 'package:flame/palette.dart';
class SquareComponent extends PositionComponent {
Paint paint = BasicPalette.white.paint();
SquareComponent() {
size = Vector2.all(100.0);
}
SquareComponent() : super(size: Vector2.all(100.0));
@override
void render(Canvas c) {

View File

@ -59,8 +59,7 @@ class BasicAnimations extends BaseGame with TapDetector {
removeOnFinish: true,
);
animationComponent.position = position;
animationComponent.position = animationComponent.position - size / 2;
animationComponent.position = position - size / 2;
add(animationComponent);
}

View File

@ -42,7 +42,7 @@ class DraggableSquare extends PositionComponent
final localCoords = gameRef!.convertGlobalToLocalCoordinate(
details.globalPosition.toVector2(),
);
position = localCoords - dragDeltaPosition;
position.setFrom(localCoords - dragDeltaPosition);
return false;
}

View File

@ -16,11 +16,11 @@ class CombinedEffectGame extends BaseGame with TapDetector {
Future<void> onLoad() async {
greenSquare = SquareComponent()
..paint = green
..position = Vector2.all(100);
..position.setValues(100, 100);
redSquare = SquareComponent()
..paint = red
..position = Vector2.all(100);
..position.setValues(100, 100);
add(greenSquare);
add(redSquare);

View File

@ -15,7 +15,7 @@ final orange = Paint()..color = const Color(0xAABB6633);
SquareComponent makeSquare(Paint paint) {
return SquareComponent()
..paint = paint
..position = Vector2.all(100);
..position.setValues(100, 100);
}
class InfiniteEffectGame extends BaseGame with TapDetector {

View File

@ -11,9 +11,8 @@ class MoveEffectGame extends BaseGame with TapDetector {
@override
Future<void> onLoad() async {
add(
square = SquareComponent()..position = Vector2.all(100),
);
square = SquareComponent()..position.setValues(100, 100);
add(square);
}
@override

View File

@ -2,7 +2,6 @@ import 'dart:math';
import 'package:flame/components.dart';
import 'package:flame/effects.dart';
import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flame/gestures.dart';
import 'package:flutter/material.dart';
@ -14,11 +13,10 @@ class RotateEffectGame extends BaseGame with TapDetector {
@override
Future<void> onLoad() async {
add(
square = SquareComponent()
..position = Vector2.all(200)
..anchor = Anchor.center,
);
square = SquareComponent()
..position.setValues(200, 200)
..anchor = Anchor.center;
add(square);
}
@override

View File

@ -13,11 +13,10 @@ class ScaleEffectGame extends BaseGame with TapDetector {
@override
Future<void> onLoad() async {
add(
square = SquareComponent()
..position = Vector2.all(200)
..anchor = Anchor.center,
);
square = SquareComponent()
..position.setValues(200, 200)
..anchor = Anchor.center;
add(square);
}
@override

View File

@ -13,11 +13,10 @@ class SequenceEffectGame extends BaseGame with TapDetector {
@override
Future<void> onLoad() async {
add(
greenSquare = SquareComponent()
..paint = green
..position = Vector2.all(100),
);
greenSquare = SquareComponent()
..paint = green
..position.setValues(100, 100);
add(greenSquare);
}
@override

View File

@ -52,13 +52,13 @@ class TextGame extends BaseGame {
add(
TextComponent('center', config: _tiny)
..anchor = Anchor.center
..position = size / 2,
..position.setFrom(size / 2),
);
add(
TextComponent('bottomRight', config: _tiny)
..anchor = Anchor.bottomRight
..position = size,
..position.setFrom(size),
);
add(

View File

@ -76,6 +76,6 @@ class IsometricTileMapGame extends BaseGame with MouseMovementDetector {
final screenPosition = event.localPosition.toVector2();
final block = base.getBlock(screenPosition);
selector.show = base.containsBlock(block);
selector.position = base.getBlockPosition(block) + topLeft;
selector.position.setFrom(base.getBlockPosition(block) + topLeft);
}
}

View File

@ -34,7 +34,7 @@ class MovableSquare extends SquareComponent
timer.update(dt);
final ds = velocity * (speed * dt);
position += ds;
position.add(ds);
}
@override
@ -83,8 +83,8 @@ class Map extends Component {
class Rock extends SquareComponent with Hitbox, Collidable {
Rock(Vector2 position) {
this.position = position;
size = Vector2.all(50);
this.position.setFrom(position);
size.setValues(50, 50);
paint = Paint()..color = const Color(0xFF2222FF);
addShape(HitboxRectangle());
}
@ -104,7 +104,7 @@ class CameraAndViewportGame extends BaseGame
add(square = MovableSquare());
camera.cameraSpeed = 1;
camera.followObject(square, worldBounds: Map.bounds);
camera.followComponent(square, worldBounds: Map.bounds);
for (var i = 0; i < 30; i++) {
add(Rock(Vector2(Map.genCoord(), Map.genCoord())));

View File

@ -10,6 +10,8 @@
- Adding some more basic colors entries to the `BasicPalette`
- Fixing Flutter and Dart version constraints
- Exporting Images and AssetsCache
- Make `size` and `position` in `PositionComponent` final
- Add a `snapTo` and `onPositionUpdate` method to the `Camera`
- Remove the SpriteAnimationComponent when the animation is really done, not when it is on the last frame
- Revamp all the docs to be up to date with v1.0.0

View File

@ -42,7 +42,7 @@ class Square extends PositionComponent {
@override
void onMount() {
super.onMount();
size = Vector2.all(squareSize);
size.setValues(squareSize, squareSize);
anchor = Anchor.center;
}
}

View File

@ -64,7 +64,7 @@ class ParallaxComponent extends PositionComponent {
@override
void onGameResize(Vector2 size) {
super.onGameResize(size);
this.size = size;
this.size.setFrom(size);
parallax?.resize(size);
}

View File

@ -23,19 +23,23 @@ import 'mixins/hitbox.dart';
/// within this component's (width, height).
abstract class PositionComponent extends BaseComponent {
/// The position of this component on the screen (relative to the anchor).
Vector2 position;
final Vector2 _position;
Vector2 get position => _position;
set position(Vector2 position) => _position.setFrom(position);
/// X position of this component on the screen (relative to the anchor).
double get x => position.x;
set x(double x) => position.x = x;
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;
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;
final Vector2 _size;
Vector2 get size => _size;
set size(Vector2 size) => _size.setFrom(size);
/// Width (size) that this component is rendered with.
double get width => size.x;
@ -132,8 +136,8 @@ abstract class PositionComponent extends BaseComponent {
this.anchor = Anchor.topLeft,
this.renderFlipX = false,
this.renderFlipY = false,
}) : position = position ?? Vector2.zero(),
size = size ?? Vector2.zero();
}) : _position = position ?? Vector2.zero(),
_size = size ?? Vector2.zero();
@override
bool containsPoint(Vector2 point) {

View File

@ -126,7 +126,7 @@ class MoveEffect extends SimplePositionComponentEffect {
final lastEndAt = _currentSubPath!.startAt;
final localPercentage =
(curveProgress - lastEndAt) / (_currentSubPath!.endAt - lastEndAt);
component?.position = _currentSubPath!.previous +
((_currentSubPath!.v - _currentSubPath!.previous) * localPercentage);
component?.position.setFrom(_currentSubPath!.previous +
((_currentSubPath!.v - _currentSubPath!.previous) * localPercentage));
}
}

View File

@ -39,7 +39,7 @@ class ScaleEffect extends SimplePositionComponentEffect {
@override
void initialize(PositionComponent component) {
super.initialize(component);
_startSize = component.size;
_startSize = component.size.clone();
_delta = isRelative ? size : size - _startSize;
if (!isAlternating) {
endSize = _startSize + _delta;
@ -52,6 +52,6 @@ class ScaleEffect extends SimplePositionComponentEffect {
@override
void update(double dt) {
super.update(dt);
component?.size = _startSize + _delta * curveProgress;
component?.size.setFrom(_startSize + _delta * curveProgress);
}
}

View File

@ -35,7 +35,7 @@ void _moveToTarget(
/// There are three major factors that determine the camera position:
///
/// * Follow
/// If you want, you can call [followObject] at the beginning of your
/// If you want, you can call [followComponent] at the beginning of your
/// stage/world/level, and provided a [PositionComponent].
/// The camera will follow this component making sure its position is fixed
/// on the screen.
@ -89,29 +89,36 @@ class Camera {
double cameraSpeed = defaultCameraSpeed;
double shakeIntensity = defaultShakeIntensity;
/// This is the current position of the camera, ie the world coordinate that is
/// rendered on the top left of the screen (origin of the screen space).
/// This is the current position of the camera, ie the world coordinate that
/// is rendered on the top left of the screen (origin of the screen space).
///
/// Zero means no translation is applied.
/// You can't change this directly; the camera will handle all ongoing
/// movements so they smoothly transition.
/// If you want to immediately snap the camera to a new place, you can do:
/// ```
/// camera.moveTo(newPosition);
/// camera.snap();
/// camera.snapTo(newPosition);
/// ```
Vector2 get position => _position.clone();
Vector2 get position => _internalPosition.clone();
final Vector2 _position = Vector2.zero();
/// Do not change this directly since it bypasses [onPositionUpdate]
final Vector2 _internalPosition = Vector2.zero();
/// If set, the camera will "follow" this component, making sure that this
/// component is always rendered in a fixed position in the screen, by
/// immediately moving the camera to "focus" on the object.
Vector2 get _position => _internalPosition;
set _position(Vector2 position) {
_internalPosition.setFrom(position);
onPositionUpdate(_internalPosition);
}
/// If set, the camera will "follow" this vector, making sure that this
/// vector is always rendered in a fixed position in the screen, by
/// immediately moving the camera to "focus" on the where the vector is.
///
/// You probably want to set it to the player component.
/// Note that this is not smooth because the movement of the follow object
/// You might want to set it to the player component by using the
/// [followComponent] method.
/// Note that this is not smooth because the movement of the followed vector
/// is assumed to be smooth.
PositionComponent? follow;
Vector2? follow;
/// Where in the screen the follow object should be.
///
@ -146,10 +153,10 @@ class Camera {
if (_targetCameraDelta != null && _currentCameraDelta != null) {
_moveToTarget(_currentCameraDelta!, _targetCameraDelta!, ds);
_position.setFrom(_currentCameraDelta! + shake);
_position = _currentCameraDelta! + shake;
} else {
_moveToTarget(_currentRelativeOffset, _targetRelativeOffset, ds);
_position.setFrom(_getTarget() + shake);
_position = _target() + shake;
}
if (shaking) {
@ -182,23 +189,23 @@ class Camera {
// Follow
/// Immediately snaps the camera to start following the object [follow].
/// Immediately snaps the camera to start following the [component].
///
/// This means that the camera will move so that the [follow] object is
/// in a fixed position on the screen.
/// This means that the camera will move so that the position vector of the
/// component is in a fixed position on the screen.
/// That position is determined by a fraction of screen size defined by
/// [relativeOffset] (default to the center).
/// [worldBounds] can be optionally set to add boundaries to how far the
/// camera is allowed to move.
/// The object is "grabbed" by its anchor (default top left). So for example
/// if you want the center of the object to be at the fixed position, set
/// its anchor to center.
void followObject(
PositionComponent follow, {
/// The component is "grabbed" by its anchor (default top left).
/// So for example if you want the center of the object to be at the fixed
/// position, set the components anchor to center.
void followComponent(
PositionComponent component, {
Vector2? relativeOffset,
Rect? worldBounds,
}) {
this.follow = follow;
follow = component.position;
this.worldBounds = worldBounds;
_targetRelativeOffset.setFrom(relativeOffset ?? Anchor.center.toVector2());
_currentRelativeOffset.setFrom(_targetRelativeOffset);
@ -214,12 +221,12 @@ class Camera {
_targetRelativeOffset.setFrom(newRelativeOffset);
}
Vector2 _getTarget() {
Vector2 _target() {
if (follow == null) {
return Vector2.zero();
}
final screenDelta = gameRef.size.clone()..multiply(_currentRelativeOffset);
final attemptedTarget = follow!.position - screenDelta;
final attemptedTarget = follow! - screenDelta;
final bounds = worldBounds;
if (bounds != null) {
@ -259,9 +266,16 @@ class Camera {
///
/// The camera will be smoothly transitioned to this position.
/// This will replace any previous targets.
void moveTo(Vector2 p) {
void moveTo(Vector2 position) {
_currentCameraDelta = _position;
_targetCameraDelta = p.clone();
_targetCameraDelta = position.clone();
}
/// Instantly moves the camera to the target, bypassing follow.
/// This will replace any previous targets.
void snapTo(Vector2 position) {
moveTo(position);
snap();
}
/// Smoothly resets any moveTo targets.
@ -290,4 +304,8 @@ class Camera {
}
return 0.0;
}
/// If you need updated on when the position of the camera is updated you
/// can override this.
void onPositionUpdate(Vector2 position) {}
}

View File

@ -7,30 +7,30 @@ void main() {
group('component test', () {
test('test get/set x/y or position', () {
final PositionComponent c = SpriteComponent();
c.position = Vector2(2.2, 3.4);
c.position.setValues(2.2, 3.4);
expect(c.x, 2.2);
expect(c.y, 3.4);
c.position = Vector2(1.0, 0.0);
c.position.setValues(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.size = Vector2(2.2, 3.4);
c.size.setValues(2.2, 3.4);
expect(c.size.x, 2.2);
expect(c.size.y, 3.4);
c.size = Vector2(1.0, 0.0);
c.size.setValues(1.0, 0.0);
expect(c.width, 1.0);
expect(c.height, 0.0);
});
test('test get/set rect', () {
final PositionComponent c = SpriteComponent();
c.position = Vector2(0.0, 1.0);
c.size = Vector2(2.0, 2.0);
c.position.setValues(0.0, 1.0);
c.size.setValues(2.0, 2.0);
final rect = c.toRect();
expect(rect.left, 0.0);
expect(rect.top, 1.0);
@ -46,8 +46,8 @@ void main() {
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.position.setValues(0.0, 1.0);
c.size.setValues(2.0, 2.0);
c.anchor = Anchor.center;
final rect = c.toRect();
expect(rect.left, -1.0);
@ -64,8 +64,8 @@ void main() {
test('test get/set anchorPosition', () {
final PositionComponent c = SpriteComponent();
c.position = Vector2(0.0, 1.0);
c.size = Vector2(2.0, 2.0);
c.position.setValues(0.0, 1.0);
c.size.setValues(2.0, 2.0);
c.anchor = Anchor.center;
final anchorPosition = c.topLeftPosition;
expect(anchorPosition.x, -1.0);

View File

@ -88,7 +88,7 @@ void main() {
final wrapper = MyComposed();
game.onResize(size);
child.size = Vector2.all(1);
child.size.setValues(1.0, 1.0);
game.add(wrapper);
wrapper.addChild(child);
game.update(0.0);
@ -101,11 +101,11 @@ void main() {
test('tap on offset children', () {
final game = MyGame();
final child = MyTap()
..position = Vector2.all(100)
..size = Vector2.all(100);
..position.setFrom(Vector2.all(100))
..size.setFrom(Vector2.all(100));
final wrapper = MyComposed()
..position = Vector2.all(100)
..size = Vector2.all(300);
..position.setFrom(Vector2.all(100))
..size.setFrom(Vector2.all(300));
game.onResize(size);
game.add(wrapper);

View File

@ -12,8 +12,8 @@ void main() {
group('PositionComponent overlap test', () {
test('overlap', () {
final PositionComponent component = MyComponent();
component.position = Vector2(2.0, 2.0);
component.size = Vector2(4.0, 4.0);
component.position.setValues(2.0, 2.0);
component.size.setValues(4.0, 4.0);
component.angle = 0.0;
component.anchor = Anchor.center;
@ -23,8 +23,8 @@ void main() {
test('overlap on edge', () {
final PositionComponent component = MyComponent();
component.position = Vector2(2.0, 2.0);
component.size = Vector2(2.0, 2.0);
component.position.setValues(2.0, 2.0);
component.size.setValues(2.0, 2.0);
component.angle = 0.0;
component.anchor = Anchor.center;
@ -34,8 +34,8 @@ void main() {
test('not overlapping with x', () {
final PositionComponent component = MyComponent();
component.position = Vector2(2.0, 2.0);
component.size = Vector2(2.0, 2.0);
component.position.setValues(2.0, 2.0);
component.size.setValues(2.0, 2.0);
component.angle = 0.0;
component.anchor = Anchor.center;
@ -45,8 +45,8 @@ void main() {
test('not overlapping with y', () {
final PositionComponent component = MyComponent();
component.position = Vector2(2.0, 2.0);
component.size = Vector2(2.0, 2.0);
component.position.setValues(2.0, 2.0);
component.size.setValues(2.0, 2.0);
component.angle = 0.0;
component.anchor = Anchor.center;
@ -56,8 +56,8 @@ void main() {
test('overlapping with angle', () {
final PositionComponent component = MyComponent();
component.position = Vector2(2.0, 2.0);
component.size = Vector2(2.0, 2.0);
component.position.setValues(2.0, 2.0);
component.size.setValues(2.0, 2.0);
component.angle = math.pi / 4;
component.anchor = Anchor.center;
@ -67,8 +67,8 @@ void main() {
test('not overlapping with angle', () {
final PositionComponent component = MyComponent();
component.position = Vector2(2.0, 2.0);
component.size = Vector2(2.0, 2.0);
component.position.setValues(2.0, 2.0);
component.size.setValues(2.0, 2.0);
component.angle = math.pi / 4;
component.anchor = Anchor.center;
@ -78,8 +78,8 @@ void main() {
test('overlapping with angle and topLeft anchor', () {
final PositionComponent component = MyComponent();
component.position = Vector2(1.0, 1.0);
component.size = Vector2(2.0, 2.0);
component.position.setValues(1.0, 1.0);
component.size.setValues(2.0, 2.0);
component.angle = math.pi / 4;
component.anchor = Anchor.topLeft;
@ -88,11 +88,10 @@ void main() {
});
test('component with hitbox contains point', () {
final size = Vector2(2.0, 2.0);
final Hitbox component = MyHitboxComponent();
component.position = Vector2(1.0, 1.0);
component.position.setValues(1.0, 1.0);
component.anchor = Anchor.topLeft;
component.size = size;
component.size.setValues(2.0, 2.0);
final hitbox = HitboxPolygon([
Vector2(1, 0),
Vector2(0, -1),
@ -106,11 +105,10 @@ void main() {
});
test('component with anchor topLeft contains point on edge', () {
final size = Vector2(2.0, 2.0);
final Hitbox component = MyHitboxComponent();
component.position = Vector2(-1, -1);
component.position.setValues(-1, -1);
component.anchor = Anchor.topLeft;
component.size = size;
component.size.setValues(2.0, 2.0);
final hitbox = HitboxRectangle();
component.addShape(hitbox);
@ -121,11 +119,10 @@ void main() {
});
test('component with anchor bottomRight contains point on edge', () {
final size = Vector2(2.0, 2.0);
final Hitbox component = MyHitboxComponent();
component.position = Vector2(1, 1);
component.position.setValues(1, 1);
component.anchor = Anchor.bottomRight;
component.size = size;
component.size.setValues(2.0, 2.0);
final hitbox = HitboxRectangle();
component.addShape(hitbox);
@ -136,11 +133,10 @@ void main() {
});
test('component with anchor topRight does not contain close points', () {
final size = Vector2(2.0, 2.0);
final Hitbox component = MyHitboxComponent();
component.position = Vector2(1, 1);
component.position.setValues(1, 1);
component.anchor = Anchor.topLeft;
component.size = size;
component.size.setValues(2.0, 2.0);
final hitbox = HitboxRectangle();
component.addShape(hitbox);
@ -151,11 +147,10 @@ void main() {
});
test('component with hitbox does not contains point', () {
final size = Vector2(2.0, 2.0);
final Hitbox component = MyHitboxComponent();
component.position = Vector2(1.0, 1.0);
component.position.setValues(1.0, 1.0);
component.anchor = Anchor.topLeft;
component.size = size;
component.size.setValues(2.0, 2.0);
component.addShape(HitboxPolygon([
Vector2(1, 0),
Vector2(0, -1),
@ -169,8 +164,8 @@ void main() {
test('component with zero size does not contain point', () {
final PositionComponent component = MyComponent();
component.position = Vector2(2.0, 2.0);
component.size = Vector2(0.0, 0.0);
component.position.setValues(2.0, 2.0);
component.size.setValues(0.0, 0.0);
component.angle = 0.0;
component.anchor = Anchor.center;

View File

@ -5,7 +5,7 @@ import 'package:test/test.dart';
class MyComponent extends PositionComponent {
String name;
@override
Vector2 size = Vector2(2.0, 2.0);
final Vector2 size = Vector2(2.0, 2.0);
late Vector2 gameSize;
MyComponent(this.name);

View File

@ -100,12 +100,12 @@ class TestComponent extends PositionComponent {
TestComponent({
Vector2? position,
Vector2? size,
double? angle,
Anchor? anchor,
}) {
this.position = position ?? Vector2.zero();
this.size = size ?? Vector2.all(100.0);
this.angle = angle ?? 0.0;
this.anchor = anchor ?? Anchor.center;
}
double angle = 0.0,
Anchor anchor = Anchor.center,
}) : super(
position: position,
size: size ?? Vector2.all(100.0),
angle: angle,
anchor: anchor,
);
}

View File

@ -14,6 +14,7 @@ void main() {
final argumentSize = randomVector2();
final argumentAngle = randomAngle();
final path = List.generate(3, (i) => randomVector2());
TestComponent component() {
return TestComponent(
position: randomVector2(),

View File

@ -11,10 +11,13 @@ import '../util/mock_canvas.dart';
class TestComponent extends PositionComponent {
static final Paint _paint = Paint();
TestComponent(Vector2 position) {
this.position = position;
size = Vector2.all(1.0);
}
TestComponent(Vector2 position)
: super(
position: position,
size: Vector2.all(1.0),
);
@override
void render(Canvas c) {
super.render(c);
@ -181,10 +184,10 @@ void main() {
final p = TestComponent(Vector2.all(10.0))..anchor = Anchor.center;
game.add(p);
game.update(0);
game.camera.followObject(p);
game.camera.followComponent(p);
expect(game.camera.position, Vector2.all(0.0));
p.position = Vector2(10.0, 20.0);
p.position.setValues(10.0, 20.0);
// follow happens immediately because the object's movement is assumed to be smooth
game.update(0);
// (10,20) - half screen (50,50)
@ -210,10 +213,10 @@ void main() {
game.add(p);
game.update(0);
// this would be a typical vertical shoot-em-up
game.camera.followObject(p, relativeOffset: Vector2(0.5, 0.8));
game.camera.followComponent(p, relativeOffset: Vector2(0.5, 0.8));
expect(game.camera.position, Vector2.all(0.0));
p.position = Vector2(600.0, 2000.0);
p.position.setValues(600.0, 2000.0);
// follow happens immediately because the object's movement is assumed to be smooth
game.update(0);
// (600,2000) - fractional screen (50,80)
@ -238,29 +241,29 @@ void main() {
final p = TestComponent(Vector2.all(10.0))..anchor = Anchor.center;
game.add(p);
game.update(0);
game.camera.followObject(
game.camera.followComponent(
p,
worldBounds: const Rect.fromLTWH(-1000, -1000, 2000, 2000),
);
p.position = Vector2(600.0, 700.0); // well within bounds
p.position.setValues(600.0, 700.0); // well within bounds
game.update(0);
expect(game.camera.position, Vector2(550, 650));
// x ok, y starts to get to bounds
p.position = Vector2(600.0, 950.0); // right on the edge
p.position.setValues(600.0, 950.0); // right on the edge
game.update(0);
expect(game.camera.position, Vector2(550, 900));
p.position = Vector2(600.0, 950.0); // stop advancing
p.position.setValues(600.0, 950.0); // stop advancing
game.update(0);
expect(game.camera.position, Vector2(550, 900));
p.position = Vector2(-1100.0, 950.0);
p.position.setValues(-1100.0, 950.0);
game.update(0);
expect(game.camera.position, Vector2(-1000, 900));
p.position = Vector2(1000.0, 1000.0);
p.position.setValues(1000.0, 1000.0);
game.update(0);
expect(game.camera.position, Vector2(900, 900));
});
@ -271,7 +274,7 @@ void main() {
final p = TestComponent(Vector2.all(10.0))..anchor = Anchor.center;
game.add(p);
game.update(0);
game.camera.followObject(
game.camera.followComponent(
p,
worldBounds: const Rect.fromLTWH(0, 0, 100, 100),
);
@ -280,11 +283,11 @@ void main() {
game.update(0);
expect(game.camera.position, Vector2(50, 50));
p.position = Vector2(60.0, 50.0);
p.position.setValues(60.0, 50.0);
game.update(0);
expect(game.camera.position, Vector2(50, 50));
p.position = Vector2(-10.0, -20.0);
p.position.setValues(-10.0, -20.0);
game.update(0);
expect(game.camera.position, Vector2(50, 50));
});
@ -299,7 +302,7 @@ void main() {
final p = TestComponent(Vector2.all(10.0))..anchor = Anchor.center;
game.add(p);
game.camera.followObject(
game.camera.followComponent(
p,
// this could be a typical mario-like platformer, where the player is more on the bottom left to allow the scenario to be seem
relativeOffset: Vector2(0.25, 0.25),
@ -309,19 +312,19 @@ void main() {
game.update(0);
expect(game.camera.position, Vector2(0, 0));
p.position = Vector2(30.0, 0.0);
p.position.setValues(30.0, 0.0);
game.update(0);
expect(game.camera.position, Vector2(5, 0));
p.position = Vector2(30.0, 100.0);
p.position.setValues(30.0, 100.0);
game.update(0);
expect(game.camera.position, Vector2(5, 75));
p.position = Vector2(30.0, 1000.0);
p.position.setValues(30.0, 1000.0);
game.update(0);
expect(game.camera.position, Vector2(5, 900));
p.position = Vector2(950.0, 20.0);
p.position.setValues(950.0, 20.0);
game.update(0);
expect(game.camera.position, Vector2(900, 0));
});