Improve camera (#770)

This commit is contained in:
Luan Nico
2021-04-24 14:18:27 -04:00
committed by GitHub
parent cba7f59302
commit ccefeed1be
5 changed files with 33 additions and 15 deletions

View File

@ -24,7 +24,7 @@ class MovableSquare extends SquareComponent
timer = Timer(3.0)
..stop()
..callback = () {
gameRef.camera.setRelativeOffset(Anchor.center.toVector2());
gameRef.camera.setRelativeOffset(Anchor.center);
};
}
@ -50,7 +50,7 @@ class MovableSquare extends SquareComponent
@override
void onCollision(Set<Vector2> points, Collidable other) {
if (other is Rock) {
gameRef.camera.setRelativeOffset(Anchor.topCenter.toVector2());
gameRef.camera.setRelativeOffset(Anchor.topCenter);
timer.start();
}
}

View File

@ -7,6 +7,8 @@
- Adding `SpriteAnimationGroupComponent`
- Allow isometric tile maps with custom heights
- Add a new renderRect method to Sprite
- Addresses the TODO to change the camera public APIs to take Anchors for relativePositions
- Adds methods to support moving the camera relative to its current position
## [1.0.0-rc9]
- Fix input bug with other anchors than center

View File

@ -179,6 +179,8 @@ class Camera extends Projector {
update(0);
}
// Coordinates
@override
Vector2 unprojectVector(Vector2 screenCoordinates) {
return screenCoordinates * zoom + _position;
@ -199,6 +201,13 @@ class Camera extends Projector {
return worldCoordinates / zoom;
}
/// This is the (current) absolute target of the camera, i.e., the
/// coordinate that should be on the top left, regardless of relative
/// offset, world boundaries or shake.
Vector2 absoluteTarget() {
return _currentCameraDelta ?? follow ?? Vector2.zero();
}
// Follow
/// Immediately snaps the camera to start following the [component].
@ -214,7 +223,7 @@ class Camera extends Projector {
/// position, set the components anchor to center.
void followComponent(
PositionComponent component, {
Vector2? relativeOffset,
Anchor relativeOffset = Anchor.center,
Rect? worldBounds,
}) {
followVector2(
@ -234,12 +243,12 @@ class Camera extends Projector {
/// camera is allowed to move.
void followVector2(
Vector2 vector2, {
Vector2? relativeOffset,
Anchor relativeOffset = Anchor.center,
Rect? worldBounds,
}) {
follow = vector2;
this.worldBounds = worldBounds;
_targetRelativeOffset.setFrom(relativeOffset ?? Anchor.center.toVector2());
_targetRelativeOffset.setFrom(relativeOffset.toVector2());
_currentRelativeOffset.setFrom(_targetRelativeOffset);
}
@ -249,9 +258,8 @@ class Camera extends Projector {
/// you have two different options for the player to choose or your have a
/// "dialog" camera that puts the player in a better place to show the
/// dialog UI.
/// TODO(luan) this should be an anchor
void setRelativeOffset(Vector2 newRelativeOffset) {
_targetRelativeOffset.setFrom(newRelativeOffset);
void setRelativeOffset(Anchor newRelativeOffset) {
_targetRelativeOffset.setFrom(newRelativeOffset.toVector2());
}
Vector2 _screenDelta() {
@ -259,7 +267,7 @@ class Camera extends Projector {
}
Vector2 _target() {
final target = _currentCameraDelta ?? follow ?? Vector2.zero();
final target = absoluteTarget();
final attemptedTarget = target - _screenDelta();
final bounds = worldBounds;
@ -294,6 +302,13 @@ class Camera extends Projector {
// Movement
/// Moves the camera by a given [displacement] (delta). This is the same as
/// [moveTo] but instead of providing an absolute end position, you can
/// provide a desired translation vector.
void translateBy(Vector2 displacement) {
moveTo(absoluteTarget() + displacement);
}
/// Applies an ad-hoc movement to the camera towards the target, bypassing
/// follow. Once it arrives the camera will not move until [resetMovement]
/// is called.

View File

@ -214,7 +214,7 @@ void main() {
game.add(p);
game.update(0);
// this would be a typical vertical shoot-em-up
game.camera.followComponent(p, relativeOffset: Vector2(0.5, 0.8));
game.camera.followComponent(p, relativeOffset: const Anchor(0.5, 0.8));
expect(game.camera.position, Vector2.all(0.0));
p.position.setValues(600.0, 2000.0);
@ -296,7 +296,7 @@ void main() {
final game = BaseGame();
game.onResize(Vector2.all(200.0));
game.camera.setRelativeOffset(Anchor.center.toVector2());
game.camera.setRelativeOffset(Anchor.center);
game.update(0);
expect(game.camera.position, Vector2.zero());
@ -339,8 +339,9 @@ void main() {
game.add(p);
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),
// 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: const Anchor(0.25, 0.25),
worldBounds: const Rect.fromLTWH(0, 0, 1000, 1000),
);

View File

@ -102,7 +102,7 @@ void main() {
game.onResize(Vector2.all(10));
// no-op because the default is already top left
game.camera.setRelativeOffset(Anchor.topLeft.toVector2());
game.camera.setRelativeOffset(Anchor.topLeft);
// top left corner of the screen is (-100, -100)
game.camera.snapTo(Vector2.all(-100));
// zoom is 2x, meaning every 1 unit you walk away of (-100, -100)
@ -118,7 +118,7 @@ void main() {
// note: in the current implementation, if we change the relative position
// the zoom is still applied w.r.t. the top left of the screen
game.camera.setRelativeOffset(Anchor.center.toVector2());
game.camera.setRelativeOffset(Anchor.center);
game.camera.snap();
// that means that the center would be -100, -100 if the zoom was 1