diff --git a/assets/images/components/sauce.png b/assets/images/components/sauce.png new file mode 100644 index 00000000..743a920a Binary files /dev/null and b/assets/images/components/sauce.png differ diff --git a/assets/images/components/spaceship/lower.png b/assets/images/components/spaceship/lower.png new file mode 100644 index 00000000..1f0d9b10 Binary files /dev/null and b/assets/images/components/spaceship/lower.png differ diff --git a/assets/images/components/spaceship/sauce.png b/assets/images/components/spaceship/sauce.png new file mode 100644 index 00000000..93af98b5 Binary files /dev/null and b/assets/images/components/spaceship/sauce.png differ diff --git a/assets/images/components/spaceship/upper.png b/assets/images/components/spaceship/upper.png new file mode 100644 index 00000000..0e03cec8 Binary files /dev/null and b/assets/images/components/spaceship/upper.png differ diff --git a/lib/game/components/components.dart b/lib/game/components/components.dart index 86fa3845..db538c88 100644 --- a/lib/game/components/components.dart +++ b/lib/game/components/components.dart @@ -11,4 +11,5 @@ export 'plunger.dart'; export 'round_bumper.dart'; export 'score_points.dart'; export 'sling_shot.dart'; +export 'spaceship.dart'; export 'wall.dart'; diff --git a/lib/game/components/spaceship.dart b/lib/game/components/spaceship.dart new file mode 100644 index 00000000..6a2cff00 --- /dev/null +++ b/lib/game/components/spaceship.dart @@ -0,0 +1,248 @@ +// ignore_for_file: avoid_renaming_method_parameters + +import 'dart:async'; +import 'dart:math'; + +import 'package:flame/components.dart'; +import 'package:flame_forge2d/body_component.dart'; +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:flutter/material.dart'; +import 'package:pinball/game/game.dart'; + +const _spaceShipBits = 0x0002; + +class Spaceship extends Component { + static const size = 20.0; +} + +class SpaceshipSauce extends BodyComponent { + SpaceshipSauce(this.position) : super(priority: 2); + + // TODO change to initial position + + final Vector2 position; + + static const sauceSpritePath = 'components/spaceship/sauce.png'; + static const upperWallPath = 'components/spaceship/upper.png'; + + @override + Future onLoad() async { + await super.onLoad(); + final sprites = await Future.wait([ + gameRef.loadSprite(sauceSpritePath), + gameRef.loadSprite(upperWallPath), + ]); + + await add( + SpriteComponent( + sprite: sprites.first, + size: Vector2.all(Spaceship.size), + anchor: Anchor.center, + ), + ); + + await add( + SpriteComponent( + sprite: sprites.last, + size: Vector2(Spaceship.size + 0.5, Spaceship.size / 2), + anchor: Anchor.center, + position: Vector2(0, -(Spaceship.size / 3.5)), + ), + ); + + renderBody = false; + } + + @override + Body createBody() { + final circleShape = CircleShape()..radius = Spaceship.size / 2; + + final bodyDef = BodyDef() + ..userData = this + ..position = position + ..type = BodyType.static; + + return world.createBody(bodyDef) + ..createFixture( + FixtureDef(circleShape) + ..isSensor = true + ..filter.maskBits = _spaceShipBits + ..filter.categoryBits = _spaceShipBits, + ); + } +} + +class SpaceshipEntrance extends BodyComponent { + SpaceshipEntrance(this.position); + + // TODO change to initial position + + final Vector2 position; + + @override + Body createBody() { + const r = Spaceship.size / 2; + final entranceShape = PolygonShape() + ..setAsEdge( + Vector2( + r * cos(20 * pi / 180), + r * sin(20 * pi / 180), + ), + Vector2( + r * cos(340 * pi / 180), + r * sin(340 * pi / 180), + ), + ); + + final bodyDef = BodyDef() + ..userData = this + ..position = position + ..angle = 90 * pi / 180 + ..type = BodyType.static; + + return world.createBody(bodyDef) + ..createFixture( + FixtureDef(entranceShape)..isSensor = true, + ); + } +} + +class SpaceshipBridge extends BodyComponent { + SpaceshipBridge(this.position) : super(priority: 3); + + // TODO change to initial position + final Vector2 position; + + @override + Body createBody() { + final circleShape = CircleShape()..radius = Spaceship.size / 5; + paint = Paint()..color = Colors.green; + + final bodyDef = BodyDef() + ..userData = this + ..position = position + ..type = BodyType.static; + + return world.createBody(bodyDef) + ..createFixture( + FixtureDef(circleShape) + ..restitution = 0.4 + ..filter.maskBits = _spaceShipBits + ..filter.categoryBits = _spaceShipBits, + ); + } +} + +class SpaceshipHole extends BodyComponent { + SpaceshipHole(this.position); + + // TODO change to initial position + final Vector2 position; + + @override + Body createBody() { + renderBody = false; + final circleShape = CircleShape()..radius = Spaceship.size / 14; + + final bodyDef = BodyDef() + ..userData = this + ..position = position + ..type = BodyType.static; + + return world.createBody(bodyDef) + ..createFixture( + FixtureDef(circleShape) + ..isSensor = true + ..filter.maskBits = _spaceShipBits + ..filter.categoryBits = _spaceShipBits, + ); + } +} + +class SpaceshipWall extends BodyComponent { + SpaceshipWall(this.position) : super(priority: 4); + + // TODO change to initial position + + final Vector2 position; + + static const lowerWallPath = 'components/spaceship/lower.png'; + + @override + Future onLoad() async { + await super.onLoad(); + + final sprite = await gameRef.loadSprite(lowerWallPath); + + await add( + SpriteComponent( + sprite: sprite, + size: Vector2(Spaceship.size, (Spaceship.size / 2) + 1), + anchor: Anchor.center, + position: Vector2(-Spaceship.size / 4, 0), + angle: 90 * pi / 180, + ), + ); + } + + @override + Body createBody() { + renderBody = false; + + const r = Spaceship.size / 2; + + final wallShape = ChainShape() + ..createChain( + [ + for (var a = 20; a <= 340; a++) + Vector2( + r * cos(a * pi / 180), + r * sin(a * pi / 180), + ), + ], + ); + + final bodyDef = BodyDef() + ..userData = this + ..position = position + ..angle = 90 * pi / 180 + ..type = BodyType.static; + + return world.createBody(bodyDef) + ..createFixture( + FixtureDef(wallShape) + ..restitution = 0.8 + ..filter.maskBits = _spaceShipBits + ..filter.categoryBits = _spaceShipBits, + ); + } +} + +class SpaceshipEntranceBallContactCallback + extends ContactCallback { + @override + void begin(SpaceshipEntrance entrance, Ball ball, Contact contact) { + ball + ..priority = 3 + ..gameRef.reorderChildren(); + + for (final fixture in ball.body.fixtures) { + fixture.filterData.categoryBits = _spaceShipBits; + fixture.filterData.maskBits = _spaceShipBits; + } + } +} + +class SpaceshipHoleBallContactCallback + extends ContactCallback { + @override + void begin(SpaceshipHole hole, Ball ball, Contact contact) { + ball.priority = 1; + ball.gameRef.reorderChildren(); + + for (final fixture in ball.body.fixtures) { + fixture.filterData.categoryBits = 0xFFFF; + fixture.filterData.maskBits = 0x0001; + } + } +} diff --git a/lib/game/pinball_game.dart b/lib/game/pinball_game.dart index c0017b33..9b273081 100644 --- a/lib/game/pinball_game.dart +++ b/lib/game/pinball_game.dart @@ -28,6 +28,8 @@ class PinballGame extends Forge2DGame await _addGameBoundaries(); unawaited(_addPlunger()); + unawaited(_addSpaceship()); + // Corner wall above plunger so the ball deflects into the rest of the // board. // TODO(allisonryan0002): remove once we have the launch track for the ball. @@ -77,6 +79,20 @@ class PinballGame extends Forge2DGame ); } + Future _addSpaceship() async{ + final position = Vector2(20, -24); + unawaited(add(SpaceshipSauce(position))); + unawaited(add(SpaceshipEntrance(position))); + unawaited(add(SpaceshipBridge(position))); + + unawaited(add(SpaceshipHole(position - Vector2(5, 5)))); + unawaited(add(SpaceshipHole(position - Vector2(-5, 5)))); + + unawaited( + add(SpaceshipWall(position)), + ); + } + void spawnBall() { final ball = Ball(); add( @@ -89,6 +105,8 @@ class PinballGame extends Forge2DGame addContactCallback(BallScorePointsCallback()); addContactCallback(BottomWallBallContactCallback()); addContactCallback(BonusLetterBallContactCallback()); + addContactCallback(SpaceshipHoleBallContactCallback()); + addContactCallback(SpaceshipEntranceBallContactCallback()); } Future _addGameBoundaries() async { diff --git a/pubspec.yaml b/pubspec.yaml index abd78157..839f1d2f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,3 +40,4 @@ flutter: assets: - assets/images/components/ + - assets/images/components/spaceship/