mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-01 10:38:17 +08:00
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:
@ -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`.
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user