feat: implementing PinballCanvasComponent

pull/282/head
alestiago 3 years ago
parent 09d020fc30
commit 39715de5aa

@ -1,6 +1,7 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// {@template bottom_group} /// {@template bottom_group}
/// Grouping of the board's symmetrical bottom [Component]s. /// Grouping of the board's symmetrical bottom [Component]s.
@ -8,7 +9,7 @@ import 'package:pinball_components/pinball_components.dart';
/// The [BottomGroup] consists of [Flipper]s, [Baseboard]s and [Kicker]s. /// The [BottomGroup] consists of [Flipper]s, [Baseboard]s and [Kicker]s.
/// {@endtemplate} /// {@endtemplate}
// TODO(allisonryan0002): Consider renaming. // TODO(allisonryan0002): Consider renaming.
class BottomGroup extends Component { class BottomGroup extends Component with Rendering {
/// {@macro bottom_group} /// {@macro bottom_group}
BottomGroup() BottomGroup()
: super( : super(
@ -17,7 +18,9 @@ class BottomGroup extends Component {
_BottomGroupSide(side: BoardSide.left), _BottomGroupSide(side: BoardSide.left),
], ],
priority: RenderPriority.bottomGroup, priority: RenderPriority.bottomGroup,
); ) {
zIndex = 2;
}
} }
/// {@template bottom_group_side} /// {@template bottom_group_side}

@ -14,7 +14,7 @@ class DinoDesert extends Blueprint {
DinoDesert() DinoDesert()
: super( : super(
components: [ components: [
ChromeDino()..initialPosition = Vector2(12.3, -6.9), // ChromeDino()..initialPosition = Vector2(12.3, -6.9),
], ],
blueprints: [ blueprints: [
DinoWalls(), DinoWalls(),

@ -45,36 +45,34 @@ class PinballGame extends Forge2DGame
await add(gameFlowController = GameFlowController(this)); await add(gameFlowController = GameFlowController(this));
await add(CameraController(this)); await add(CameraController(this));
await add(Backboard.waiting(position: Vector2(0, -88))); await add(Backboard.waiting(position: Vector2(0, -88)));
await add(BoardBackgroundSpriteComponent());
await add(Drain());
await add(BottomGroup());
await addFromBlueprint(Boundaries());
final launcher = Launcher();
await add(launcher);
await add(FlutterForest()..priority = 1);
await add(Multipliers());
await addFromBlueprint(SparkyScorch());
await addFromBlueprint(AndroidAcres());
await addFromBlueprint(DinoDesert());
await addFromBlueprint(Slingshots());
await add( await add(
PinballCanvasComponent(
camera: camera,
children: [
BoardBackgroundSpriteComponent(),
Multipliers(),
Drain(),
BottomGroup(),
Launcher(),
FlutterForest(),
GoogleWord( GoogleWord(
position: Vector2( position: Vector2(
BoardDimensions.bounds.center.dx - 4.1, BoardDimensions.bounds.center.dx - 4.1,
BoardDimensions.bounds.center.dy + 1.8, BoardDimensions.bounds.center.dy + 1.8,
), ),
), ),
],
),
); );
await super.onLoad(); await addFromBlueprint(Boundaries());
} await addFromBlueprint(SparkyScorch());
await addFromBlueprint(AndroidAcres());
await addFromBlueprint(DinoDesert());
await addFromBlueprint(Slingshots());
@override await super.onLoad();
void renderTree(Canvas canvas) {
final pinballCanvas = PinballCanvas(canvas, camera);
super.renderTree(pinballCanvas);
pinballCanvas.runPostActions();
} }
BoardSide? focusedBoardSide; BoardSide? focusedBoardSide;
@ -152,8 +150,8 @@ class _GameBallsController extends ComponentController<PinballGame>
} }
@override @override
Future<void> onLoad() async { void onMount() {
await super.onLoad(); super.onMount();
_spawnBall(); _spawnBall();
} }
@ -164,7 +162,7 @@ class _GameBallsController extends ComponentController<PinballGame>
Vector2(41.1, 43).x, Vector2(41.1, 43).x,
Vector2(41.1, 45).y - Ball.size.y, Vector2(41.1, 45).y - Ball.size.y,
); );
component.add(ball); component.firstChild<PinballCanvasComponent>()?.add(ball);
} }
} }

@ -2,8 +2,10 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
class BoardBackgroundSpriteComponent extends SpriteComponent with HasGameRef { class BoardBackgroundSpriteComponent extends SpriteComponent
with HasGameRef, Rendering {
BoardBackgroundSpriteComponent() BoardBackgroundSpriteComponent()
: super( : super(
anchor: Anchor.center, anchor: Anchor.center,

@ -124,10 +124,11 @@ class _LaunchRampBaseSpriteComponent extends SpriteComponent with HasGameRef {
} }
class _LaunchRampBackgroundRailingSpriteComponent extends SpriteComponent class _LaunchRampBackgroundRailingSpriteComponent extends SpriteComponent
with HasGameRef { with HasGameRef, Rendering {
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
zIndex = 1;
final sprite = await gameRef.loadSprite( final sprite = await gameRef.loadSprite(
Assets.images.launchRamp.backgroundRailing.keyName, Assets.images.launchRamp.backgroundRailing.keyName,

@ -6,4 +6,5 @@ export 'src/contact_behavior.dart';
export 'src/keyboard_input_controller.dart'; export 'src/keyboard_input_controller.dart';
export 'src/parent_is_a.dart'; export 'src/parent_is_a.dart';
export 'src/pinball_canvas.dart'; export 'src/pinball_canvas.dart';
export 'src/rendering/rendering.dart';
export 'src/sprite_animation.dart'; export 'src/sprite_animation.dart';

@ -1,207 +1 @@
// ignore_for_file: public_member_api_docs
import 'dart:typed_data';
import 'dart:ui';
import 'package:flame/components.dart';
import 'package:flame/game.dart';
typedef CanvasAction = void Function(Canvas canvas);
mixin AbsoluteRendering on PositionComponent {
@override
void renderTree(Canvas canvas) {
if (canvas is PinballCanvas) {
canvas.actions.add(this);
}
}
}
class PinballCanvas implements Canvas {
PinballCanvas(this.canvas, this.camera);
Canvas canvas;
Camera camera;
List<PositionComponent> actions = [];
void runPostActions() {
for (final action in actions) {
renderComponent(action);
}
actions.clear();
}
void renderComponent(PositionComponent component) {
canvas.save();
// camera.viewport.apply(canvas);
camera.apply(canvas);
canvas.transform(component.transformMatrix.storage);
component.render(canvas);
canvas.restore();
}
@override
void clipPath(Path path, {bool doAntiAlias = true}) =>
canvas.clipPath(path, doAntiAlias: doAntiAlias);
@override
void clipRRect(RRect rrect, {bool doAntiAlias = true}) =>
canvas.clipRRect(rrect, doAntiAlias: doAntiAlias);
@override
void clipRect(Rect rect,
{ClipOp clipOp = ClipOp.intersect, bool doAntiAlias = true}) =>
canvas.clipRect(rect, clipOp: clipOp, doAntiAlias: doAntiAlias);
@override
void drawArc(
Rect rect,
double startAngle,
double sweepAngle,
bool useCenter,
Paint paint,
) =>
canvas.drawArc(rect, startAngle, sweepAngle, useCenter, paint);
@override
void drawAtlas(
Image atlas,
List<RSTransform> transforms,
List<Rect> rects,
List<Color>? colors,
BlendMode? blendMode,
Rect? cullRect,
Paint paint,
) =>
canvas.drawAtlas(
atlas,
transforms,
rects,
colors,
blendMode,
cullRect,
paint,
);
@override
void drawCircle(Offset c, double radius, Paint paint) => canvas.drawCircle(
c,
radius,
paint,
);
@override
void drawColor(Color color, BlendMode blendMode) =>
canvas.drawColor(color, blendMode);
@override
void drawDRRect(RRect outer, RRect inner, Paint paint) =>
canvas.drawDRRect(outer, inner, paint);
@override
void drawImage(Image image, Offset offset, Paint paint) =>
canvas.drawImage(image, offset, paint);
@override
void drawImageNine(Image image, Rect center, Rect dst, Paint paint) =>
canvas.drawImageNine(image, center, dst, paint);
@override
void drawImageRect(Image image, Rect src, Rect dst, Paint paint) =>
canvas.drawImageRect(image, src, dst, paint);
@override
void drawLine(Offset p1, Offset p2, Paint paint) =>
canvas.drawLine(p1, p2, paint);
@override
void drawOval(Rect rect, Paint paint) => canvas.drawOval(rect, paint);
@override
void drawPaint(Paint paint) => canvas.drawPaint(paint);
@override
void drawParagraph(Paragraph paragraph, Offset offset) =>
canvas.drawParagraph(paragraph, offset);
@override
void drawPath(Path path, Paint paint) => canvas.drawPath(path, paint);
@override
void drawPicture(Picture picture) => canvas.drawPicture(picture);
@override
void drawPoints(PointMode pointMode, List<Offset> points, Paint paint) =>
canvas.drawPoints(pointMode, points, paint);
@override
void drawRRect(RRect rrect, Paint paint) => canvas.drawRRect(rrect, paint);
@override
void drawRawAtlas(
Image atlas,
Float32List rstTransforms,
Float32List rects,
Int32List? colors,
BlendMode? blendMode,
Rect? cullRect,
Paint paint,
) =>
canvas.drawRawAtlas(
atlas,
rstTransforms,
rects,
colors,
blendMode,
cullRect,
paint,
);
@override
void drawRawPoints(PointMode pointMode, Float32List points, Paint paint) =>
canvas.drawRawPoints(pointMode, points, paint);
@override
void drawRect(Rect rect, Paint paint) => canvas.drawRect(rect, paint);
@override
void drawShadow(
Path path,
Color color,
double elevation,
bool transparentOccluder,
) =>
canvas.drawShadow(path, color, elevation, transparentOccluder);
@override
void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) =>
canvas.drawVertices(vertices, blendMode, paint);
@override
int getSaveCount() => canvas.getSaveCount();
@override
void restore() => canvas.restore();
@override
void rotate(double radians) => canvas.rotate(radians);
@override
void save() => canvas.save();
@override
void saveLayer(Rect? bounds, Paint paint) => canvas.saveLayer(bounds, paint);
@override
void scale(double sx, [double? sy]) => canvas.scale(sx);
@override
void skew(double sx, double sy) => canvas.skew(sx, sy);
@override
void transform(Float64List matrix4) => canvas.transform(matrix4);
@override
void translate(double dx, double dy) => canvas.translate(dx, dy);
}

@ -0,0 +1,238 @@
// ignore_for_file: public_member_api_docs
import 'dart:typed_data';
import 'dart:ui';
import 'package:flame/components.dart';
import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_flame/src/rendering/rendering.dart';
class PinballCanvas implements Canvas {
PinballCanvas({
required this.camera,
});
late Canvas canvas;
Camera camera;
final List<Rendering> _zBuffer = [];
void buffer(Rendering rendering) => _zBuffer.add(rendering);
void render() {
_zBuffer
..sort((a, b) => a.zIndex.compareTo(b.zIndex))
..whereType<Component>().forEach(_render);
// ..expand(_flatten).forEach(_render);
_zBuffer.clear();
}
Iterable<PositionComponent> _flatten(Rendering rendering) {
final components = <PositionComponent>[];
if (rendering is PositionComponent) {
components.add(rendering as PositionComponent);
}
components.addAll(rendering.descendants().whereType<PositionComponent>());
return components;
}
void _render(Component component) {
// TODO(alestiago): Uses zones to detect when super.renderTree is called,
// and call _render insted.
if (component is BodyComponent) {
final Matrix4 _transform = Matrix4.identity();
double? _lastAngle;
if (_transform.m14 != component.body.position.x ||
_transform.m24 != component.body.position.y ||
_lastAngle != component.angle) {
_transform.setIdentity();
_transform.translate(
component.body.position.x, component.body.position.y);
_transform.rotateZ(component.angle);
_lastAngle = component.angle;
}
canvas.save();
canvas.transform(_transform.storage);
component.children.forEach(_render);
canvas.restore();
} else if (component is PositionComponent) {
canvas
..save()
..transform(component.transformMatrix.storage);
component.render(canvas);
component.children.forEach(_render);
canvas.restore();
} else {
component.render(canvas);
component.children.forEach(_render);
}
}
@override
void clipPath(Path path, {bool doAntiAlias = true}) =>
canvas.clipPath(path, doAntiAlias: doAntiAlias);
@override
void clipRRect(RRect rrect, {bool doAntiAlias = true}) =>
canvas.clipRRect(rrect, doAntiAlias: doAntiAlias);
@override
void clipRect(Rect rect,
{ClipOp clipOp = ClipOp.intersect, bool doAntiAlias = true}) =>
canvas.clipRect(rect, clipOp: clipOp, doAntiAlias: doAntiAlias);
@override
void drawArc(
Rect rect,
double startAngle,
double sweepAngle,
bool useCenter,
Paint paint,
) =>
canvas.drawArc(rect, startAngle, sweepAngle, useCenter, paint);
@override
void drawAtlas(
Image atlas,
List<RSTransform> transforms,
List<Rect> rects,
List<Color>? colors,
BlendMode? blendMode,
Rect? cullRect,
Paint paint,
) =>
canvas.drawAtlas(
atlas,
transforms,
rects,
colors,
blendMode,
cullRect,
paint,
);
@override
void drawCircle(Offset c, double radius, Paint paint) => canvas.drawCircle(
c,
radius,
paint,
);
@override
void drawColor(Color color, BlendMode blendMode) =>
canvas.drawColor(color, blendMode);
@override
void drawDRRect(RRect outer, RRect inner, Paint paint) =>
canvas.drawDRRect(outer, inner, paint);
@override
void drawImage(Image image, Offset offset, Paint paint) =>
canvas.drawImage(image, offset, paint);
@override
void drawImageNine(Image image, Rect center, Rect dst, Paint paint) =>
canvas.drawImageNine(image, center, dst, paint);
@override
void drawImageRect(Image image, Rect src, Rect dst, Paint paint) =>
canvas.drawImageRect(image, src, dst, paint);
@override
void drawLine(Offset p1, Offset p2, Paint paint) =>
canvas.drawLine(p1, p2, paint);
@override
void drawOval(Rect rect, Paint paint) => canvas.drawOval(rect, paint);
@override
void drawPaint(Paint paint) => canvas.drawPaint(paint);
@override
void drawParagraph(Paragraph paragraph, Offset offset) =>
canvas.drawParagraph(paragraph, offset);
@override
void drawPath(Path path, Paint paint) => canvas.drawPath(path, paint);
@override
void drawPicture(Picture picture) => canvas.drawPicture(picture);
@override
void drawPoints(PointMode pointMode, List<Offset> points, Paint paint) =>
canvas.drawPoints(pointMode, points, paint);
@override
void drawRRect(RRect rrect, Paint paint) => canvas.drawRRect(rrect, paint);
@override
void drawRawAtlas(
Image atlas,
Float32List rstTransforms,
Float32List rects,
Int32List? colors,
BlendMode? blendMode,
Rect? cullRect,
Paint paint,
) =>
canvas.drawRawAtlas(
atlas,
rstTransforms,
rects,
colors,
blendMode,
cullRect,
paint,
);
@override
void drawRawPoints(PointMode pointMode, Float32List points, Paint paint) =>
canvas.drawRawPoints(pointMode, points, paint);
@override
void drawRect(Rect rect, Paint paint) => canvas.drawRect(rect, paint);
@override
void drawShadow(
Path path,
Color color,
double elevation,
bool transparentOccluder,
) =>
canvas.drawShadow(path, color, elevation, transparentOccluder);
@override
void drawVertices(Vertices vertices, BlendMode blendMode, Paint paint) =>
canvas.drawVertices(vertices, blendMode, paint);
@override
int getSaveCount() => canvas.getSaveCount();
@override
void restore() => canvas.restore();
@override
void rotate(double radians) => canvas.rotate(radians);
@override
void save() => canvas.save();
@override
void saveLayer(Rect? bounds, Paint paint) => canvas.saveLayer(bounds, paint);
@override
void scale(double sx, [double? sy]) => canvas.scale(sx);
@override
void skew(double sx, double sy) => canvas.skew(sx, sy);
@override
void transform(Float64List matrix4) => canvas.transform(matrix4);
@override
void translate(double dx, double dy) => canvas.translate(dx, dy);
}

@ -0,0 +1,24 @@
// ignore_for_file: public_member_api_docs
import 'dart:ui' show Canvas;
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:pinball_flame/src/rendering/rendering.dart';
class PinballCanvasComponent extends Component {
PinballCanvasComponent({
required Camera camera,
Iterable<Component>? children,
}) : _pinballCanvas = PinballCanvas(camera: camera),
super(children: children);
final PinballCanvas _pinballCanvas;
@override
void renderTree(Canvas canvas) {
_pinballCanvas.canvas = canvas;
super.renderTree(_pinballCanvas);
_pinballCanvas.render();
}
}

@ -0,0 +1,3 @@
export 'pinball_canvas.dart';
export 'pinball_canvas_component.dart';
export 'rendering_mixin.dart';

@ -0,0 +1,18 @@
// ignore_for_file: public_member_api_docs
import 'dart:ui';
import 'package:flame/components.dart';
import 'package:pinball_flame/src/rendering/rendering.dart';
mixin Rendering on Component {
int zIndex = 0;
@override
void renderTree(Canvas canvas) {
if (canvas is PinballCanvas) {
canvas.buffer(this);
} else {
super.renderTree(canvas);
}
}
}
Loading…
Cancel
Save