`CameraComponent.setBounds` with `considerViewport: true` only works for bounds that start at (0, 0), at zoom 1
维护者通常 1 天内回复
评估
这个 Issue 还没有评估数据。
描述
What happened?
camera.setBounds(bounds, considerViewport: true) should keep the whole viewport inside bounds. ViewportAwareBoundsBehavior calculates the region that the camera has to stay in, but it only gets it right for a Rectangle or RoundedRectangle whose top-left corner is at (0, 0), with the zoom at 1. In every other case the camera either gets stuck or shows the empty space outside of the bounds.
With a 320×180 fixed resolution camera:
- Bounds centered on the origin,
Rectangle.fromLTRB(-245, -146, 245, 146): the camera can only move ±37.5 × ±17 away from (0, 0), so it barely moves while the player walks off-screen. - Bounds away from the origin,
Rectangle.fromLTWH(1600, 960, 490, 292): the region is(960, 570)to(2730, 1642), far larger than the bounds themselves. In its top-left corner, none of the level is visible at all. - Zoom other than 1: the viewport's size is subtracted, not the size of the world region that is visible through it. With
Rectangle.fromLTWH(0, 0, 490, 292), at zoom 2 the camera stops at (160, 90) instead of (80, 45), so the corners of the level can't be seen. At zoom 0.8 it shows 40 units past the left edge and 22.5 past the top. - Bounds smaller than the view,
Rectangle.fromLTWH(0, 0, 138, 100): the size passed toRectangle.fromCenteris negative, whichRectangle.fromPointsflips into a regular rectangle. The camera moves around inside the room instead of staying centered on it. - Circles:
Circle(Vector2.zero(), 376)gives a radius of 28, so the camera barely moves, andCircle(Vector2.zero(), 300)throwsRadius cannot be negative: -10.0. Even with the right size, the radius is only reduced by half of the viewport's longer side, which lets the viewport's corners leave the circle.
https://github.com/user-attachments/assets/6521d5a6-5a13-46ac-b1bc-c39d60d07c4a
https://github.com/user-attachments/assets/45949372-36b3-42cb-94fa-765ba042344b
https://github.com/user-attachments/assets/7dbe69de-e4d8-499f-b209-fe765e6930af
https://github.com/user-attachments/assets/46eb7ff3-f873-43c3-abf0-90827740a69f
https://github.com/user-attachments/assets/3583f56a-02af-4d68-a177-8888f68e3b27
What do you expect?
The camera can move as far as possible while the whole visible region stays inside the bounds, wherever the bounds are and at any zoom. With the same 320×180 camera:
Rectangle.fromLTRB(-245, -146, 245, 146): the camera stays within(-85, -56)to(85, 56).Rectangle.fromLTWH(1600, 960, 490, 292): within(1760, 1050)to(1930, 1162).Rectangle.fromLTWH(0, 0, 490, 292)at zoom 2: within(80, 45)to(410, 247).- Bounds smaller than the view: the camera stays at the center of the bounds along that axis.
Circle(Vector2.zero(), 376): within a radius of about 192.4, so none of the viewport's corners leave the circle.
How can we reproduce this?
- Create a camera with
CameraComponent.withFixedResolution(width: 320, height: 180). - Call
camera.setBounds(Rectangle.fromLTRB(-245, -146, 245, 146), considerViewport: true). - Move the camera towards the top-left corner, for example with
camera.moveTo(Vector2(-10000, -10000)). - The camera stops at (-37.5, -17) instead of (-85, -56), and the corner of the bounds is off-screen.
What steps should take to fix this?
_calculateViewportAwareBounds (viewport_aware_bounds_behavior.dart#L77-L118) calculates the size of the bounds like this:
_boundsShape
.support(
_boundsShape.nearestPoint(
_boundsShape.center + Vector2(1, 0),
),
)
.x,
support takes a direction, but it is given a point here, and .x of the result is the x coordinate of the right edge, not the width. The two are only the same when the bounds start at x = 0. The viewport's virtualSize is then subtracted without taking the zoom into account, and a negative result isn't clamped.
The region will be calculated from the shape's aabb and the size of the world region visible through the viewport, which is virtualSize / zoom, taking the viewfinder's angle into account. It is clamped at zero, so that it collapses to the center of the bounds when they are smaller than the view. For circles, the radius will be reduced by half of the visible region's diagonal, so that the corners of the viewport stay inside.
Do have an example of where the bug occurs?
import 'dart:ui';
import 'package:flame/camera.dart';
import 'package:flame/components.dart';
import 'package:flame/experimental.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart' show Colors;
import 'package:flutter/widgets.dart';
void main() => runApp(GameWidget(game: ReproGame()));
class ReproGame extends FlameGame {
ReproGame()
: super(
camera: CameraComponent.withFixedResolution(width: 320, height: 180),
);
// The other cases:
// Rectangle.fromLTWH(1600, 960, 490, 292)
// Rectangle.fromLTWH(0, 0, 490, 292), with camera.viewfinder.zoom = 2
// Rectangle.fromLTWH(0, 0, 138, 100)
// Circle(Vector2.zero(), 300)
final Shape level = Rectangle.fromLTRB(-245, -146, 245, 146);
@override
Future<void> onLoad() async {
final aabb = level.aabb;
world.add(
RectangleComponent(
position: aabb.min,
size: aabb.max - aabb.min,
paint: Paint()..color = Colors.brown,
),
);
camera.setBounds(level, considerViewport: true);
// Look at the top-left corner of the level.
camera.moveTo(Vector2(-10000, -10000));
}
}
Expected: the top-left corner of the level is at the top-left corner of the screen. Actual: the camera stops at (-37.5, -17), and the corner is off-screen. The other cases show the empty space next to the level, can't reach its corners, or throw.
Relevant log output
# With Circle(Vector2.zero(), 300), otherwise nothing is logged or thrown.
'package:flame/src/experimental/geometry/shapes/circle.dart': Failed assertion: line 20 pos 17: '_radius >= 0': Radius cannot be negative: -10.0
Execute in a terminal and put output into the code block below
[√] Flutter (Channel stable, 3.47.9, on Microsoft Windows [Version 10.0.22631.6199], locale en-US)
• Flutter version 3.47.9 on channel stable
• Framework revision c197ca5199 (4 days ago), 2026-10-29 10:10:20 -0400
• Engine revision 89c39edfdf
• Dart version 3.13.7
• DevTools version 2.60.0
[√] Windows Version (11 Pro 64-bit, 23H2, 2009)
[√] Android toolchain - develop for Android devices (Android SDK version 36.1.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Community 2026 18.11.2)
[√] Connected device (3 available)
[√] Network resources
• No issues found!
Affected platforms
All
Are you interested in working on a PR for this?
- I want to work on this
- 主要语言
- Dart
- 星标
- 10.8k
- 派生
- 1.1k
- 平均合并
- 1 天 22 小时
- 30 天内合并 PR
- 54
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
flame-engine/flame 的其他 Issue
-
`UniformsSetter.setColor` sends every color to the shader as black可能已有人在做 @ufrshubham 于 2 天前认领。 未关闭bug
flame-engine/flame#4211 · 已指派 1 人 ·
维护者通常 1 天内回复
-
`Viewfinder.visibleGameSize` is not reapplied when the viewport changes size可能已有人在做 @ufrshubham 于 4 天前认领。 未关闭bug
flame-engine/flame#4204 · 已指派 1 人 ·
维护者通常 1 天内回复
-
`Viewfinder.visibleGameSize` zooms in too far with a `FixedResolutionViewport`可能已有人在做 @ufrshubham 于 4 天前认领。 未关闭bug
flame-engine/flame#4203 · 已指派 1 人 ·
维护者通常 1 天内回复
-
Camera bounds with `considerViewport: true` are not updated when the viewport is resized可能已有人在做 @ufrshubham 于 4 天前认领。 未关闭bug
flame-engine/flame#4202 · 已指派 1 人 ·
维护者通常 1 天内回复
-
`findPostProcessFromContext` returns `null` for components rendered with `CameraComponent.postProcess`可能已有人在做 @ufrshubham 于 4 天前认领。 未关闭bug
flame-engine/flame#4200 · 已指派 1 人 ·
维护者通常 1 天内回复
查看 flame-engine/flame 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 82/100
customerio/customerio-flutter#441 ·
维护者通常 2 天内回复
-
JsonParseNode.getObjectValue returns non-null model on null JSON nodes and duplicates lifecycle hooks可能已有人在做 @hardikkaurani 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 76/100
microsoft/kiota-dart#170 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 77/100
fable-compiler/Fable#5280 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 74/100
immich-app/immich#33043 ·
维护者通常 1 天内回复
-
[FR] 希望能折叠搜索历史未关闭enhancement
难度 2/5 1-3 小时 新手友好度 68/100
bggRGjQaUbCoE/PiliPlus#3503 ·
维护者通常 1 天内回复