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

View File

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

View File

@ -115,5 +115,41 @@ void main() {
expect(testBlock.endCounter, 0); 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);
},
});
}); });
} }