Children are not ordered by priority following add and remove
Current bug behavior
After a particular sequence of adding and removing component children with different priority values, the children will become ordered incorrectly resulting in incorrect rendering.
Expected behavior
Children are always ordered and rendered by priority.
Steps to reproduce
The following example reproduces the issue on flame 1.14.0:
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
GameWidget(
game: MyGame(),
),
);
}
class MyGame extends FlameGame {
@override
Future<void> onLoad() async {
camera.viewport.add(ButtonComponent(
button: TextComponent(text: 'Go'),
onPressed: () async {
final redCircle = CircleComponent(
position: Vector2(-512, 0),
radius: 128,
priority: 10,
paint: Paint()..color = const Color(0xffff0000),
);
await world.add(redCircle);
await Future.delayed(const Duration(seconds: 1));
final greenCircle = CircleComponent(
position: Vector2(0, 0),
radius: 128,
priority: 9,
paint: Paint()..color = const Color(0xff00ff00),
);
await world.add(greenCircle);
await Future.delayed(const Duration(seconds: 1));
final yellowCircle = CircleComponent(
position: Vector2(-512, 0),
radius: 128,
priority: 10,
paint: Paint()..color = const Color(0xff0000ff),
);
world.remove(redCircle);
await world.add(yellowCircle);
await Future.delayed(const Duration(seconds: 1));
final purpleCircle = CircleComponent(
position: Vector2(64, 0),
radius: 128,
priority: 8,
paint: Paint()..color = const Color(0xffff00ff),
);
await world.add(purpleCircle);
await Future.delayed(const Duration(seconds: 1));
print(world.children.map((p) => p.priority).toList());
// Outputs:
// [9, 8, 10]
},
));
}
}
After the sequence is done:
- Children are no longer in priority order.
- The purple circle (priority 8) is incorrectly rendered on top of the green circle (priority 9).
Note if we then call world.children.rebalanceAll() the children become ordered correctly again.
Flutter doctor output
[✓] Flutter (Channel stable, 3.13.9, on macOS 14.2.1 23C71 darwin-arm64, locale en-US)
• Flutter version 3.13.9 on channel stable at /opt/homebrew/Caskroom/flutter/3.13.7/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision d211f42860 (3 months ago), 2023-10-25 13:42:25 -0700
• Engine revision 0545f8705d
• Dart version 3.1.5
• DevTools version 2.25.0
And they are not in the correct order after the next update tick has passed?
They remain in the incorrect order until world.children.rebalanceAll() is called.
Found the same issue after several hours investigation. New children are added to end of render queue ignoring old children higher priority.
This was a really nasty bug, it was all the way down in the OrderedSet package. It is now solved at least and we'll soon release a version of OrderedSet that includes it.
You can run pub upgrade in you projects to use the new version of ordered_set (v5.0.3).
Please write in here once you've confirmed that it works like it should. :)