🏷 Backport some code improvements from the null-safety branch (#603)

This commit is contained in:
Serge Matveenko
2021-01-09 05:25:29 +03:00
committed by GitHub
parent 5b1988ca36
commit 16eaef3bb1
28 changed files with 168 additions and 149 deletions

View File

@ -1,6 +1,7 @@
# CHANGELOG
## [next]
- Code improvements and preparing APIs to null-safety
- BaseComponent removes children marked as shouldRemove during update
- Use `find` instead of `globstar` pattern in `scripts/lint.sh` as the later isn't enabled by default in bash
- Fixes aseprite constructor bug

View File

@ -21,18 +21,19 @@ void main() async {
);
}
const green = Color(0xAA338833);
const red = Color(0xAA883333);
const orange = Color(0xAABB6633);
class MyGame extends BaseGame with TapDetector {
Square greenSquare;
Square redSquare;
Square orangeSquare;
MyGame() {
final green = Paint()..color = const Color(0xAA338833);
final red = Paint()..color = const Color(0xAA883333);
final orange = Paint()..color = const Color(0xAABB6633);
greenSquare = Square(green, Vector2.all(100));
redSquare = Square(red, Vector2.all(200));
orangeSquare = Square(orange, Vector2(200, 400));
MyGame()
: greenSquare = Square(Paint()..color = green, Vector2.all(100)),
redSquare = Square(Paint()..color = red, Vector2.all(200)),
orangeSquare = Square(Paint()..color = orange, Vector2(200, 400)) {
add(greenSquare);
add(redSquare);
add(orangeSquare);

View File

@ -74,12 +74,14 @@ class MyGame extends BaseGame
}
void onPanEnd(DragEndDetails details) {
_panRect = Rect.fromLTRB(
_start.dx,
_start.dy,
_end.dx,
_end.dy,
);
if (_start != null && _end != null) {
_panRect = Rect.fromLTRB(
_start.dx,
_start.dy,
_end.dx,
_end.dy,
);
}
}
@override

View File

@ -25,14 +25,15 @@ class Player extends Component implements JoystickListener {
@override
void render(Canvas canvas) {
if (_rect != null) {
canvas.save();
canvas.translate(_rect.center.dx, _rect.center.dy);
canvas.rotate(radAngle == 0.0 ? 0.0 : radAngle + (pi / 2));
canvas.translate(-_rect.center.dx, -_rect.center.dy);
canvas.drawRect(_rect, _paint);
canvas.restore();
if (_rect == null) {
return;
}
canvas.save();
canvas.translate(_rect.center.dx, _rect.center.dy);
canvas.rotate(radAngle == 0.0 ? 0.0 : radAngle + (pi / 2));
canvas.translate(-_rect.center.dx, -_rect.center.dy);
canvas.drawRect(_rect, _paint);
canvas.restore();
}
@override
@ -79,12 +80,15 @@ class Player extends Component implements JoystickListener {
final double nextX = (currentSpeed * dtUpdate) * cos(radAngle);
final double nextY = (currentSpeed * dtUpdate) * sin(radAngle);
if (_rect == null) {
return;
}
final Offset diffBase = Offset(
_rect.center.dx + nextX,
_rect.center.dy + nextY,
) -
_rect.center;
_rect = _rect.shift(diffBase);
}
}

View File

@ -16,8 +16,6 @@ void main() async {
}
class MyGame extends BaseGame {
SpriteAnimation animation;
@override
Future<void> onLoad() async {
final image = await images.load('chopper.png');

View File

@ -108,8 +108,9 @@ void main() async {
child: SpriteWidget(
sprite: shieldSprite,
anchor: parseAnchor(
ctx.listProperty('anchor', 'Anchor.center', anchorOptions),
),
ctx.listProperty('anchor', 'Anchor.center', anchorOptions),
) ??
Anchor.topLeft,
),
),
);
@ -134,8 +135,9 @@ void main() async {
animation: _animation,
playing: ctx.boolProperty('playing', true),
anchor: parseAnchor(
ctx.listProperty('anchor', 'Anchor.center', anchorOptions),
),
ctx.listProperty('anchor', 'Anchor.center', anchorOptions),
) ??
Anchor.topLeft,
),
),
);

View File

@ -34,11 +34,11 @@ class JoystickAction {
bool _dragging = false;
Sprite _spriteAction;
Offset _dragPosition;
Paint _paintBackground;
Paint _paintAction;
Paint _paintActionPressed;
final Paint _paintBackground;
final Paint _paintAction;
final Paint _paintActionPressed;
JoystickController _joystickController;
double _sizeBackgroundDirection;
final double _sizeBackgroundDirection;
DragEvent _currentDragEvent;
double _tileSize;
@ -55,9 +55,17 @@ class JoystickAction {
this.align = JoystickActionAlign.BOTTOM_RIGHT,
this.opacityBackground = 0.5,
this.opacityKnob = 0.8,
}) {
_spriteAction = sprite;
_sizeBackgroundDirection = sizeFactorBackgroundDirection * size;
}) : _spriteAction = sprite,
_sizeBackgroundDirection = sizeFactorBackgroundDirection * size,
_paintBackground = Paint()
..color = color.withOpacity(opacityBackground)
..style = PaintingStyle.fill,
_paintAction = Paint()
..color = color.withOpacity(opacityKnob)
..style = PaintingStyle.fill,
_paintActionPressed = Paint()
..color = color.withOpacity(opacityBackground)
..style = PaintingStyle.fill {
_tileSize = _sizeBackgroundDirection / 2;
}
@ -91,25 +99,6 @@ class JoystickAction {
center: Offset(dx, dy),
radius: _sizeBackgroundDirection / 2,
);
if (spriteBackgroundDirection == null) {
_paintBackground = Paint()
..color = color.withOpacity(opacityBackground)
..style = PaintingStyle.fill;
}
if (sprite == null) {
_paintAction = Paint()
..color = color.withOpacity(opacityKnob)
..style = PaintingStyle.fill;
}
if (spritePressed == null) {
_paintActionPressed = Paint()
..color = color.withOpacity(opacityBackground)
..style = PaintingStyle.fill;
}
_dragPosition = _rectAction.center;
}
@ -128,7 +117,7 @@ class JoystickAction {
}
void update(double dt) {
if (_dragging) {
if (_rectBackgroundDirection != null && _dragging) {
final double _radAngle = atan2(
_dragPosition.dy - _rectBackgroundDirection.center.dy,
_dragPosition.dx - _rectBackgroundDirection.center.dx,
@ -149,13 +138,15 @@ class JoystickAction {
final double nextY = dist * sin(_radAngle);
final Offset nextPoint = Offset(nextX, nextY);
final Offset diff = Offset(
_rectBackgroundDirection.center.dx + nextPoint.dx,
_rectBackgroundDirection.center.dy + nextPoint.dy,
) -
_rectAction.center;
if (_rectAction != null) {
final Offset diff = Offset(
_rectBackgroundDirection.center.dx + nextPoint.dx,
_rectBackgroundDirection.center.dy + nextPoint.dy,
) -
_rectAction.center;
_rectAction = _rectAction.shift(diff);
_rectAction = _rectAction.shift(diff);
}
final double _intensity = dist / _tileSize;
@ -176,24 +167,26 @@ class JoystickAction {
}
void onReceiveDrag(DragEvent event) {
if (!_dragging && (_rectAction?.contains(event.initialPosition) ?? false)) {
if (enableDirection) {
_dragPosition = event.initialPosition;
_dragging = true;
}
_joystickController.joystickAction(
JoystickActionEvent(
id: actionId,
event: ActionEvent.DOWN,
),
);
tapDown();
_currentDragEvent = event;
_currentDragEvent
..onUpdate = onPanUpdate
..onEnd = onPanEnd
..onCancel = onPanCancel;
if (_dragging || !(_rectAction?.contains(event.initialPosition) ?? false)) {
return;
}
if (enableDirection) {
_dragPosition = event.initialPosition;
_dragging = true;
}
_joystickController.joystickAction(
JoystickActionEvent(
id: actionId,
event: ActionEvent.DOWN,
),
);
tapDown();
_currentDragEvent = event;
_currentDragEvent
..onUpdate = onPanUpdate
..onEnd = onPanEnd
..onCancel = onPanCancel;
}
void tapDown() {

View File

@ -11,6 +11,8 @@ class JoystickUtils {
}
if (sprite == null) {
assert(paint != null, '`paint` must not be `null` if `sprite` is `null`');
final double radius = rect.width / 2;
c.drawCircle(
Offset(rect.left + radius, rect.top + radius),

View File

@ -34,7 +34,7 @@ class SpriteComponent extends PositionComponent {
@override
void render(Canvas canvas) {
super.render(canvas);
sprite.render(
sprite?.render(
canvas,
size: size,
overridePaint: overridePaint,

View File

@ -28,11 +28,11 @@ class TextBoxConfig {
class TextBoxComponent extends PositionComponent {
static final Paint _imagePaint = BasicPalette.white.paint
..filterQuality = FilterQuality.high;
Vector2 _gameSize;
Vector2 _gameSize = Vector2.zero();
String _text;
TextConfig _config;
TextBoxConfig _boxConfig;
final String _text;
final TextConfig _config;
final TextBoxConfig _boxConfig;
List<String> _lines;
double _maxLineWidth = 0.0;
@ -53,15 +53,15 @@ class TextBoxComponent extends PositionComponent {
String text, {
TextConfig config,
TextBoxConfig boxConfig,
}) {
_boxConfig = boxConfig ?? TextBoxConfig();
_config = config ?? TextConfig();
_text = text;
}) : _text = text,
_boxConfig = boxConfig ?? TextBoxConfig(),
_config = config ?? TextConfig() {
_lines = [];
double lineHeight;
text.split(' ').forEach((word) {
final possibleLine = _lines.isEmpty ? word : _lines.last + ' ' + word;
final painter = _config.toTextPainter(possibleLine);
_lineHeight ??= painter.height;
lineHeight ??= painter.height;
if (painter.width <=
_boxConfig.maxWidth - _boxConfig.margins.horizontal) {
if (_lines.isNotEmpty) {
@ -76,6 +76,7 @@ class TextBoxComponent extends PositionComponent {
}
});
_totalLines = _lines.length;
_lineHeight = lineHeight ?? 0.0;
}
void _updateMaxWidth(double w) {

View File

@ -28,8 +28,8 @@ class TextComponent extends PositionComponent {
_updateBox();
}
TextComponent(this._text, {TextConfig config}) {
_config = config ?? TextConfig();
TextComponent(this._text, {TextConfig config})
: _config = config ?? TextConfig() {
_updateBox();
}

View File

@ -47,8 +47,10 @@ class CombinedEffect extends PositionComponentEffect {
effect.originalAngle != effect.endAngle ? effect.endAngle : endAngle;
endSize =
effect.originalSize != effect.endSize ? effect.endSize : endSize;
peakTime = max(peakTime ?? 0,
effect.iterationTime + offset * effects.indexOf(effect));
peakTime = max(
peakTime,
effect.iterationTime + offset * effects.indexOf(effect),
);
});
if (isAlternating) {
endPosition = originalPosition;

View File

@ -30,8 +30,8 @@ abstract class ComponentEffect<T extends BaseComponent> {
final bool _initialIsInfinite;
final bool _initialIsAlternating;
double percentage;
double curveProgress;
double peakTime;
double curveProgress = 0.0;
double peakTime = 0.0;
double currentTime = 0.0;
double driftTime = 0.0;
int curveDirection = 1;
@ -43,13 +43,12 @@ abstract class ComponentEffect<T extends BaseComponent> {
this._initialIsInfinite,
this._initialIsAlternating, {
this.isRelative = false,
this.curve = Curves.linear,
Curve curve,
this.onComplete,
}) {
isInfinite = _initialIsInfinite;
isAlternating = _initialIsAlternating;
curve ??= Curves.linear;
}
}) : assert(isRelative != null),
isInfinite = _initialIsInfinite,
isAlternating = _initialIsAlternating,
curve = curve ?? Curves.linear;
@mustCallSuper
void update(double dt) {
@ -171,12 +170,24 @@ abstract class PositionComponentEffect
void _setComponentState(Vector2 position, double angle, Vector2 size) {
if (isRootEffect()) {
if (modifiesPosition) {
assert(
position != null,
'`position` must not be `null` for an effect which modifies `position`',
);
component?.position?.setFrom(position);
}
if (modifiesAngle) {
assert(
angle != null,
'`angle` must not be `null` for an effect which modifies `angle`',
);
component?.angle = angle;
}
if (modifiesSize) {
assert(
size != null,
'`size` must not be `null` for an effect which modifies `size`',
);
component?.size?.setFrom(size);
}
}

View File

@ -50,8 +50,8 @@ class MoveEffect extends SimplePositionComponentEffect {
);
@override
void initialize(_comp) {
super.initialize(_comp);
void initialize(component) {
super.initialize(component);
List<Vector2> _movePath;
_startPosition = component.position.clone();
// With relative here we mean that any vector in the list is relative
@ -96,7 +96,11 @@ class MoveEffect extends SimplePositionComponentEffect {
}
final double totalPathLength = isAlternating ? pathLength * 2 : pathLength;
speed ??= totalPathLength / duration;
// `duration` is not null when speed is null
duration ??= totalPathLength / speed;
// `speed` is always not null here already
peakTime = isAlternating ? duration / 2 : duration;
}

View File

@ -34,8 +34,8 @@ class RotateEffect extends SimplePositionComponentEffect {
);
@override
void initialize(_comp) {
super.initialize(_comp);
void initialize(component) {
super.initialize(component);
_startAngle = component.angle;
_delta = isRelative ? angle : angle - _startAngle;
if (!isAlternating) {
@ -49,6 +49,6 @@ class RotateEffect extends SimplePositionComponentEffect {
@override
void update(double dt) {
super.update(dt);
component.angle = _startAngle + _delta * curveProgress;
component?.angle = _startAngle + _delta * curveProgress;
}
}

View File

@ -35,8 +35,8 @@ class ScaleEffect extends SimplePositionComponentEffect {
);
@override
void initialize(_comp) {
super.initialize(_comp);
void initialize(component) {
super.initialize(component);
_startSize = component.size;
_delta = isRelative ? size : size - _startSize;
if (!isAlternating) {

View File

@ -5,10 +5,14 @@ import 'effects.dart';
class SequenceEffect extends PositionComponentEffect {
final List<PositionComponentEffect> effects;
int _currentIndex;
PositionComponentEffect currentEffect;
bool _currentWasAlternating;
double _driftModifier;
static const int _initialIndex = 0;
static const double _initialDriftModifier = 0.0;
int _currentIndex = _initialIndex;
double _driftModifier = _initialDriftModifier;
SequenceEffect({
@required this.effects,
@ -36,8 +40,8 @@ class SequenceEffect extends PositionComponentEffect {
@override
void initialize(PositionComponent component) {
super.initialize(component);
_currentIndex = 0;
_driftModifier = 0.0;
_currentIndex = _initialIndex;
_driftModifier = _initialDriftModifier;
effects.forEach((effect) {
effect.reset();

View File

@ -14,8 +14,7 @@ import 'util.dart';
class Flame {
// Flame asset bundle, defaults to root
static AssetBundle _bundle;
static AssetBundle get bundle => _bundle == null ? rootBundle : _bundle;
static AssetBundle get bundle => _bundle ?? rootBundle;
/// Access a shared instance of [AssetsCache] class.
static AssetsCache assets = AssetsCache();

View File

@ -57,9 +57,7 @@ class BaseGame extends Game with FPSCounter {
}
// first time resize
if (size != null) {
c.onGameResize(size);
}
c.onGameResize(size);
}
/// Prepares and registers a component to be added on the next game tick

View File

@ -134,12 +134,13 @@ class _GameWidgetState<T extends Game> extends State<GameWidget<T>> {
}
void _initActiveOverlays() {
if (widget.initialActiveOverlays != null) {
_checkOverlays(widget.initialActiveOverlays.toSet());
widget.initialActiveOverlays.forEach((key) {
widget.game.overlays.add(key);
});
if (widget.initialActiveOverlays == null) {
return;
}
_checkOverlays(widget.initialActiveOverlays.toSet());
widget.initialActiveOverlays.forEach((key) {
widget.game.overlays.add(key);
});
}
@override
@ -175,8 +176,10 @@ class _GameWidgetState<T extends Game> extends State<GameWidget<T>> {
void _checkOverlays(Set<String> overlays) {
overlays.forEach((overlayKey) {
assert(widget.overlayBuilderMap.containsKey(overlayKey),
"A non mapped overlay has been added: $overlayKey");
assert(
widget.overlayBuilderMap?.containsKey(overlayKey) ?? false,
"A non mapped overlay has been added: $overlayKey",
);
});
}
@ -472,10 +475,9 @@ Widget _applyAdvancedGesturesDetectors(Game game, Widget child) {
(MultiDragGestureRecognizer instance) {
instance
..onStart = (Offset o) {
final drag = DragEvent();
// Note that padding or margin isn't taken into account here
drag.initialPosition = o;
dragHandlers.forEach((h) => h.onReceiveDrag(drag));
final drag = DragEvent(o);
dragHandlers.forEach((h) => h.onReceiveDrag?.call(drag));
return drag;
};
},

View File

@ -11,7 +11,9 @@ mixin MultiTouchTapDetector on Game {
}
class DragEvent extends Drag {
Offset initialPosition;
final Offset initialPosition;
DragEvent(this.initialPosition);
void Function(DragUpdateDetails) onUpdate;
void Function() onCancel;

View File

@ -5,7 +5,7 @@ abstract class LayerProcessor {
}
class ShadowProcessor extends LayerProcessor {
Paint _shadowPaint;
final Paint _shadowPaint;
final Offset offset;
@ -13,11 +13,9 @@ class ShadowProcessor extends LayerProcessor {
this.offset = const Offset(10, 10),
double opacity = 0.9,
Color color = const Color(0xFF000000),
}) {
_shadowPaint = Paint()
..colorFilter =
ColorFilter.mode(color.withOpacity(opacity), BlendMode.srcATop);
}
}) : _shadowPaint = Paint()
..colorFilter =
ColorFilter.mode(color.withOpacity(opacity), BlendMode.srcATop);
@override
void process(Picture pic, Canvas canvas) {

View File

@ -30,9 +30,9 @@ class NineTileBox {
///
/// If [destTileSize] is not provided, the evaluated [tileSize] is used instead
/// (so no scaling happens).
NineTileBox(this.sprite, {int tileSize, int destTileSize}) {
this.tileSize = tileSize ?? sprite.src.width.toInt();
this.destTileSize = destTileSize ?? tileSize;
NineTileBox(this.sprite, {int tileSize, int destTileSize})
: tileSize = tileSize ?? sprite.src.width.toInt() {
this.destTileSize = destTileSize ?? this.tileSize;
}
/// Renders this nine box with the dimensions provided by [rect].

View File

@ -121,10 +121,8 @@ class ParallaxLayer {
/// multiplying the [baseVelocity] with the [velocityMultiplier].
ParallaxLayer(
this.parallaxImage, {
this.velocityMultiplier,
}) {
velocityMultiplier ??= Vector2.all(1.0);
}
Vector2 velocityMultiplier,
}) : velocityMultiplier = velocityMultiplier ?? Vector2.all(1.0);
Vector2 currentOffset() => _scroll;
@ -241,10 +239,8 @@ class Parallax {
Parallax(
this.layers, {
this.baseVelocity,
}) {
baseVelocity ??= Vector2.zero();
}
Vector2 baseVelocity,
}) : baseVelocity = baseVelocity ?? Vector2.zero();
/// The base offset of the parallax, can be used in an outer update loop
/// if you want to transition the parallax to a certain position.

View File

@ -19,7 +19,6 @@ class ComputedParticle extends Particle {
ComputedParticle({
@required this.renderer,
double lifespan,
Duration duration,
}) : super(
lifespan: lifespan,
);

View File

@ -25,7 +25,7 @@ class RotatingParticle extends CurvedParticle with SingleChildParticle {
lifespan: lifespan,
);
double get angle => lerpDouble(from, to, progress);
double get angle => lerpDouble(from, to, progress) ?? 0;
@override
void render(Canvas canvas) {

View File

@ -10,7 +10,7 @@ import 'assets/images.dart';
class Sprite {
Paint paint = BasicPalette.white.paint;
Image image;
Rect src;
Rect src = Rect.zero;
Sprite(
this.image, {
@ -44,10 +44,10 @@ class Sprite {
set srcSize(Vector2 size) {
size ??= Vector2Extension.fromInts(image.width, image.height);
src = (srcPosition ?? Vector2.zero()).toPositionedRect(size);
src = srcPosition.toPositionedRect(size);
}
Vector2 get srcPosition => (src?.topLeft ?? Offset.zero).toVector2();
Vector2 get srcPosition => src.topLeft.toVector2();
set srcPosition(Vector2 position) {
src = (position ?? Vector2.zero()).toPositionedRect(srcSize);

View File

@ -50,7 +50,7 @@ class _AnimationWidget extends State<SpriteAnimationWidget>
..addListener(() {
final now = DateTime.now().millisecond.toDouble();
final dt = max(0, (now - _lastUpdated) / 1000).toDouble();
final dt = max(0, (now - (_lastUpdated ?? 0)) / 1000).toDouble();
widget.animation.update(dt);
setState(() {