mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-02 03:15:43 +08:00
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:
@ -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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ class DraggableSquare extends PositionComponent
|
||||
final localCoords = gameRef!.convertGlobalToLocalCoordinate(
|
||||
details.globalPosition.toVector2(),
|
||||
);
|
||||
position = localCoords - dragDeltaPosition;
|
||||
position.setFrom(localCoords - dragDeltaPosition);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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())));
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ class Square extends PositionComponent {
|
||||
@override
|
||||
void onMount() {
|
||||
super.onMount();
|
||||
size = Vector2.all(squareSize);
|
||||
size.setValues(squareSize, squareSize);
|
||||
anchor = Anchor.center;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user