mirror of https://github.com/flutter/pinball.git
feat: adding camera zoom effect (#153)
* feat: adding camera zoom effect * testing ci * testing ci * Apply suggestions from code review Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> * testing ci * testing ci * ci * feat: pr suggestion * fix: lint * fix: lint * Apply suggestions from code review Co-authored-by: Alejandro Santiago <dev@alestiago.com> Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> Co-authored-by: Alejandro Santiago <dev@alestiago.com>pull/162/head
parent
2f40dcc971
commit
daebb0b749
@ -0,0 +1,56 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame/effects.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// {@template camera_zoom}
|
||||||
|
/// Applies zoom to the camera of the game where this is added to
|
||||||
|
/// {@endtemplate}
|
||||||
|
class CameraZoom extends Effect with HasGameRef {
|
||||||
|
/// {@macro camera_zoom}
|
||||||
|
CameraZoom({
|
||||||
|
required this.value,
|
||||||
|
}) : super(
|
||||||
|
EffectController(
|
||||||
|
duration: 0.4,
|
||||||
|
curve: Curves.easeOut,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
/// The total zoom value to be applied to the camera
|
||||||
|
final double value;
|
||||||
|
|
||||||
|
late final Tween<double> _tween;
|
||||||
|
|
||||||
|
final Completer<void> _completer = Completer();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
_tween = Tween(
|
||||||
|
begin: gameRef.camera.zoom,
|
||||||
|
end: value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void apply(double progress) {
|
||||||
|
gameRef.camera.zoom = _tween.transform(progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a [Future] that completes once the zoom is finished
|
||||||
|
Future<void> get completed {
|
||||||
|
if (controller.completed) {
|
||||||
|
return Future.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _completer.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onRemove() {
|
||||||
|
_completer.complete();
|
||||||
|
|
||||||
|
super.onRemove();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame/input.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
import 'package:sandbox/common/common.dart';
|
||||||
|
|
||||||
|
class BasicCameraZoomGame extends BasicGame with TapDetector {
|
||||||
|
static const info = '''
|
||||||
|
Simple game to demonstrate how the CameraZoom can be used.
|
||||||
|
Tap to zoom in/out
|
||||||
|
''';
|
||||||
|
|
||||||
|
bool zoomApplied = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
final sprite = await loadSprite(Assets.images.flutterSignPost.keyName);
|
||||||
|
|
||||||
|
await add(
|
||||||
|
SpriteComponent(
|
||||||
|
sprite: sprite,
|
||||||
|
size: Vector2(4, 8),
|
||||||
|
anchor: Anchor.center,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
camera.followVector2(Vector2.zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onTap() {
|
||||||
|
if (firstChild<CameraZoom>() == null) {
|
||||||
|
final zoom = CameraZoom(value: zoomApplied ? 30 : 10);
|
||||||
|
add(zoom);
|
||||||
|
zoomApplied = !zoomApplied;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
import 'package:dashbook/dashbook.dart';
|
||||||
|
import 'package:flame/game.dart';
|
||||||
|
import 'package:sandbox/common/common.dart';
|
||||||
|
import 'package:sandbox/stories/zoom/basic_zoom_game.dart';
|
||||||
|
|
||||||
|
void addZoomStories(Dashbook dashbook) {
|
||||||
|
dashbook.storiesOf('CameraZoom').add(
|
||||||
|
'Basic',
|
||||||
|
(context) => GameWidget(
|
||||||
|
game: BasicCameraZoomGame(),
|
||||||
|
),
|
||||||
|
codeLink: buildSourceLink('zoom/basic_zoom_game.dart'),
|
||||||
|
info: BasicCameraZoomGame.info,
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
// ignore_for_file: cascade_invocations
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
import '../../helpers/helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('CameraZoom', () {
|
||||||
|
final tester = FlameTester(TestGame.new);
|
||||||
|
|
||||||
|
tester.testGameWidget(
|
||||||
|
'renders correctly',
|
||||||
|
setUp: (game, tester) async {
|
||||||
|
game.camera.followVector2(Vector2.zero());
|
||||||
|
game.camera.zoom = 10;
|
||||||
|
final sprite = await game.loadSprite(
|
||||||
|
Assets.images.flutterSignPost.keyName,
|
||||||
|
);
|
||||||
|
|
||||||
|
await game.add(
|
||||||
|
SpriteComponent(
|
||||||
|
sprite: sprite,
|
||||||
|
size: Vector2(4, 8),
|
||||||
|
anchor: Anchor.center,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await game.add(CameraZoom(value: 40));
|
||||||
|
},
|
||||||
|
verify: (game, tester) async {
|
||||||
|
await expectLater(
|
||||||
|
find.byGame<TestGame>(),
|
||||||
|
matchesGoldenFile('golden/camera_zoom/no_zoom.png'),
|
||||||
|
);
|
||||||
|
|
||||||
|
game.update(0.2);
|
||||||
|
await tester.pump();
|
||||||
|
await expectLater(
|
||||||
|
find.byGame<TestGame>(),
|
||||||
|
matchesGoldenFile('golden/camera_zoom/in_between.png'),
|
||||||
|
);
|
||||||
|
|
||||||
|
game.update(0.4);
|
||||||
|
await tester.pump();
|
||||||
|
await expectLater(
|
||||||
|
find.byGame<TestGame>(),
|
||||||
|
matchesGoldenFile('golden/camera_zoom/finished.png'),
|
||||||
|
);
|
||||||
|
game.update(0.1);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(game.firstChild<CameraZoom>(), isNull);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
tester.test(
|
||||||
|
'completes when checked after it is finished',
|
||||||
|
(game) async {
|
||||||
|
await game.add(CameraZoom(value: 40));
|
||||||
|
game.update(10);
|
||||||
|
final cameraZoom = game.firstChild<CameraZoom>();
|
||||||
|
final future = cameraZoom!.completed;
|
||||||
|
|
||||||
|
expect(future, completes);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
tester.test(
|
||||||
|
'completes when checked before it is finished',
|
||||||
|
(game) async {
|
||||||
|
final zoom = CameraZoom(value: 40);
|
||||||
|
final future = zoom.completed;
|
||||||
|
|
||||||
|
await game.add(zoom);
|
||||||
|
game.update(10);
|
||||||
|
game.update(0);
|
||||||
|
|
||||||
|
expect(future, completes);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 31 KiB |
Loading…
Reference in new issue