Flame onLoad vs constructor initialization - flutter

If I create a component in Flame like this:
class MyComponent extends PositionComponent {
MyComponent() {
// Option 1
}
#override
Future<void> onLoad() {
// Option 2
}
}
What difference does it make if I initialize my component in the constructor (Option 1) or the onLoad method (Option 2)?

If you have things that need to load before the component is added to the game, like an image for example, then you need to do that loading in onLoad so that the game knows that it shouldn't add your component to the game until everything in there is loaded. For example:
class MyComponent extends PositionComponent {
#override
Future<void> onLoad() async {
final sprite = await loadSprite('flame.png');
}
}
So to make your code consistent you can do all your initialization in onLoad, even if it is not needed for all your components.
Another good thing to know about onLoad is that if your are using the HasGameRef mixin the gameRef will be set to your component in onLoad, but not in the constructor.

Related

How to update the gravity in flutter flame forge2d?

I want to update the gravity according to some events in the game, but I can't find a way to change it after I initialise it in the super of the class Forge2DGame.
You have to use setGravity to change it.
For example:
class MyGame extends Forge2DGame with TapDetector {
#override
void onTap() {
world.setGravity(Vector2(0, 10));
}
}

How to detect screen boundaries with Flame in Flutter?

I want to detect when an object goes outside of the screen in Flame Flutter. I think there is two way to accomplish this either with Collidable mixin or with Forge2D. If possible explain it in both of them.
Flame version: flame: 1.0.0-releasecandidate.18
It is way overkill to use Forge2D for this (that complicates a lot of other things too). But you can use the built-in collision detection system, or you can check in the update-loop whether it is within the screen or not (this would be the most efficient).
By using the collision detection system we can use the built-in ScreenCollidable and you can do something like this:
class ExampleGame extends FlameGame with HasCollidables {
...
#override
Future<void> onLoad() async {
await super.onLoad();
add(ScreenCollidable());
}
}
class YourComponent extends PositionComponent with HasHitboxes, Collidable {
#override
Future<void> onLoad() async {
await super.onLoad();
// Change this if you want the components to collide with each other
// and not only the screen.
collidableType = CollidableType.passive;
addHitbox(HitboxRectangle());
}
// Do note that this doesn't work if the component starts
// to go outside of the screen but then comes back.
#override
void onCollisionEnd(Collidable other) {
if (other is ScreenCollidable) {
removeFromParent();
}
}
}
and by just calculating it in the update-loop:
class YourComponent extends PositionComponent with HasGameRef {
#override
void update(double dt) {
final topLeft = absoluteTopLeftPosition;
final gameSize = gameRef.size;
if(topLeft.x > gameSize.x || topLeft.y > gameSize.y) {
removeFromParent();
return;
}
final bottomRight = absolutePositionOfAnchor(Anchor.bottomRight);
if(bottomRight.x < 0 || bottomRight.y < 0) {
removeFromParent();
return;
}
}
}
I also recommend that you update to Flame 1.0.0 now when it is released. :)
There is no longer a Collidable mixin.
See the Flame documentation

What is the best way to define singleton properties in Flutter/Dart?

I am using flutter_easyLoading package for loaders in my flutter project. It says in the documentation that it creates a singleton and I have to define its properties only once somewhere and it would be available throughout the app. What is the best practice to define these properties?
Right now I am initializing its variables in a splash screen file like this.
class _SplashScreenState extends State<SplashScreen> {
#override
void didChangeDependencies() async {
super.didChangeDependencies();
EasyLoading.instance
..displayDuration = const Duration(milliseconds: 2000)
..indicatorType = EasyLoadingIndicatorType.fadingCircle
..loadingStyle = EasyLoadingStyle.dark;
}
Should I do it this way or maybe define some util method for all these properties.
You can use a factory constructor implement singleton classes in dart.
This is a simple example adapted to this context
class EasyLoadingSingleton {
static final EasyLoadingSingleton _easyloading = EasyLoadingSingleton._internal();
factory EasyLoadingSingleton() {
return _easyloading;
}
EasyLoadingSingleton._internal();
}

Flutter - How to call functions (and variables) between stateful widgets?

I have this function in a widget (homescreen):
void toggleRecording() async {
// HERE IS THE CONFUSION I GUESS
_isRecording = !_isRecording;
recorder = SoundStream(isRecording: _isRecording);
//recorder.toggleRecording(_isRecording);
setState(() {
_isRecording = recorder.isRecording;
});
if (_isRecording) {
startTimer();
_stopwatch.start();
} else {
stopTimer();
_stopwatch.stop();
}
}
It needs to call (trigger) another function in my recorder class:
void toggleRecording() async {
widget.isRecording ////// currently being passed as an argument from homescreen
? {_recorder.stop, await save(_micChunks, 44100)}
: _recorder.start;
}
Also, the boolean variable _isRecording is present in both the classes. How do I sync the state?
In your situation passing reference of function through widgets will work. However best practice of this will be using provider package.
Managing functions from provider will allow you to control functions from all pages.
If you change a variable you can call notifylistener() function inside your provider function. So that you can change state of widget.
I will try to explain it in a glance however this is an important subject of flutter.
Here is my folder structure
At provider folder we define our provider classes.
Firstly i define class which extends changeNotifier class. This is what make this class provider.
Side note: notifyListener() function here calls setState of every widget if you use any variables inside that class and this is what you are searching for.
Then i import it into my main.dart file or whatever file you want. Only condition is being above the widget that you will use provider at.
At last you can use your function at everywhere if you import provider package and define your provider like i did in this code.
At last here is the visualized stucture of provider package.
I wish i explained it well. There is more about it on youtube.
Pass the function to other widget
using Function keyword
Say ContentWidget is your child and ParentWidget is parent
class ParentWidget extends StatefulWidget {
//Do Something
void onSomeFunction()
{
ContentWidget(onTimerUpdate:onTimerClosed)
}
void onTimerClosed()
{
//Perform Operation on Timer Change
}
}
class ContentWidget extends StatefulWidget {
final Function onTimerUpdate;
ContentWidget({
Key key,
#required this.onTimerUpdate,
}) : super(key: key);
void onAnyActionFromChild()
{
widget.onTimerUpdate() //Note () can have any param or can be null
}

Migrating to flame v1.0.0

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