import 'dart:async'; import 'dart:ui'; import 'package:flame/vector.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/services.dart'; import 'package:flutter/foundation.dart'; /// Some utilities that did not fit anywhere else. /// /// To use this class, access it via [Flame.util]. class Util { /// Sets the app to be fullscreen (no buttons bar os notifications on top). /// /// Most games should probably be this way. Future fullScreen() { if (kIsWeb) { return Future.value(); } return SystemChrome.setEnabledSystemUIOverlays([]); } /// Sets the preferred orientation (landscape or portrait) for the app. /// /// When it opens, it will automatically change orientation to the preferred one (if possible) depending on the physical orientation of the device. Future setOrientation(DeviceOrientation orientation) { if (kIsWeb) { return Future.value(); } return SystemChrome.setPreferredOrientations( [orientation], ); } /// Sets the preferred orientations (landscape left, right, portrait up, or down) for the app. /// /// When it opens, it will automatically change orientation to the preferred one (if possible) depending on the physical orientation of the device. Future setOrientations(List orientations) { if (kIsWeb) { return Future.value(); } return SystemChrome.setPreferredOrientations(orientations); } /// Sets the preferred orientation of the app to landscape only. /// /// When it opens, it will automatically change orientation to the preferred one (if possible). Future setLandscape() { return setOrientations([ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); } /// Sets the preferred orientation of the app to `DeviceOrientation.landscapeLeft` only. /// /// When it opens, it will automatically change orientation to the preferred one (if possible). Future setLandscapeLeftOnly() { return setOrientation(DeviceOrientation.landscapeLeft); } /// Sets the preferred orientation of the app to `DeviceOrientation.landscapeRight` only. /// /// When it opens, it will automatically change orientation to the preferred one (if possible). Future setLandscapeRightOnly() { return setOrientation(DeviceOrientation.landscapeRight); } /// Sets the preferred orientation of the app to portrait only. /// /// When it opens, it will automatically change orientation to the preferred one (if possible). Future setPortrait() { return setOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); } /// Sets the preferred orientation of the app to `DeviceOrientation.portraitUp` only. /// /// When it opens, it will automatically change orientation to the preferred one (if possible). Future setPortraitUpOnly() { return setOrientation(DeviceOrientation.portraitUp); } /// Sets the preferred orientation of the app to `DeviceOrientation.portraitDown` only. /// /// When it opens, it will automatically change orientation to the preferred one (if possible). Future setPortraitDownOnly() { return setOrientation(DeviceOrientation.portraitDown); } /// Waits for the initial screen dimensions to be available. /// /// Because of flutter's issue [#5259](https://github.com/flutter/flutter/issues/5259), when the app starts the size might be 0x0. /// This waits for the information to be properly updated. /// /// A best practice would be to implement there resize hooks on your game and components and don't use this at all. /// Make sure your components are able to render and update themselves for any possible screen size. Future initialDimensions() async { // https://github.com/flutter/flutter/issues/5259 // "In release mode we start off at 0x0 but we don't in debug mode" return await Future(() { if (window.physicalSize.isEmpty) { final completer = Completer(); window.onMetricsChanged = () { if (!window.physicalSize.isEmpty && !completer.isCompleted) { completer.complete(VectorUtil.fromSize( window.physicalSize / window.devicePixelRatio)); } }; return completer.future; } return VectorUtil.fromSize(window.physicalSize / window.devicePixelRatio); }); } /// This properly binds a gesture recognizer to your game. /// /// Use this in order to get it to work in case your app also contains other widgets. /// /// Read more at: https://flame-engine.org/docs/input.md /// @Deprecated( 'This method can lead to confuse behaviour, use the gestures methods provided by the Game class', ) void addGestureRecognizer(GestureRecognizer recognizer) { if (GestureBinding.instance == null) { throw Exception( 'GestureBinding is not initialized yet, this probably happened because addGestureRecognizer was called before the runApp method'); } GestureBinding.instance.pointerRouter.addGlobalRoute((PointerEvent e) { if (e is PointerDownEvent) { recognizer.addPointer(e); } }); } /// This properly removes the bind of a gesture recognizer to your game. /// /// Use this in order to clear any added recognizers that you have added before void removeGestureRecognizer(GestureRecognizer recognizer) { recognizer.dispose(); } /// Utility method to render stuff on a specific place. /// /// Some render methods don't allow to pass a offset. /// This method translate the canvas, draw what you want, and then translate back. void drawWhere(Canvas c, Vector2 p, void Function(Canvas) fn) { c.translate(p.x, p.y); fn(c); c.translate(-p.x, -p.y); } }