chore: review docs and names

pull/40/head
RuiAlonso 4 years ago
parent dab5cbbe4f
commit 7dc9ef1714

@ -1,16 +1,17 @@
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
/// Modifies maskBits of [BodyComponent] to control what other bodies it can /// {@template layered}
/// have physical interactions with. /// Modifies maskBits and categoryBits of all the [BodyComponent]'s [Fixture]s
/// to specify what other [BodyComponent]s it can collide with.
/// ///
/// Changes the [Filter] data for category and maskBits of the [BodyComponent] /// [BodyComponent]s with the same [Layer] can collide with each other, ignoring
/// so it will only collide with bodies having the same bit value and ignore /// those with different [Layer]s.
/// bodies with a different bit value.
/// {@endtemplate} /// {@endtemplate}
mixin Layered<T extends Forge2DGame> on BodyComponent<T> { mixin Layered<T extends Forge2DGame> on BodyComponent<T> {
Layer _layer = Layer.all; Layer _layer = Layer.all;
/// Sets [Filter] category and mask bits for the [BodyComponent]. /// {@macro layered}
Layer get layer => _layer; Layer get layer => _layer;
set layer(Layer value) { set layer(Layer value) {
@ -19,18 +20,18 @@ mixin Layered<T extends Forge2DGame> on BodyComponent<T> {
// TODO(alestiago): Use loaded.whenComplete once provided. // TODO(alestiago): Use loaded.whenComplete once provided.
mounted.whenComplete(() { mounted.whenComplete(() {
layer = value; layer = value;
_applyMaskbits(); _applyMaskBits();
}); });
} else { } else {
_applyMaskbits(); _applyMaskBits();
} }
} }
void _applyMaskbits() { void _applyMaskBits() {
for (final fixture in body.fixtures) { for (final fixture in body.fixtures) {
fixture fixture
..filterData.categoryBits = layer.maskBits ..filterData.categoryBits = layer._maskBits
..filterData.maskBits = layer.maskBits; ..filterData.maskBits = layer._maskBits;
} }
} }
} }
@ -56,10 +57,18 @@ enum Layer {
launcher, launcher,
} }
/// Utility methods for [Layer]. /// {@template layer_mask_bits}
extension LayerX on Layer { /// Specifies the maskBits of each [Layer].
/// Mask of bits for each [Layer] to filter collisions. ///
int get maskBits { /// Used by [Layered] to specify what other [BodyComponent]s it can collide
///
/// Note: the maximum value for maskBits is 2^16.
/// {@endtemplate}
@visibleForTesting
extension LayerMaskBits on Layer {
/// {@macro layer_mask_bits}
int get _maskBits {
// TODO(ruialonso): test bit groups once final design is implemented.
switch (this) { switch (this) {
case Layer.all: case Layer.all:
return 0xFFFF; return 0xFFFF;

@ -1,7 +1,6 @@
// ignore_for_file: avoid_renaming_method_parameters // ignore_for_file: avoid_renaming_method_parameters
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
/// {@template ramp_orientation} /// {@template ramp_orientation}
@ -21,7 +20,7 @@ enum RampOrientation {
/// [RampOpeningBallContactCallback] detects when a [Ball] passes /// [RampOpeningBallContactCallback] detects when a [Ball] passes
/// through this opening. /// through this opening.
/// ///
/// By default the [layer] is set to [Layer.board]. /// By default the base [layer] is set to [Layer.board].
/// {@endtemplate} /// {@endtemplate}
// TODO(ruialonso): Consider renaming the class. // TODO(ruialonso): Consider renaming the class.
abstract class RampOpening extends BodyComponent with InitialPosition, Layered { abstract class RampOpening extends BodyComponent with InitialPosition, Layered {
@ -62,24 +61,23 @@ abstract class RampOpening extends BodyComponent with InitialPosition, Layered {
/// Detects when a [Ball] enters or exits a [Pathway] ramp through a /// Detects when a [Ball] enters or exits a [Pathway] ramp through a
/// [RampOpening]. /// [RampOpening].
/// ///
/// Modifies [Ball]'s maskBits while it is inside the ramp. When [Ball] exits, /// Modifies [Ball]'s [Layer] accordingly depending on whether the [Ball] is
/// sets maskBits to collide with all elements. /// outside or inside a ramp.
/// {@endtemplate} /// {@endtemplate}
class RampOpeningBallContactCallback<Opening extends RampOpening> class RampOpeningBallContactCallback<Opening extends RampOpening>
extends ContactCallback<Ball, Opening> { extends ContactCallback<Ball, Opening> {
/// Collection of balls inside ramp pathway. /// [Ball]s currently inside the ramp.
@visibleForTesting final _ballsInside = <Ball>{};
final ballsInside = <Ball>{};
@override @override
void begin(Ball ball, Opening opening, Contact _) { void begin(Ball ball, Opening opening, Contact _) {
late final Layer layer; late final Layer layer;
if (!ballsInside.contains(ball)) { if (!_ballsInside.contains(ball)) {
layer = opening.pathwayLayer; layer = opening.pathwayLayer;
ballsInside.add(ball); _ballsInside.add(ball);
} else { } else {
layer = Layer.board; layer = Layer.board;
ballsInside.remove(ball); _ballsInside.remove(ball);
} }
ball.layer = layer; ball.layer = layer;

@ -24,9 +24,9 @@ void main() {
for (final fixture in fixtures) { for (final fixture in fixtures) {
expect( expect(
fixture.filterData.categoryBits, fixture.filterData.categoryBits,
equals(layer.maskBits), equals(layer._maskBits),
); );
expect(fixture.filterData.maskBits, equals(layer.maskBits)); expect(fixture.filterData.maskBits, equals(layer._maskBits));
} }
} }
@ -128,39 +128,20 @@ void main() {
}); });
}); });
group('LayerX', () { group('LayerMaskBits', () {
test('all types are different', () { test('all types are different', () {
expect(Layer.all.maskBits, isNot(equals(Layer.board.maskBits))); expect(Layer.all._maskBits, isNot(equals(Layer.board._maskBits)));
expect(Layer.board.maskBits, isNot(equals(Layer.opening.maskBits))); expect(Layer.board._maskBits, isNot(equals(Layer.opening._maskBits)));
expect(Layer.opening.maskBits, isNot(equals(Layer.jetpack.maskBits))); expect(Layer.opening._maskBits, isNot(equals(Layer.jetpack._maskBits)));
expect(Layer.jetpack.maskBits, isNot(equals(Layer.launcher.maskBits))); expect(Layer.jetpack._maskBits, isNot(equals(Layer.launcher._maskBits)));
expect(Layer.launcher.maskBits, isNot(equals(Layer.board.maskBits))); expect(Layer.launcher._maskBits, isNot(equals(Layer.board._maskBits)));
}); });
test('ensure all maskBits are 16 bits max size', () { test('ensure all maskBits are 16 bits max size', () {
final maxMaskBitSize = math.pow(2, 16); final maxMaskBitSize = math.pow(2, 16);
for (final layer in Layer.values) { for (final layer in Layer.values) {
expect(layer.maskBits, isNot(greaterThan(maxMaskBitSize))); expect(layer._maskBits, isNot(greaterThan(maxMaskBitSize)));
} }
}); });
test('all type has 0xFFFF maskBits', () {
expect(Layer.all.maskBits, equals(0xFFFF));
});
test('board type has 0x0001 maskBits', () {
expect(Layer.board.maskBits, equals(0x0001));
});
test('opening type has 0x0007 maskBits', () {
expect(Layer.opening.maskBits, equals(0x0007));
});
test('jetpack type has 0x0002 maskBits', () {
expect(Layer.jetpack.maskBits, equals(0x0002));
});
test('launcher type has 0x0005 maskBits', () {
expect(Layer.launcher.maskBits, equals(0x0005));
});
}); });
} }

Loading…
Cancel
Save