mirror of https://github.com/flutter/pinball.git
feat: implemented ChromeDino mechanics (#76)
* feat: included ChromeDino in Board * feat: made ChromeDino sweep * feat: enclosed ChromeDino * feat: included ChromeDino in Board * feat: included initial file * feat: made ChromeDino sweep * feat: enclosed ChromeDino * feat: positioned and clean * feat: used ChromeDinoJoint * feat: used a Timer in ChromeDino animation * feat: positioned ChromeDino * feat: adjusted motor values * feat: created test file * feat: included tests * refactor: used TimerComponent * feat: adjusted ChromeDino * refactor: renamed test variable * refactor: removed redundant test * fix: included components import * refactor: removed joint member * refactor: included missing new line * docs: fixed "dinosaur" typo Co-authored-by: Erick <erickzanardoo@gmail.com> Co-authored-by: Rui Miguel Alonso <ruiskas@gmail.com>pull/108/head
parent
e0bfe3015c
commit
6f32c4f2b8
@ -0,0 +1,169 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'package:flame/components.dart';
|
||||||
|
import 'package:flame_forge2d/flame_forge2d.dart' hide Timer;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
import 'package:pinball_components/pinball_components.dart';
|
||||||
|
|
||||||
|
/// {@template chrome_dino}
|
||||||
|
/// Dinosaur that gobbles up a [Ball], swivel his head around, and shoots it
|
||||||
|
/// back out.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class ChromeDino extends BodyComponent with InitialPosition {
|
||||||
|
/// {@macro chrome_dino}
|
||||||
|
ChromeDino() {
|
||||||
|
// TODO(alestiago): Remove once sprites are defined.
|
||||||
|
paint = Paint()..color = Colors.blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The size of the dinosaur mouth.
|
||||||
|
static final size = Vector2(5, 2.5);
|
||||||
|
|
||||||
|
/// Anchors the [ChromeDino] to the [RevoluteJoint] that controls its arc
|
||||||
|
/// motion.
|
||||||
|
Future<_ChromeDinoJoint> _anchorToJoint() async {
|
||||||
|
final anchor = _ChromeDinoAnchor(chromeDino: this);
|
||||||
|
await add(anchor);
|
||||||
|
|
||||||
|
final jointDef = _ChromeDinoAnchorRevoluteJointDef(
|
||||||
|
chromeDino: this,
|
||||||
|
anchor: anchor,
|
||||||
|
);
|
||||||
|
final joint = _ChromeDinoJoint(jointDef);
|
||||||
|
world.createJoint2(joint);
|
||||||
|
|
||||||
|
return joint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onLoad() async {
|
||||||
|
await super.onLoad();
|
||||||
|
final joint = await _anchorToJoint();
|
||||||
|
await add(
|
||||||
|
TimerComponent(
|
||||||
|
period: 1,
|
||||||
|
onTick: joint.swivel,
|
||||||
|
repeat: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FixtureDef> _createFixtureDefs() {
|
||||||
|
final fixtureDefs = <FixtureDef>[];
|
||||||
|
|
||||||
|
// TODO(alestiago): Subject to change when sprites are added.
|
||||||
|
final box = PolygonShape()..setAsBoxXY(size.x / 2, size.y / 2);
|
||||||
|
final fixtureDef = FixtureDef(box)
|
||||||
|
..shape = box
|
||||||
|
..density = 999
|
||||||
|
..friction = 0.3
|
||||||
|
..restitution = 0.1
|
||||||
|
..isSensor = true;
|
||||||
|
fixtureDefs.add(fixtureDef);
|
||||||
|
|
||||||
|
// FIXME(alestiago): Investigate why adding these fixtures is considered as
|
||||||
|
// an invalid contact type.
|
||||||
|
// final upperEdge = EdgeShape()
|
||||||
|
// ..set(
|
||||||
|
// Vector2(-size.x / 2, -size.y / 2),
|
||||||
|
// Vector2(size.x / 2, -size.y / 2),
|
||||||
|
// );
|
||||||
|
// final upperEdgeDef = FixtureDef(upperEdge)..density = 0.5;
|
||||||
|
// fixtureDefs.add(upperEdgeDef);
|
||||||
|
|
||||||
|
// final lowerEdge = EdgeShape()
|
||||||
|
// ..set(
|
||||||
|
// Vector2(-size.x / 2, size.y / 2),
|
||||||
|
// Vector2(size.x / 2, size.y / 2),
|
||||||
|
// );
|
||||||
|
// final lowerEdgeDef = FixtureDef(lowerEdge)..density = 0.5;
|
||||||
|
// fixtureDefs.add(lowerEdgeDef);
|
||||||
|
|
||||||
|
// final rightEdge = EdgeShape()
|
||||||
|
// ..set(
|
||||||
|
// Vector2(size.x / 2, -size.y / 2),
|
||||||
|
// Vector2(size.x / 2, size.y / 2),
|
||||||
|
// );
|
||||||
|
// final rightEdgeDef = FixtureDef(rightEdge)..density = 0.5;
|
||||||
|
// fixtureDefs.add(rightEdgeDef);
|
||||||
|
|
||||||
|
return fixtureDefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Body createBody() {
|
||||||
|
final bodyDef = BodyDef()
|
||||||
|
..gravityScale = 0
|
||||||
|
..position = initialPosition
|
||||||
|
..type = BodyType.dynamic;
|
||||||
|
|
||||||
|
final body = world.createBody(bodyDef);
|
||||||
|
_createFixtureDefs().forEach(body.createFixture);
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@template flipper_anchor}
|
||||||
|
/// [JointAnchor] positioned at the end of a [ChromeDino].
|
||||||
|
/// {@endtemplate}
|
||||||
|
class _ChromeDinoAnchor extends JointAnchor {
|
||||||
|
/// {@macro flipper_anchor}
|
||||||
|
_ChromeDinoAnchor({
|
||||||
|
required ChromeDino chromeDino,
|
||||||
|
}) {
|
||||||
|
initialPosition = Vector2(
|
||||||
|
chromeDino.body.position.x + ChromeDino.size.x / 2,
|
||||||
|
chromeDino.body.position.y,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@template chrome_dino_anchor_revolute_joint_def}
|
||||||
|
/// Hinges a [ChromeDino] to a [_ChromeDinoAnchor].
|
||||||
|
/// {@endtemplate}
|
||||||
|
class _ChromeDinoAnchorRevoluteJointDef extends RevoluteJointDef {
|
||||||
|
/// {@macro chrome_dino_anchor_revolute_joint_def}
|
||||||
|
_ChromeDinoAnchorRevoluteJointDef({
|
||||||
|
required ChromeDino chromeDino,
|
||||||
|
required _ChromeDinoAnchor anchor,
|
||||||
|
}) {
|
||||||
|
initialize(
|
||||||
|
chromeDino.body,
|
||||||
|
anchor.body,
|
||||||
|
anchor.body.position,
|
||||||
|
);
|
||||||
|
enableLimit = true;
|
||||||
|
// TODO(alestiago): Apply design angle value.
|
||||||
|
const angle = math.pi / 3.5;
|
||||||
|
lowerAngle = -angle / 2;
|
||||||
|
upperAngle = angle / 2;
|
||||||
|
|
||||||
|
enableMotor = true;
|
||||||
|
// TODO(alestiago): Tune this values.
|
||||||
|
maxMotorTorque = motorSpeed = chromeDino.body.mass * 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChromeDinoJoint extends RevoluteJoint {
|
||||||
|
_ChromeDinoJoint(_ChromeDinoAnchorRevoluteJointDef def) : super(def);
|
||||||
|
|
||||||
|
/// Sweeps the [ChromeDino] up and down repeatedly.
|
||||||
|
void swivel() {
|
||||||
|
setMotorSpeed(-motorSpeed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension on World {
|
||||||
|
// TODO(alestiago): Remove once Forge2D supports custom joints.
|
||||||
|
void createJoint2(Joint joint) {
|
||||||
|
assert(!isLocked, '');
|
||||||
|
|
||||||
|
joints.add(joint);
|
||||||
|
|
||||||
|
joint.bodyA.joints.add(joint);
|
||||||
|
joint.bodyB.joints.add(joint);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flame_forge2d/flame_forge2d.dart';
|
||||||
|
import 'package:flame_test/flame_test.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:pinball/game/game.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final flameTester = FlameTester(Forge2DGame.new);
|
||||||
|
|
||||||
|
group('ChromeDino', () {
|
||||||
|
flameTester.test(
|
||||||
|
'loads correctly',
|
||||||
|
(game) async {
|
||||||
|
final chromeDino = ChromeDino();
|
||||||
|
|
||||||
|
await game.ready();
|
||||||
|
await game.ensureAdd(chromeDino);
|
||||||
|
|
||||||
|
expect(game.contains(chromeDino), isTrue);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in new issue