Rename isHud to respectCamera (#1159)

* Camera as an internal component

* Correct respectCamera

* Added changelog entry

* Add super call that will later be removed

* Rename callRender -> callOwnRender

* Don't call render when root

* Remove callOwnRender

* Skip CameraWrapper in own renderTree

* Too complex to have camera as component

* Revert test

* Update docs for respectCamera

* Move down field

* Fix changelog
This commit is contained in:
Lukas Klingsbo
2021-12-04 14:41:51 +01:00
committed by GitHub
parent 0835741e63
commit 4b40479563
11 changed files with 58 additions and 37 deletions

View File

@ -24,8 +24,9 @@ component before the next update loop. It will then no longer be rendered or upd
`game.remove(Component c)` and `component.removeFromParent()` also can be used to remove components `game.remove(Component c)` and `component.removeFromParent()` also can be used to remove components
from its parent. from its parent.
The `isHUD` variable can be overridden or set to true (defaults to `false`) to make the `FlameGame` The `respectCamera` variable can be overridden or set to `false` (defaults to `true`) to make the
ignore the `camera` for this element, making it static in relation to the screen that is. `FlameGame` ignore the `camera` for this component, making it static in relation to the viewport
that is.
Do note that this currently only works if the component is added directly to the root `FlameGame`. Do note that this currently only works if the component is added directly to the root `FlameGame`.
The `onRemove` method can be overridden to run code before the component is removed from the game, The `onRemove` method can be overridden to run code before the component is removed from the game,

View File

@ -111,7 +111,7 @@ you handle this through the `button` component.
As the name suggests this button is a hud by default, which means that it will be static on your As the name suggests this button is a hud by default, which means that it will be static on your
screen even if the camera for the game moves around. You can also use this component as a non-hud by screen even if the camera for the game moves around. You can also use this component as a non-hud by
setting `hudButtonComponent.isHud = false;`. setting `hudButtonComponent.respectCamera = true;`.
If you want to act upon the button being pressed (which would be the common thing to do) you can either pass in If you want to act upon the button being pressed (which would be the common thing to do) you can either pass in
a callback function as the `onPressed` argument, or you extend the component and override a callback function as the `onPressed` argument, or you extend the component and override

View File

@ -163,11 +163,11 @@ class JoystickAdvancedExample extends FlameGame
speedText = TextComponent( speedText = TextComponent(
text: 'Speed: 0', text: 'Speed: 0',
textRenderer: _regular, textRenderer: _regular,
)..isHud = true; )..respectCamera = false;
directionText = TextComponent( directionText = TextComponent(
text: 'Direction: idle', text: 'Direction: idle',
textRenderer: _regular, textRenderer: _regular,
)..isHud = true; )..respectCamera = false;
final speedWithMargin = HudMarginComponent( final speedWithMargin = HudMarginComponent(
margin: const EdgeInsets.only( margin: const EdgeInsets.only(

View File

@ -7,6 +7,7 @@
- Export new effects system - Export new effects system
- Introduce `updateTree` to follow the `renderTree` convention - Introduce `updateTree` to follow the `renderTree` convention
- Fix `Parallax.load` with different loading times - Fix `Parallax.load` with different loading times
- `isHud` renamed to `respectCamera`
## [1.0.0-releasecandidate.18] ## [1.0.0-releasecandidate.18]
- Forcing portrait and landscape mode is now supported on web - Forcing portrait and landscape mode is now supported on web

View File

@ -18,11 +18,15 @@ import 'cache/value_cache.dart';
/// called automatically once the component is added to the component tree in /// called automatically once the component is added to the component tree in
/// your game (with `game.add`). /// your game (with `game.add`).
class Component with Loadable { class Component with Loadable {
/// Whether this component is a HUD (Heads-up display) object or not. /// Whether this component should respect the camera or not.
/// ///
/// HUD objects ignore the FlameGame.camera when rendered (so their position /// Components that have this property set to false will ignore the
/// coordinates are considered relative to the device screen). /// `FlameGame.camera` when rendered (so their position coordinates are
bool isHud = false; /// considered relative only to the viewport instead).
///
/// Do note that this currently only works if the component is added directly
/// to the root `FlameGame`.
bool respectCamera = true;
/// Whether this component has been prepared and is ready to be added to the /// Whether this component has been prepared and is ready to be added to the
/// game loop. /// game loop.
@ -153,7 +157,9 @@ class Component with Loadable {
@protected @protected
Vector2 eventPosition(PositionInfo info) { Vector2 eventPosition(PositionInfo info) {
return isHud ? info.eventPosition.viewportOnly : info.eventPosition.game; return respectCamera
? info.eventPosition.game
: info.eventPosition.viewportOnly;
} }
/// Remove the component from its parent in the next tick. /// Remove the component from its parent in the next tick.

View File

@ -18,7 +18,7 @@ import '../../../game.dart';
class HudMarginComponent<T extends FlameGame> extends PositionComponent class HudMarginComponent<T extends FlameGame> extends PositionComponent
with HasGameRef<T> { with HasGameRef<T> {
@override @override
bool isHud = true; bool respectCamera = false;
/// Instead of setting a position of the [HudMarginComponent] a margin /// Instead of setting a position of the [HudMarginComponent] a margin
/// from the edges of the viewport can be used instead. /// from the edges of the viewport can be used instead.

View File

@ -38,7 +38,7 @@ import '../projector.dart';
/// ///
/// Note: in the context of the FlameGame, the camera effectively translates /// Note: in the context of the FlameGame, the camera effectively translates
/// the position where components are rendered with relation to the Viewport. /// the position where components are rendered with relation to the Viewport.
/// Components marked as `isHud = true` are always rendered in screen /// Components marked as `respectCamera = false` are always rendered in screen
/// coordinates, bypassing the camera altogether. /// coordinates, bypassing the camera altogether.
class Camera extends Projector { class Camera extends Projector {
Camera() : _viewport = DefaultViewport() { Camera() : _viewport = DefaultViewport() {

View File

@ -1,5 +1,7 @@
import 'dart:ui'; import 'dart:ui';
import 'package:meta/meta.dart';
import '../../../components.dart'; import '../../../components.dart';
import 'camera.dart'; import 'camera.dart';
@ -7,6 +9,7 @@ import 'camera.dart';
/// converted into a proper Component in a future release, but until then /// converted into a proper Component in a future release, but until then
/// using it in any code other than the FlameGame class is unsafe and /// using it in any code other than the FlameGame class is unsafe and
/// not recommended. /// not recommended.
@internal
class CameraWrapper { class CameraWrapper {
// TODO(st-pasha): extend from Component // TODO(st-pasha): extend from Component
CameraWrapper(this.camera, this.world); CameraWrapper(this.camera, this.world);
@ -19,16 +22,14 @@ class CameraWrapper {
} }
void render(Canvas canvas) { void render(Canvas canvas) {
// TODO(st-pasha): it would be easier to keep the world and the
// HUD as two separate component trees.
camera.viewport.render(canvas, (_canvas) { camera.viewport.render(canvas, (_canvas) {
var hasCamera = false; // so we don't apply unecessary transformations var hasCamera = false; // so we don't apply unnecessary transformations
world.forEach((component) { world.forEach((component) {
if (!component.isHud && !hasCamera) { if (component.respectCamera && !hasCamera) {
canvas.save(); canvas.save();
camera.apply(canvas); camera.apply(canvas);
hasCamera = true; hasCamera = true;
} else if (component.isHud && hasCamera) { } else if (!component.respectCamera && hasCamera) {
canvas.restore(); canvas.restore();
hasCamera = false; hasCamera = false;
} }

View File

@ -21,13 +21,11 @@ class FlameGame extends Component with Game {
_cameraWrapper = CameraWrapper(camera ?? Camera(), children); _cameraWrapper = CameraWrapper(camera ?? Camera(), children);
} }
late final CameraWrapper _cameraWrapper;
/// The camera translates the coordinate space after the viewport is applied. /// The camera translates the coordinate space after the viewport is applied.
Camera get camera => _cameraWrapper.camera; Camera get camera => _cameraWrapper.camera;
// When the Game becomes a Component (#906), this could be added directly
// into the component tree.
late final CameraWrapper _cameraWrapper;
/// 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
@ -64,7 +62,17 @@ class FlameGame extends Component with Game {
/// interfering with each others rendering. /// interfering with each others rendering.
@override @override
@mustCallSuper @mustCallSuper
void render(Canvas canvas) => _cameraWrapper.render(canvas); void render(Canvas canvas) {
if (parent == null) {
renderTree(canvas);
}
}
@override
void renderTree(Canvas canvas) {
// Don't call super.renderTree, since the tree is rendered by the camera
_cameraWrapper.render(canvas);
}
/// This updates every component in the tree. /// This updates every component in the tree.
/// ///
@ -75,10 +83,11 @@ class FlameGame extends Component with Game {
@override @override
@mustCallSuper @mustCallSuper
void update(double dt) { void update(double dt) {
super.update(dt);
_cameraWrapper.update(dt);
if (parent == null) { if (parent == null) {
super.updateTree(dt, callOwnUpdate: false); super.updateTree(dt, callOwnUpdate: false);
} }
_cameraWrapper.update(dt);
} }
/// This passes the new size along to every component in the tree via their /// This passes the new size along to every component in the tree via their

View File

@ -116,7 +116,7 @@ mixin Game on Loadable {
onAttach(); onAttach();
} }
/// Called when the game has been attached. This can be overriden /// Called when the game has been attached. This can be overridden
/// to add logic that requires the game to already be attached /// to add logic that requires the game to already be attached
/// to the widget tree. /// to the widget tree.
void onAttach() {} void onAttach() {}
@ -131,7 +131,7 @@ mixin Game on Loadable {
} }
/// Called after the game has left the widget tree. /// Called after the game has left the widget tree.
/// This can be overriden to add logic that requires the game /// This can be overridden to add logic that requires the game
/// not be on the flutter widget tree anymore. /// not be on the flutter widget tree anymore.
void onDetach() {} void onDetach() {}
@ -157,12 +157,14 @@ mixin Game on Loadable {
return _gameRenderBox!.localToGlobal(point.toOffset()).toVector2(); return _gameRenderBox!.localToGlobal(point.toOffset()).toVector2();
} }
/// This is the projector used by non-isHUD components. /// This is the projector used by all components that respect the camera
/// This can be overriden on your [Game] implementation. /// (`respectCamera = true`).
/// This can be overridden on your [Game] implementation.
Projector projector = IdentityProjector(); Projector projector = IdentityProjector();
/// This is the projector used by isHUD components. /// This is the projector used by components that don't respect the camera
/// This can be overriden on your [Game] implementation. /// (`respectCamera = false`).
/// This can be overridden on your [Game] implementation.
Projector viewportProjector = IdentityProjector(); Projector viewportProjector = IdentityProjector();
/// Utility method to load and cache the image for a sprite based on its /// Utility method to load and cache the image for a sprite based on its

View File

@ -11,9 +11,10 @@ import 'package:flutter_test/flutter_test.dart';
class _MyComponent extends Component { class _MyComponent extends Component {
@override @override
bool isHud; bool respectCamera;
_MyComponent(int priority, {this.isHud = false}) : super(priority: priority); _MyComponent(int priority, {this.respectCamera = true})
: super(priority: priority);
@override @override
void render(Canvas canvas) { void render(Canvas canvas) {
@ -54,9 +55,9 @@ void main() {
'only HUD components', 'only HUD components',
(game) async { (game) async {
await game.ensureAddAll([ await game.ensureAddAll([
_MyComponent(4, isHud: true), _MyComponent(4, respectCamera: false),
_MyComponent(1, isHud: true), _MyComponent(1, respectCamera: false),
_MyComponent(2, isHud: true), _MyComponent(2, respectCamera: false),
]); ]);
final canvas = MockCanvas(); final canvas = MockCanvas();
game.camera.snapTo(Vector2(12.0, 18.0)); game.camera.snapTo(Vector2(12.0, 18.0));
@ -78,9 +79,9 @@ void main() {
await game.ensureAddAll([ await game.ensureAddAll([
_MyComponent(4), _MyComponent(4),
_MyComponent(1), _MyComponent(1),
_MyComponent(2, isHud: true), _MyComponent(2, respectCamera: false),
_MyComponent(5, isHud: true), _MyComponent(5, respectCamera: false),
_MyComponent(3, isHud: true), _MyComponent(3, respectCamera: false),
_MyComponent(0), _MyComponent(0),
]); ]);