Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Fix SpriteBatch to comply with new drawAtlas requirement #3338

Merged
merged 11 commits into from
Oct 13, 2024
5 changes: 5 additions & 0 deletions examples/lib/stories/sprites/sprite_batch_load_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ class SpriteBatchLoadExample extends FlameGame {

class MySpriteBatchComponent extends SpriteBatchComponent
with HasGameReference<SpriteBatchLoadExample> {
MySpriteBatchComponent()
: super(
blendMode: BlendMode.srcOver,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blend mode is now mandatory when using colors

);

@override
Future<void> onLoad() async {
final spriteBatch = await game.loadSpriteBatch('boom.png');
Expand Down
20 changes: 12 additions & 8 deletions packages/flame/lib/src/sprite_batch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,7 @@ class SpriteBatch {

_sources[index] = newBatchItem.source;
_transforms[index] = newBatchItem.transform;
if (color != null) {
_colors[index] = color;
}
_colors[index] = color ?? _defaultColor;
}

/// Add a new batch item using a RSTransform.
Expand Down Expand Up @@ -328,9 +326,7 @@ class SpriteBatch {
: batchItem.source,
);
_transforms.add(batchItem.transform);
if (color != null) {
_colors.add(color);
}
_colors.add(color ?? _defaultColor);
}

/// Add a new batch item.
Expand Down Expand Up @@ -413,13 +409,19 @@ class SpriteBatch {

final renderPaint = paint ?? _emptyPaint;

final hasNoColors = _colors.every((c) => c == _defaultColor);
final actualBlendMode = blendMode ?? defaultBlendMode;
if (!hasNoColors && actualBlendMode == null) {
throw 'When setting any colors, a blend mode must be provided.';
}

if (useAtlas && !_flippedAtlasStatus.isGenerating) {
canvas.drawAtlas(
atlas,
_transforms,
_sources,
_colors.isEmpty ? null : _colors,
blendMode ?? defaultBlendMode,
hasNoColors ? null : _colors,
actualBlendMode,
cullRect,
renderPaint,
);
Expand All @@ -441,4 +443,6 @@ class SpriteBatch {
}
}
}

static const _defaultColor = Color(0x00000000);
}
Binary file added packages/flame/test/_goldens/sprite_batch_test.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/flame/test/_goldens/sprite_batch_test_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/flame/test/_goldens/sprite_batch_test_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/flame/test/_resources/boom.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions packages/flame/test/sprite_batch_test.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import 'dart:ui';

import 'package:flame/components.dart';
import 'package:flame/sprite.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter/material.dart' hide Image;
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';

import '_resources/load_image.dart';

class _MockImage extends Mock implements Image {}

void main() {
Expand Down Expand Up @@ -56,5 +60,68 @@ void main() {
.having((t) => t.ty, 'ty', 1),
);
});

const margin = 2.0;
const tileSize = 6.0;

testGolden(
'can render a batch with blend mode',
(game) async {
final spriteSheet = await loadImage('alphabet.png');
final spriteBatch = SpriteBatch(spriteSheet);

const source = Rect.fromLTWH(3 * tileSize, 0, tileSize, tileSize);

spriteBatch.add(
source: source,
color: Colors.redAccent,
offset: Vector2.all(margin),
);

spriteBatch.add(
source: source,
offset: Vector2(2 * margin + tileSize, margin),
);

game.add(
SpriteBatchComponent(
spriteBatch: spriteBatch,
blendMode: BlendMode.srcOver,
),
);
},
size: Vector2(3 * margin + 2 * tileSize, 2 * margin + tileSize),
backgroundColor: const Color(0xFFFFFFFF),
goldenFile: '_goldens/sprite_batch_test_1.png',
);

testGolden(
'can render a batch without blend mode',
(game) async {
final spriteSheet = await loadImage('alphabet.png');
final spriteBatch = SpriteBatch(spriteSheet);

const source = Rect.fromLTWH(3 * tileSize, 0, tileSize, tileSize);

spriteBatch.add(
source: source,
offset: Vector2.all(margin),
);

spriteBatch.add(
source: source,
offset: Vector2(2 * margin + tileSize, margin),
);

game.add(
SpriteBatchComponent(
spriteBatch: spriteBatch,
),
);
},
size: Vector2(3 * margin + 2 * tileSize, 2 * margin + tileSize),
backgroundColor: const Color(0xFFFFFFFF),
goldenFile: '_goldens/sprite_batch_test_2.png',
);
});
}
15 changes: 14 additions & 1 deletion packages/flame_test/lib/src/test_golden.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,17 @@ void testGolden(
PrepareGameFunction testBody, {
required String goldenFile,
Vector2? size,
Color? backgroundColor,
FlameGame? game,
bool skip = false,
}) {
testWidgets(
testName,
(tester) async {
final gameInstance = game ?? FlameGame();
final gameInstance = game ??
(backgroundColor != null
? GameWithBackgroundColor(backgroundColor)
: FlameGame());
const myKey = ValueKey('game-instance');

await tester.runAsync(() async {
Expand Down Expand Up @@ -73,3 +77,12 @@ void testGolden(
}

typedef PrepareGameFunction = Future<void> Function(FlameGame game);

class GameWithBackgroundColor extends FlameGame {
final Color _backgroundColor;

GameWithBackgroundColor(this._backgroundColor);

@override
Color backgroundColor() => _backgroundColor;
}