I'm currently playing with flame, a small 2D game engine based on flutter. My code contains a rather strange Heisenbug: It works fine if you start it via run or debug. But if you set a breakpoint, it throws an error
Unhandled exception:
NoSuchMethodError: The getter 'cls' was called on null.
Although I don't think that this is related to flame, I was not able to reproduce the problem with flutter alone. So I'm including a minimal version of my flame-based code. It simply paints the phone-screen with a gray background color:
main.dart:
import 'package:flutter/material.dart';
import 'package:temp/game.dart';
void main(){
MyGame game = MyGame(); // error thrown here
runApp(game.widget);
}
game.dart:
import 'package:flame/game.dart';
import 'dart:ui';
class MyGame extends Game{
Size screenSize;
#override
void render(Canvas canvas) {
Rect screenRect = Rect.fromLTWH(0, 0, screenSize.width, screenSize.height);
Paint screenPaint = Paint();
screenPaint.color = Color.fromARGB(255, 100, 100, 100);
canvas.drawRect(screenRect, screenPaint);
}
#override
void update(double t) {
}
#override
void resize(Size size) {
super.resize(size);
screenSize = size;
}
}
If you want to run this, you also have to add flame to your pubspec:
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
flame: ^0.10.2
My bug happens everytime I set a breakpoint in the render method of MyGame and start debugging.
I can not reproduce this on flame: ^0.22.0 so you can just upgrade to that version and it should work fine.
Related
I want to play an audio as the app background music(without button click/autoplay). The code seen like no problem, but cant display.Did I do anything wrong with the code?
import 'package:flutter/material.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flame_audio/flame_audio.dart';
import 'package:flutter/widgets.dart';
void main() {
runApp(GameWidget(game: Audio()));
}
class Audio extends FlameGame with TapDetector {
#override
Future<void> onLoad() async {
super.onLoad();
}
#override
void onTapUp(TapUpInfo) {
FlameAudio.bgm.play('assets/Sound3.mp3');
}
}
pubspec.yaml
assets:
- assets/Sound3.mp3
[The Error Show in C:\flutter_windows_2.10.4-stable\flutter\packages\flutter\lib\src\services\asset_bundle.dart][1]
[1]: https://i.stack.imgur.com/p383i.png
const AssetImage('icons/heart.png', package: 'my_icons');
Assets used by the package (or plugin) itself should also be fetched using the package argument.
line: https://docs.flutter.dev/development/ui/assets-and-images
Is it possible to navigate out of a Flame Engine game widget into other Flutter widgets?
The app below immediately loads the game widget. How can navigation outside of the Game widget to another Flutter widget be achieved?
Flutter version: 2.2.3
Dart version: 2.13.4
Flame Engine version: flame-1.0.0-rc8
main.dart
import 'package:flame/flame.dart';
import 'package:flame/game.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:my_game.dart';
void main() {
runApp(
GameWidget(
game: MyGame(),
),
);
}
my_game.dart
import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flame/gestures.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class MyGame extends BaseGame with TapDetector {
#override
void update(double dt) { /* TODO */ }
#override
void render(Canvas canvas) { /* TODO */ }
#override
void onTapUp(TapUpDetails details) {
// How to navigate outside of the game widget?
}
}
You can do two things:
Either put the GameWidget in a Stack and handle navigation by Navigator from Flutter and remove and add the GameWidget to the widget tree when deemed necessary. Flutter Navigation docs
Use the Overlays API in Flame to handle the state from within Flame instead. Flame docs
For using the overlays you add the overlays that you want to have accessible when you create the GameWidget and then you call game.overlays.add to render a specific widget, and game.overlays.remove to stop rendering it.
I do recommend that you upgrade from rc8 to rc13, since the docs are for that version and things are more stable in general.
I'm Migrating to flame v1.0.0-rc8 from flame v0.29.4
and I can't find a good roadmap of how to get the initialDimensions, how to get the engine widget via engine.widget, how to init the Sprite object (Previously via Sprite('path_to_asset_file')), and how to set the width and height for SpriteComponent (Previously via SpriteComponent.rectangle).
These are several questions, so I'll give several answers:
How to get the inititialDimensions?
inititialDimensions is no longer needed, onGameResize is called before onLoad which will give you the size of the game. You can also get the size of the game by adding the HasGameRef mixin to your Components and call gameRef.size.
How to get the flutter widget?
You now wrap your game inside of a GameWidget instead of using .widget:
import 'package:flutter/material.dart';
import 'package:flame/game.dart';
void main() {
final myGame = MyGame();
runApp(
GameWidget(
game: myGame,
),
);
}
How to initialize a Sprite?
You usually want a SpriteComponent, and not a raw Sprite.
To create a Sprite:
class MyGame extends FlameGame {
Sprite player;
#override
Future<void> onLoad() async {
player = Sprite.load('player.png');
}
}
To create a SpriteComponent:
class MyGame extends FlameGame {
SpriteComponent player;
#override
Future<void> onLoad() async {
final sprite = await loadSprite('player.png');
player = SpriteComponent(sprite: sprite);
// And you usually want to add your component to the game too.
add(player);
}
}
How to set the size of a component?
Simply do component.size = Vector2(width, height); or component.width = width; + component.height = height
What should I do to apply my background image in my project? Did I miss something? My background image found under lib/assets/background.jpg
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Util flameUtil = Util();
await flameUtil.fullScreen();
await flameUtil.setOrientation(DeviceOrientation.portraitUp);
LangawGame game = LangawGame();
runApp(game.widget);
}
langaw-game.dart
class LangawGame extends Game {
Size screenSize;
double tileSize;
#override
void render(Canvas canvas) {
body:
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/background.jpg"),
fit: BoxFit.cover,
),
),
);
}
#override
void update(double t) {}
#override
void resize(Size size) {
super.resize(size);
screenSize = size;
tileSize = screenSize.width / 9;
}
}
This is the result
This is the background
i dont have error receive but the image didnt refect
Your image path is not correct. Now your image is under lib/assets folder, but you are trying to access assets/background.jpg. You need to edit with a full path like following:
AssetImage("lib/assets/background.jpg"),
Note: Also, check your pubspec.yaml file.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add Flutter specific assets to your application, add an assets section,
# like this:
assets:
- lib/assets/background.jpg
Read more from the official document.
make sure in pubspec.yaml indention is correct.
flutter
1 tab for assets:
2 tabs for -assets/
Hope this helps
When removing system overlays with SystemChrome.setEnabledSystemUIOverlays([]) the app does not expand to fill the screen.
Complete main.dart file:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setEnabledSystemUIOverlays([]);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Container(
color: Colors.red,
),
);
}
}
Without SystemChrome.setEnabledSystemUIOverlays([]):
Flutter version: 1.22.2
I'm unable to reproduce with Flutter 1.22(stable) but in https://github.com/flutter/flutter/issues/14432 people seem to have had good results with
setting Scaffold.resizeToAvoidBottomPadding to true.
You can also try to update Flutter and/or changing channels. Perhaps even trying on a physical device.