mirror of
https://github.com/flame-engine/flame.git
synced 2025-10-30 08:27:36 +08:00
feat: Adding paint attribute to SpriteWidget and SpriteAnimationWidget (#3298)
Adds a `Paint` attribute to the `SpriteWidget` and `SpriteAnimationWidget` for an improved API. --------- Co-authored-by: Lukas Klingsbo <me@lukas.fyi>
This commit is contained in:
28
examples/lib/stories/widgets/paints.dart
Normal file
28
examples/lib/stories/widgets/paints.dart
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
final paintChoices = [
|
||||||
|
'none',
|
||||||
|
'transparent',
|
||||||
|
'red tinted',
|
||||||
|
'green tinted',
|
||||||
|
'blue tinted',
|
||||||
|
];
|
||||||
|
final paintList = [
|
||||||
|
null,
|
||||||
|
Paint()..color = const Color(0x22FFFFFF),
|
||||||
|
Paint()
|
||||||
|
..colorFilter = const ColorFilter.mode(
|
||||||
|
Color(0x88FF0000),
|
||||||
|
BlendMode.srcATop,
|
||||||
|
),
|
||||||
|
Paint()
|
||||||
|
..colorFilter = const ColorFilter.mode(
|
||||||
|
Color(0x8800FF00),
|
||||||
|
BlendMode.srcATop,
|
||||||
|
),
|
||||||
|
Paint()
|
||||||
|
..colorFilter = const ColorFilter.mode(
|
||||||
|
Color(0x880000FF),
|
||||||
|
BlendMode.srcATop,
|
||||||
|
),
|
||||||
|
];
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import 'package:dashbook/dashbook.dart';
|
import 'package:dashbook/dashbook.dart';
|
||||||
|
import 'package:examples/stories/widgets/paints.dart';
|
||||||
import 'package:flame/extensions.dart';
|
import 'package:flame/extensions.dart';
|
||||||
import 'package:flame/widgets.dart';
|
import 'package:flame/widgets.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
@ -20,6 +21,13 @@ Widget spriteAnimationWidgetBuilder(DashbookContext ctx) {
|
|||||||
anchor: Anchor.valueOf(
|
anchor: Anchor.valueOf(
|
||||||
ctx.listProperty('anchor', 'center', anchorOptions),
|
ctx.listProperty('anchor', 'center', anchorOptions),
|
||||||
),
|
),
|
||||||
|
paint: paintList[paintChoices.indexOf(
|
||||||
|
ctx.listProperty(
|
||||||
|
'paint',
|
||||||
|
'none',
|
||||||
|
paintChoices,
|
||||||
|
),
|
||||||
|
)],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:dashbook/dashbook.dart';
|
import 'package:dashbook/dashbook.dart';
|
||||||
|
import 'package:examples/stories/widgets/paints.dart';
|
||||||
import 'package:flame/widgets.dart';
|
import 'package:flame/widgets.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@ -17,6 +18,13 @@ Widget spriteWidgetBuilder(DashbookContext ctx) {
|
|||||||
anchor: Anchor.valueOf(
|
anchor: Anchor.valueOf(
|
||||||
ctx.listProperty('anchor', 'center', anchorOptions),
|
ctx.listProperty('anchor', 'center', anchorOptions),
|
||||||
),
|
),
|
||||||
|
paint: paintList[paintChoices.indexOf(
|
||||||
|
ctx.listProperty(
|
||||||
|
'paint',
|
||||||
|
'none',
|
||||||
|
paintChoices,
|
||||||
|
),
|
||||||
|
)],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,10 @@ class SpriteAnimationWidget extends StatelessWidget {
|
|||||||
/// A callback that is called when the animation completes.
|
/// A callback that is called when the animation completes.
|
||||||
final VoidCallback? onComplete;
|
final VoidCallback? onComplete;
|
||||||
|
|
||||||
|
/// A custom [Paint] to be used when rendering the sprite.
|
||||||
|
/// When omitted the default paint from the [Sprite] class will be used.
|
||||||
|
final Paint? paint;
|
||||||
|
|
||||||
const SpriteAnimationWidget({
|
const SpriteAnimationWidget({
|
||||||
required SpriteAnimation animation,
|
required SpriteAnimation animation,
|
||||||
required SpriteAnimationTicker animationTicker,
|
required SpriteAnimationTicker animationTicker,
|
||||||
@ -38,6 +42,7 @@ class SpriteAnimationWidget extends StatelessWidget {
|
|||||||
this.errorBuilder,
|
this.errorBuilder,
|
||||||
this.loadingBuilder,
|
this.loadingBuilder,
|
||||||
this.onComplete,
|
this.onComplete,
|
||||||
|
this.paint,
|
||||||
super.key,
|
super.key,
|
||||||
}) : _animationFuture = animation,
|
}) : _animationFuture = animation,
|
||||||
_animationTicker = animationTicker;
|
_animationTicker = animationTicker;
|
||||||
@ -57,6 +62,7 @@ class SpriteAnimationWidget extends StatelessWidget {
|
|||||||
this.errorBuilder,
|
this.errorBuilder,
|
||||||
this.loadingBuilder,
|
this.loadingBuilder,
|
||||||
this.onComplete,
|
this.onComplete,
|
||||||
|
this.paint,
|
||||||
super.key,
|
super.key,
|
||||||
}) : _animationFuture = SpriteAnimation.load(path, data, images: images),
|
}) : _animationFuture = SpriteAnimation.load(path, data, images: images),
|
||||||
_animationTicker = null;
|
_animationTicker = null;
|
||||||
@ -74,6 +80,7 @@ class SpriteAnimationWidget extends StatelessWidget {
|
|||||||
animationTicker: ticker,
|
animationTicker: ticker,
|
||||||
anchor: anchor,
|
anchor: anchor,
|
||||||
playing: playing,
|
playing: playing,
|
||||||
|
paint: paint,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
errorBuilder: errorBuilder,
|
errorBuilder: errorBuilder,
|
||||||
@ -97,11 +104,14 @@ class InternalSpriteAnimationWidget extends StatefulWidget {
|
|||||||
/// Should the [animation] be playing or not
|
/// Should the [animation] be playing or not
|
||||||
final bool playing;
|
final bool playing;
|
||||||
|
|
||||||
|
final Paint? paint;
|
||||||
|
|
||||||
const InternalSpriteAnimationWidget({
|
const InternalSpriteAnimationWidget({
|
||||||
required this.animation,
|
required this.animation,
|
||||||
required this.animationTicker,
|
required this.animationTicker,
|
||||||
this.playing = true,
|
this.playing = true,
|
||||||
this.anchor = Anchor.topLeft,
|
this.anchor = Anchor.topLeft,
|
||||||
|
this.paint,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -193,6 +203,7 @@ class _InternalSpriteAnimationWidgetState
|
|||||||
painter: SpritePainter(
|
painter: SpritePainter(
|
||||||
widget.animationTicker.getSprite(),
|
widget.animationTicker.getSprite(),
|
||||||
widget.anchor,
|
widget.anchor,
|
||||||
|
widget.paint,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,16 +8,18 @@ import 'package:flutter/widgets.dart';
|
|||||||
class SpritePainter extends CustomPainter {
|
class SpritePainter extends CustomPainter {
|
||||||
final Sprite _sprite;
|
final Sprite _sprite;
|
||||||
final Anchor _anchor;
|
final Anchor _anchor;
|
||||||
|
final Paint? _paint;
|
||||||
final double _angle;
|
final double _angle;
|
||||||
|
|
||||||
SpritePainter(this._sprite, this._anchor, {double angle = 0})
|
SpritePainter(this._sprite, this._anchor, this._paint, {double angle = 0})
|
||||||
: _angle = angle;
|
: _angle = angle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool shouldRepaint(SpritePainter oldDelegate) {
|
bool shouldRepaint(SpritePainter oldDelegate) {
|
||||||
return oldDelegate._sprite != _sprite ||
|
return oldDelegate._sprite != _sprite ||
|
||||||
oldDelegate._anchor != _anchor ||
|
oldDelegate._anchor != _anchor ||
|
||||||
oldDelegate._angle != _angle;
|
oldDelegate._angle != _angle ||
|
||||||
|
oldDelegate._paint != _paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -33,12 +35,16 @@ class SpritePainter extends CustomPainter {
|
|||||||
canvas.translateVector(boxAnchorPosition..sub(spriteAnchorPosition));
|
canvas.translateVector(boxAnchorPosition..sub(spriteAnchorPosition));
|
||||||
|
|
||||||
if (_angle == 0) {
|
if (_angle == 0) {
|
||||||
_sprite.render(canvas, size: paintSize);
|
_sprite.render(canvas, size: paintSize, overridePaint: _paint);
|
||||||
} else {
|
} else {
|
||||||
canvas.renderRotated(
|
canvas.renderRotated(
|
||||||
_angle,
|
_angle,
|
||||||
spriteAnchorPosition,
|
spriteAnchorPosition,
|
||||||
(canvas) => _sprite.render(canvas, size: paintSize),
|
(canvas) => _sprite.render(
|
||||||
|
canvas,
|
||||||
|
size: paintSize,
|
||||||
|
overridePaint: _paint,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,10 @@ class SpriteWidget extends StatelessWidget {
|
|||||||
/// A builder function that is called while the loading is on the way
|
/// A builder function that is called while the loading is on the way
|
||||||
final WidgetBuilder? loadingBuilder;
|
final WidgetBuilder? loadingBuilder;
|
||||||
|
|
||||||
|
/// A custom [Paint] to be used when rendering the sprite.
|
||||||
|
/// When omitted the default paint from the [Sprite] class will be used.
|
||||||
|
final Paint? paint;
|
||||||
|
|
||||||
final FutureOr<Sprite> _spriteFuture;
|
final FutureOr<Sprite> _spriteFuture;
|
||||||
|
|
||||||
/// renders the [sprite] as a Widget.
|
/// renders the [sprite] as a Widget.
|
||||||
@ -36,6 +40,7 @@ class SpriteWidget extends StatelessWidget {
|
|||||||
this.angle = 0,
|
this.angle = 0,
|
||||||
this.errorBuilder,
|
this.errorBuilder,
|
||||||
this.loadingBuilder,
|
this.loadingBuilder,
|
||||||
|
this.paint,
|
||||||
super.key,
|
super.key,
|
||||||
}) : _spriteFuture = sprite;
|
}) : _spriteFuture = sprite;
|
||||||
|
|
||||||
@ -54,6 +59,7 @@ class SpriteWidget extends StatelessWidget {
|
|||||||
Vector2? srcSize,
|
Vector2? srcSize,
|
||||||
this.errorBuilder,
|
this.errorBuilder,
|
||||||
this.loadingBuilder,
|
this.loadingBuilder,
|
||||||
|
this.paint,
|
||||||
super.key,
|
super.key,
|
||||||
}) : _spriteFuture = Sprite.load(
|
}) : _spriteFuture = Sprite.load(
|
||||||
path,
|
path,
|
||||||
@ -71,6 +77,7 @@ class SpriteWidget extends StatelessWidget {
|
|||||||
sprite: sprite,
|
sprite: sprite,
|
||||||
anchor: anchor,
|
anchor: anchor,
|
||||||
angle: angle,
|
angle: angle,
|
||||||
|
paint: paint,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
errorBuilder: errorBuilder,
|
errorBuilder: errorBuilder,
|
||||||
@ -91,17 +98,20 @@ class InternalSpriteWidget extends StatelessWidget {
|
|||||||
/// The angle to rotate this [sprite], in rad. (default = 0)
|
/// The angle to rotate this [sprite], in rad. (default = 0)
|
||||||
final double angle;
|
final double angle;
|
||||||
|
|
||||||
|
final Paint? paint;
|
||||||
|
|
||||||
const InternalSpriteWidget({
|
const InternalSpriteWidget({
|
||||||
required this.sprite,
|
required this.sprite,
|
||||||
this.anchor = Anchor.topLeft,
|
this.anchor = Anchor.topLeft,
|
||||||
this.angle = 0,
|
this.angle = 0,
|
||||||
|
this.paint,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CustomPaint(
|
return CustomPaint(
|
||||||
painter: SpritePainter(sprite, anchor, angle: angle),
|
painter: SpritePainter(sprite, anchor, paint, angle: angle),
|
||||||
size: sprite.srcSize.toSize(),
|
size: sprite.srcSize.toSize(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user