@@ -120,8 +120,8 @@ would apply their action even though the drag never finished. This is not a rare
120120with ` MultiDragScaleDispatcher ` every two finger pinch cancels the individual pointer drags.
121121
122122The default implementation now only resets ` isDragged ` , which means that ` onDragEnd ` is no longer
123- called when a drag is cancelled. If you were relying on the old behavior, override ` onDragCancel ` and
124- forward the event yourself with ` DragCancelEvent.toDragEnd ` :
123+ called when a drag is cancelled. If you were relying on the old behavior, override ` onDragCancel `
124+ and forward the event yourself with ` DragCancelEvent.toDragEnd ` :
125125
126126``` dart
127127// Before
@@ -223,6 +223,80 @@ The equivalent field on the deprecated `*Info` event classes (`TapDownInfo.handl
223223been removed as well.
224224
225225
226+ ### ` add ` , ` addAll ` and ` addToParent ` are now synchronous
227+
228+ ` Component.add ` , ` Component.addAll ` and ` Component.addToParent ` used to return a future, which made
229+ it look like you could await the addition. That future only covered the child's loading, never its
230+ mounting, so awaiting it was misleading, and forgetting to await it (or to wrap it in ` unawaited ` )
231+ tripped the ` discarded_futures ` lint in a lot of games. All three methods now return ` void ` .
232+
233+ Drop the ` await ` :
234+
235+ ``` dart
236+ // Before
237+ await add(MyComponent());
238+ await addAll([MyComponent(), MyOtherComponent()]);
239+
240+ // After
241+ add(MyComponent());
242+ addAll([MyComponent(), MyOtherComponent()]);
243+ ```
244+
245+ If you were relying on the returned future to know when the child had loaded, await the child's
246+ ` loaded ` future instead:
247+
248+ ``` dart
249+ // Before
250+ await add(crate);
251+
252+ // After
253+ add(crate);
254+ await crate.loaded;
255+ ```
256+
257+ For a batch of children, ` loaded ` , ` mounted ` and ` removed ` are also available on any
258+ ` Iterable<Component> ` :
259+
260+ ``` dart
261+ // Before
262+ await addAll(crates);
263+
264+ // After
265+ addAll(crates);
266+ await crates.loaded;
267+ ```
268+
269+ Or, when you need them to be present in ` children ` rather than just loaded, await
270+ ` game.lifecycleEventsProcessed ` once after adding them.
271+
272+
273+ #### Load errors are no longer reported by ` GameWidget.errorBuilder `
274+
275+ ` GameWidget.errorBuilder ` shows a widget when the * game's* loading fails, and it used to catch a
276+ failing child's ` onLoad ` as well, because ` await add(child) ` chained the child's error onto the
277+ game's own ` onLoad ` future. Since ` add ` no longer returns a future, that chain is gone: a child that
278+ throws in ` onLoad ` no longer reaches ` errorBuilder ` .
279+
280+ The component itself is not added to the tree, and the rest of the game keeps running. The error is
281+ reported through the child's ` loaded ` future, and if nothing is awaiting it, it is handed to the
282+ current ` Zone ` as an uncaught error.
283+
284+ To get the old behavior for a specific child, await its ` loaded ` future inside the parent's
285+ ` onLoad ` , which puts the error back onto the future ` errorBuilder ` watches:
286+
287+ ``` dart
288+ class MyGame extends FlameGame {
289+ @override
290+ Future<void> onLoad() async {
291+ final level = Level();
292+ world.add(level);
293+ // Throws here if Level.onLoad fails, so errorBuilder is shown.
294+ await level.loaded;
295+ }
296+ }
297+ ```
298+
299+
226300### ` GameWidget.controlled ` renamed to ` GameWidget.managed `
227301
228302The ` GameWidget.controlled ` constructor has been renamed to ` GameWidget.managed ` . The behavior is
0 commit comments