Skip to content

Commit

Permalink
feat: Add autoResize for SpriteGroupComponent (#2442)
Browse files Browse the repository at this point in the history
This PR adds an autoResize parameter to SpriteGroupComponent which will allow Flame users to control if the size of the component should be re-calculated to fit the size of current active sprite in the group. This new parameter auto-populates when not specified, based value of size while construction. If size is not given, autoResize will be true and vice-versa.

Caveat:
If someone goes and replaces the actual Sprite at a particular key within SpriteGroupComponent.sprites map and if that key is the current state, it will not trigger an auto-resize. This seems like a very unlikely use-case, so I am not worried about it too much.
  • Loading branch information
ufrshubham committed Mar 30, 2023
1 parent 5b5ff30 commit 1576bd8
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 6 deletions.
52 changes: 47 additions & 5 deletions packages/flame/lib/src/components/sprite_group_component.dart
Expand Up @@ -11,33 +11,64 @@ export '../sprite_animation.dart';
class SpriteGroupComponent<T> extends PositionComponent
with HasPaint
implements SizeProvider {
/// Key with the current playing animation
T? current;
T? _current;

/// Map with the available states for this sprite group
Map<T, Sprite>? sprites;

bool _autoResize;

/// Creates a component with an empty animation which can be set later
SpriteGroupComponent({
this.sprites,
this.current,
T? current,
bool? autoResize,
Paint? paint,
super.position,
super.size,
Vector2? size,
super.scale,
super.angle,
super.nativeAngle,
super.anchor,
super.children,
super.priority,
}) {
}) : assert(
(size == null) == (autoResize ?? size == null),
'''If size is set, autoResize should be false or size should be null when autoResize is true.''',
),
_current = current,
_autoResize = autoResize ?? size == null,
super(size: size ?? sprites?[current]?.srcSize) {
if (paint != null) {
this.paint = paint;
}
}

Sprite? get sprite => sprites?[current];

/// Returns the current group state.
T? get current => _current;

/// The the group state to given state.
///
/// Will update [size] if [autoResize] is true.
set current(T? value) {
_current = value;
_resizeToSprite();
}

/// Returns current value of auto resize flag.
bool get autoResize => _autoResize;

/// Sets the given value of autoResize flag.
///
/// Will update the [size] to fit srcSize of
/// current [sprite] if set to true.
set autoResize(bool value) {
_autoResize = value;
_resizeToSprite();
}

@override
@mustCallSuper
void onMount() {
Expand All @@ -60,4 +91,15 @@ class SpriteGroupComponent<T> extends PositionComponent
overridePaint: paint,
);
}

/// Updates the size to current [sprite]'s srcSize if [autoResize] is true.
void _resizeToSprite() {
if (_autoResize) {
if (sprite != null) {
size.setFrom(sprite!.srcSize);
} else {
size.setZero();
}
}
}
}
58 changes: 57 additions & 1 deletion packages/flame/test/components/sprite_group_component_test.dart
@@ -1,6 +1,6 @@
import 'package:flame/components.dart';
import 'package:flame_test/flame_test.dart';
import 'package:test/test.dart';
import 'package:flutter_test/flutter_test.dart';

enum _SpriteState {
idle,
Expand Down Expand Up @@ -34,4 +34,60 @@ Future<void> main() async {
expect(component.sprite, sprite2);
});
});

group('SpriteComponent.autoResize', () {
test('mutual exclusive with size while construction', () {
expect(
() => SpriteGroupComponent<_SpriteState>(
autoResize: true,
size: Vector2.all(2),
),
throwsAssertionError,
);

expect(
() => SpriteGroupComponent<_SpriteState>(autoResize: false),
throwsAssertionError,
);
});

test('default value set correctly when not provided explicitly', () {
final component1 = SpriteGroupComponent<_SpriteState>();
final component2 = SpriteGroupComponent<_SpriteState>(
size: Vector2.all(2),
);

expect(component1.autoResize, true);
expect(component2.autoResize, false);
});

test('resizes on current state change', () {
final sprite1 = Sprite(image);
final sprite2 = Sprite(image, srcSize: Vector2.all(15));

final component = SpriteGroupComponent<_SpriteState>(
sprites: {_SpriteState.idle: sprite1, _SpriteState.running: sprite2},
current: _SpriteState.idle,
);
expect(component.size, sprite1.srcSize);

component.current = _SpriteState.running;
expect(component.size, sprite2.srcSize);
});

test('resizes only when true', () {
final sprite1 = Sprite(image);
final sprite2 = Sprite(image, srcSize: Vector2.all(15));
final component = SpriteGroupComponent<_SpriteState>(
sprites: {_SpriteState.idle: sprite1, _SpriteState.running: sprite2},
current: _SpriteState.idle,
)..autoResize = false;

component.current = _SpriteState.running;
expect(component.size, sprite1.srcSize);

component.autoResize = true;
expect(component.size, sprite2.srcSize);
});
});
}

0 comments on commit 1576bd8

Please sign in to comment.