fix: The visibleGameSize should be based on viewport.virtualSize (#2945)

The `visibleGameSize` should be based on the virtual size of the
viewport, otherwise it won't work for `FixedResolutionViewport` for
example.
We noticed this when using the `ScreenHitbox` in a world that was looked
upon by a camera with a `FixedResolutionViewport`.
This commit is contained in:
Lukas Klingsbo
2023-12-21 17:42:07 +01:00
committed by GitHub
parent 093a702a76
commit bd130b711b
3 changed files with 54 additions and 18 deletions

View File

@ -2,41 +2,41 @@ import 'package:flame/collisions.dart';
import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flutter/material.dart' hide Image, Draggable;
class CirclesExample extends FlameGame with HasCollisionDetection, TapDetector {
class CirclesExample extends FlameGame {
static const description = '''
This example will create a circle every time you tap on the screen. It will
have the initial velocity towards the center of the screen and if it touches
another circle both of them will change color.
''';
@override
Future<void> onLoad() async {
add(ScreenHitbox());
CirclesExample()
: super(
camera: CameraComponent.withFixedResolution(width: 600, height: 400),
world: MyWorld(),
);
}
class MyWorld extends World with TapCallbacks, HasCollisionDetection {
MyWorld() : super(children: [ScreenHitbox()..debugMode = true]);
@override
void onTapDown(TapDownInfo info) {
add(MyCollidable(info.eventPosition.widget));
void onTapDown(TapDownEvent info) {
add(MyCollidable(position: info.localPosition));
}
}
class MyCollidable extends PositionComponent
with HasGameReference<CirclesExample>, CollisionCallbacks {
MyCollidable({super.position})
: super(size: Vector2.all(30), anchor: Anchor.center);
late Vector2 velocity;
final _collisionColor = Colors.amber;
final _defaultColor = Colors.cyan;
late ShapeHitbox hitbox;
MyCollidable(Vector2 position)
: super(
position: position,
size: Vector2.all(100),
anchor: Anchor.center,
);
@override
Future<void> onLoad() async {
final defaultPaint = Paint()
@ -46,8 +46,8 @@ class MyCollidable extends PositionComponent
..paint = defaultPaint
..renderShape = true;
add(hitbox);
final center = game.size / 2;
velocity = (center - position)..scaleTo(150);
velocity = -position
..scaleTo(50);
}
@override

View File

@ -152,7 +152,7 @@ class Viewfinder extends Component
Rect? visibleRect;
@protected
Rect computeVisibleRect() {
final viewportSize = camera.viewport.size;
final viewportSize = camera.viewport.virtualSize;
final currentTransform = transform;
currentTransform.globalToLocal(_zeroVector, output: _topLeft);
currentTransform.globalToLocal(viewportSize, output: _bottomRight);

View File

@ -115,5 +115,41 @@ void main() {
expect(testBlock.endCounter, 0);
},
});
runCollisionTestRegistry({
'collides with FixedResolutionViewport': (hasCollisionDetection) async {
final game = hasCollisionDetection as FlameGame;
game.camera = CameraComponent.withFixedResolution(
width: 100,
height: 100,
);
final testBlock = TestBlock(
Vector2.all(-50),
Vector2.all(2),
)..anchor = Anchor.center;
final screenHitbox = ScreenHitbox();
await game.world.addAll([screenHitbox, testBlock]);
await game.ready();
game.update(0);
expect(testBlock.startCounter, 1);
expect(testBlock.onCollisionCounter, 1);
expect(testBlock.endCounter, 0);
testBlock.position = Vector2.all(50);
game.update(0);
expect(testBlock.startCounter, 1);
expect(testBlock.onCollisionCounter, 2);
expect(testBlock.endCounter, 0);
testBlock.position = Vector2.all(0);
game.update(0);
expect(testBlock.startCounter, 1);
expect(testBlock.onCollisionCounter, 2);
expect(testBlock.endCounter, 1);
},
});
});
}