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

View File

@@ -7,6 +7,8 @@
- Adding `SpriteAnimationGroupComponent` - Adding `SpriteAnimationGroupComponent`
- Allow isometric tile maps with custom heights - Allow isometric tile maps with custom heights
- Add a new renderRect method to Sprite - 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] ## [1.0.0-rc9]
- Fix input bug with other anchors than center - Fix input bug with other anchors than center

View File

@@ -179,6 +179,8 @@ class Camera extends Projector {
update(0); update(0);
} }
// Coordinates
@override @override
Vector2 unprojectVector(Vector2 screenCoordinates) { Vector2 unprojectVector(Vector2 screenCoordinates) {
return screenCoordinates * zoom + _position; return screenCoordinates * zoom + _position;
@@ -199,6 +201,13 @@ class Camera extends Projector {
return worldCoordinates / zoom; 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 // Follow
/// Immediately snaps the camera to start following the [component]. /// Immediately snaps the camera to start following the [component].
@@ -214,7 +223,7 @@ class Camera extends Projector {
/// position, set the components anchor to center. /// position, set the components anchor to center.
void followComponent( void followComponent(
PositionComponent component, { PositionComponent component, {
Vector2? relativeOffset, Anchor relativeOffset = Anchor.center,
Rect? worldBounds, Rect? worldBounds,
}) { }) {
followVector2( followVector2(
@@ -234,12 +243,12 @@ class Camera extends Projector {
/// camera is allowed to move. /// camera is allowed to move.
void followVector2( void followVector2(
Vector2 vector2, { Vector2 vector2, {
Vector2? relativeOffset, Anchor relativeOffset = Anchor.center,
Rect? worldBounds, Rect? worldBounds,
}) { }) {
follow = vector2; follow = vector2;
this.worldBounds = worldBounds; this.worldBounds = worldBounds;
_targetRelativeOffset.setFrom(relativeOffset ?? Anchor.center.toVector2()); _targetRelativeOffset.setFrom(relativeOffset.toVector2());
_currentRelativeOffset.setFrom(_targetRelativeOffset); _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 /// 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" camera that puts the player in a better place to show the
/// dialog UI. /// dialog UI.
/// TODO(luan) this should be an anchor void setRelativeOffset(Anchor newRelativeOffset) {
void setRelativeOffset(Vector2 newRelativeOffset) { _targetRelativeOffset.setFrom(newRelativeOffset.toVector2());
_targetRelativeOffset.setFrom(newRelativeOffset);
} }
Vector2 _screenDelta() { Vector2 _screenDelta() {
@@ -259,7 +267,7 @@ class Camera extends Projector {
} }
Vector2 _target() { Vector2 _target() {
final target = _currentCameraDelta ?? follow ?? Vector2.zero(); final target = absoluteTarget();
final attemptedTarget = target - _screenDelta(); final attemptedTarget = target - _screenDelta();
final bounds = worldBounds; final bounds = worldBounds;
@@ -294,6 +302,13 @@ class Camera extends Projector {
// Movement // 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 /// Applies an ad-hoc movement to the camera towards the target, bypassing
/// follow. Once it arrives the camera will not move until [resetMovement] /// follow. Once it arrives the camera will not move until [resetMovement]
/// is called. /// is called.

View File

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

View File

@@ -102,7 +102,7 @@ void main() {
game.onResize(Vector2.all(10)); game.onResize(Vector2.all(10));
// no-op because the default is already top left // 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) // top left corner of the screen is (-100, -100)
game.camera.snapTo(Vector2.all(-100)); game.camera.snapTo(Vector2.all(-100));
// zoom is 2x, meaning every 1 unit you walk away of (-100, -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 // 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 // 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(); game.camera.snap();
// that means that the center would be -100, -100 if the zoom was 1 // that means that the center would be -100, -100 if the zoom was 1