mirror of
				https://github.com/flame-engine/flame.git
				synced 2025-11-04 04:47:13 +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
 | 
					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
 | 
					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
 | 
					the size as seen through the viewport together with the zoom of the camera. If for some reason you
 | 
				
			||||||
logical pixel size, you can use `canvasSize`. For a more in depth description on what each Viewport
 | 
					need to access the original real logical pixel size, you can use `canvasSize`. For a more in depth
 | 
				
			||||||
does and how it operates, check the documentation on its class.
 | 
					description on what each `Viewport` does and how it operates, check the documentation on its class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Camera
 | 
					## Camera
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Unlike the Viewport, the Camera is a more dynamic Canvas transformation that is normally dependent
 | 
					Unlike the `Viewport`, the `Camera` is a more dynamic `Canvas` transformation that is normally
 | 
				
			||||||
on:
 | 
					dependent on:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 * world coordinates that do not match screen coordinates 1:1
 | 
					 * 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)
 | 
					 * Centering or following the player around the game world (if the world is bigger than the screen).
 | 
				
			||||||
 * user controlled zooming in and out
 | 
					 * User controlled zooming in and out.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
There is only one Camera implementation but it allows for many different configurations. Again, you
 | 
					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`.
 | 
					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);
 | 
					      lastToAdd = createRandomCollidable(lastToAdd, screenCollidable);
 | 
				
			||||||
      final lastBottomRight =
 | 
					      final lastBottomRight =
 | 
				
			||||||
          lastToAdd.toAbsoluteRect().bottomRight.toVector2();
 | 
					          lastToAdd.toAbsoluteRect().bottomRight.toVector2();
 | 
				
			||||||
      final screenSize = size / camera.zoom;
 | 
					      if (lastBottomRight.x < size.x && lastBottomRight.y < size.y) {
 | 
				
			||||||
      if (lastBottomRight.x < screenSize.x &&
 | 
					 | 
				
			||||||
          lastBottomRight.y < screenSize.y) {
 | 
					 | 
				
			||||||
        add(lastToAdd);
 | 
					        add(lastToAdd);
 | 
				
			||||||
        totalAdded++;
 | 
					        totalAdded++;
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,8 @@
 | 
				
			|||||||
 - Refactor TextBoxComponent
 | 
					 - Refactor TextBoxComponent
 | 
				
			||||||
 - Fix bugs with TextBoxComponent
 | 
					 - Fix bugs with TextBoxComponent
 | 
				
			||||||
 - Improve error message for composed components
 | 
					 - 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
 | 
					 - Add `anchor` for `ShapeComponent` constructor
 | 
				
			||||||
 - Fix rendering of polygons in `ShapeComponent`
 | 
					 - Fix rendering of polygons in `ShapeComponent`
 | 
				
			||||||
 - Add `SpriteAnimation` support to parallax
 | 
					 - Add `SpriteAnimation` support to parallax
 | 
				
			||||||
 | 
				
			|||||||
@ -26,28 +26,18 @@ class ScreenCollidable extends PositionComponent
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  CollidableType collidableType = CollidableType.passive;
 | 
					  CollidableType collidableType = CollidableType.passive;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  final Vector2 _effectiveSize = Vector2.zero();
 | 
					 | 
				
			||||||
  double _zoom = 1.0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Future<void> onLoad() async {
 | 
					  Future<void> onLoad() async {
 | 
				
			||||||
    await super.onLoad();
 | 
					    await super.onLoad();
 | 
				
			||||||
    _updateSize();
 | 
					    size = gameRef.size;
 | 
				
			||||||
    addShape(HitboxRectangle());
 | 
					    addShape(HitboxRectangle());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final _zeroVector = Vector2.zero();
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void update(double dt) {
 | 
					  void update(double dt) {
 | 
				
			||||||
    super.update(dt);
 | 
					    super.update(dt);
 | 
				
			||||||
    _updateSize();
 | 
					    position = gameRef.camera.unprojectVector(_zeroVector);
 | 
				
			||||||
  }
 | 
					    size = gameRef.size;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  void _updateSize() {
 | 
					 | 
				
			||||||
    if (_effectiveSize != gameRef.viewport.effectiveSize ||
 | 
					 | 
				
			||||||
        _zoom != gameRef.camera.zoom) {
 | 
					 | 
				
			||||||
      _effectiveSize.setFrom(gameRef.viewport.effectiveSize);
 | 
					 | 
				
			||||||
      _zoom = gameRef.camera.zoom;
 | 
					 | 
				
			||||||
      size = _effectiveSize / _zoom;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -65,15 +65,20 @@ class BaseGame extends Game with FPSCounter {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  late Projector _combinedProjector;
 | 
					  late Projector _combinedProjector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final Vector2 _sizeBuffer = Vector2.zero();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// This is overwritten to consider the viewport transformation.
 | 
					  /// This is overwritten to consider the viewport transformation.
 | 
				
			||||||
  ///
 | 
					  ///
 | 
				
			||||||
  /// Which means that this is the logical size of the game screen area as
 | 
					  /// 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].
 | 
					  /// This does not match the Flutter widget size; for that see [canvasSize].
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Vector2 get size {
 | 
					  Vector2 get size {
 | 
				
			||||||
    assertHasLayout();
 | 
					    assertHasLayout();
 | 
				
			||||||
    return viewport.effectiveSize;
 | 
					    return _sizeBuffer
 | 
				
			||||||
 | 
					      ..setFrom(viewport.effectiveSize)
 | 
				
			||||||
 | 
					      ..scale(1 / camera.zoom);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// This is the original Flutter widget size, without any transformation.
 | 
					  /// This is the original Flutter widget size, without any transformation.
 | 
				
			||||||
 | 
				
			|||||||
@ -203,6 +203,18 @@ class Camera extends Projector {
 | 
				
			|||||||
    return worldCoordinates * zoom;
 | 
					    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
 | 
					  /// This is the (current) absolute target of the camera, i.e., the
 | 
				
			||||||
  /// coordinate that should be on the top left, regardless of relative
 | 
					  /// coordinate that should be on the top left, regardless of relative
 | 
				
			||||||
  /// offset, world boundaries or shake.
 | 
					  /// 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
 | 
					      // that means that the center would be -100, -100 if the zoom was 1
 | 
				
			||||||
      // meaning the topLeft will be -105, -105 (regardless of zoom)
 | 
					      // meaning the topLeft will be -105, -105 (regardless of zoom)
 | 
				
			||||||
      expect(game.unprojectVector(Vector2.zero()), Vector2.all(-105));
 | 
					      // but since the offset is set to center, topLeft will be -102.5, -102.5
 | 
				
			||||||
      // and with 2x zoom the center will actually be -95, -95
 | 
					      expect(game.unprojectVector(Vector2.zero()), Vector2.all(-102.5));
 | 
				
			||||||
      expect(game.unprojectVector(Vector2.all(5)), 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
 | 
					      // TODO(luan) we might want to change the behaviour so that the zoom
 | 
				
			||||||
      // is applied w.r.t. the relativeOffset and not topLeft
 | 
					      // is applied w.r.t. the relativeOffset and not topLeft
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user