Make game.size take zoom into consideration (#836)

* Make game.size take zoom into consideration

* Fix formatting

* Fix formatting

* Apply suggestions from code review

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

* Move _sizeBuffer

* Apply suggestions from code review

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

* Update list from wolfenrains suggestion

* Fix formatting

* Update CHANGELOG.md

Co-authored-by: Jochum van der Ploeg <jochum@vdploeg.net>
This commit is contained in:
Lukas Klingsbo
2021-06-09 16:39:45 +02:00
committed by GitHub
parent 607c4bbdcd
commit a7fd05f2b5
7 changed files with 39 additions and 30 deletions

View File

@ -29,18 +29,18 @@ your needs):
When using `BaseGame`, the operations performed by the viewport are done automatically to every
render operation, and the `size` property in the game, instead of the logical widget size, becomes
the size as seen through the viewport. If for some reason you need to access the original real
logical pixel size, you can use `canvasSize`. For a more in depth description on what each Viewport
does and how it operates, check the documentation on its class.
the size as seen through the viewport together with the zoom of the camera. If for some reason you
need to access the original real logical pixel size, you can use `canvasSize`. For a more in depth
description on what each `Viewport` does and how it operates, check the documentation on its class.
## Camera
Unlike the Viewport, the Camera is a more dynamic Canvas transformation that is normally dependent
on:
Unlike the `Viewport`, the `Camera` is a more dynamic `Canvas` transformation that is normally
dependent on:
* world coordinates that do not match screen coordinates 1:1
* centering or following the player around the game world (if it's bigger than the screen)
* user controlled zooming in and out
* World coordinates that do not match screen coordinates 1:1.
* Centering or following the player around the game world (if the world is bigger than the screen).
* User controlled zooming in and out.
There is only one Camera implementation but it allows for many different configurations. Again, you
can use it standalone on your `Game` but it's already included and wired into `BaseGame`.

View File

@ -228,9 +228,7 @@ class MultipleShapes extends BaseGame
lastToAdd = createRandomCollidable(lastToAdd, screenCollidable);
final lastBottomRight =
lastToAdd.toAbsoluteRect().bottomRight.toVector2();
final screenSize = size / camera.zoom;
if (lastBottomRight.x < screenSize.x &&
lastBottomRight.y < screenSize.y) {
if (lastBottomRight.x < size.x && lastBottomRight.y < size.y) {
add(lastToAdd);
totalAdded++;
} else {

View File

@ -18,6 +18,8 @@
- Refactor TextBoxComponent
- Fix bugs with TextBoxComponent
- Improve error message for composed components
- Fix `game.size` to take zoom into consideration
- Fix `camera.followComponent` when `zoom != 1`
- Add `anchor` for `ShapeComponent` constructor
- Fix rendering of polygons in `ShapeComponent`
- Add `SpriteAnimation` support to parallax

View File

@ -26,28 +26,18 @@ class ScreenCollidable extends PositionComponent
@override
CollidableType collidableType = CollidableType.passive;
final Vector2 _effectiveSize = Vector2.zero();
double _zoom = 1.0;
@override
Future<void> onLoad() async {
await super.onLoad();
_updateSize();
size = gameRef.size;
addShape(HitboxRectangle());
}
final _zeroVector = Vector2.zero();
@override
void update(double dt) {
super.update(dt);
_updateSize();
}
void _updateSize() {
if (_effectiveSize != gameRef.viewport.effectiveSize ||
_zoom != gameRef.camera.zoom) {
_effectiveSize.setFrom(gameRef.viewport.effectiveSize);
_zoom = gameRef.camera.zoom;
size = _effectiveSize / _zoom;
}
position = gameRef.camera.unprojectVector(_zeroVector);
size = gameRef.size;
}
}

View File

@ -65,15 +65,20 @@ class BaseGame extends Game with FPSCounter {
late Projector _combinedProjector;
final Vector2 _sizeBuffer = Vector2.zero();
/// This is overwritten to consider the viewport transformation.
///
/// Which means that this is the logical size of the game screen area as
/// exposed to the canvas after viewport transformations.
/// exposed to the canvas after viewport transformations and camera zooming.
///
/// This does not match the Flutter widget size; for that see [canvasSize].
@override
Vector2 get size {
assertHasLayout();
return viewport.effectiveSize;
return _sizeBuffer
..setFrom(viewport.effectiveSize)
..scale(1 / camera.zoom);
}
/// This is the original Flutter widget size, without any transformation.

View File

@ -203,6 +203,18 @@ class Camera extends Projector {
return worldCoordinates * zoom;
}
/// Takes coordinates in the screen space and returns their counter-part in
/// the world space.
Vector2 screenToWorld(Vector2 screenCoordinates) {
return unprojectVector(screenCoordinates);
}
/// Takes coordinates in the world space and returns their counter-part in
/// the screen space.
Vector2 worldToScreen(Vector2 worldCoordinates) {
return projectVector(worldCoordinates);
}
/// 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.

View File

@ -123,9 +123,11 @@ void main() {
// that means that the center would be -100, -100 if the zoom was 1
// meaning the topLeft will be -105, -105 (regardless of zoom)
expect(game.unprojectVector(Vector2.zero()), Vector2.all(-105));
// and with 2x zoom the center will actually be -95, -95
expect(game.unprojectVector(Vector2.all(5)), Vector2.all(-102.5));
// but since the offset is set to center, topLeft will be -102.5, -102.5
expect(game.unprojectVector(Vector2.zero()), Vector2.all(-102.5));
// and with 2x zoom the center will actually be -100, -100 since the
// relative offset is set to center.
expect(game.unprojectVector(Vector2.all(5)), Vector2.all(-100));
// TODO(luan) we might want to change the behaviour so that the zoom
// is applied w.r.t. the relativeOffset and not topLeft