flutter/packages/flutter_sprites/lib/physics_joint.dart

182 lines
4.5 KiB
Dart

part of skysprites;
abstract class PhysicsJoint {
PhysicsJoint(this.bodyA, this.bodyB, this.breakingForce) {
bodyA._joints.add(this);
bodyB._joints.add(this);
}
final PhysicsBody bodyA;
final PhysicsBody bodyB;
final double breakingForce;
bool _active = true;
box2d.Joint _joint;
PhysicsNode _physicsNode;
void _completeCreation() {
if (bodyA._attached && bodyB._attached) {
_attach(bodyA._physicsNode);
}
}
void _attach(PhysicsNode physicsNode) {
if (_joint == null) {
_physicsNode = physicsNode;
_joint = _createB2Joint(physicsNode);
_physicsNode._joints.add(this);
}
}
void _detach() {
if (_joint != null && _active) {
_physicsNode.b2World.destroyJoint(_joint);
_joint = null;
_physicsNode._joints.remove(this);
}
_active = false;
}
box2d.Joint _createB2Joint(PhysicsNode physicsNode);
void destroy() {
_detach();
}
void _checkBreakingForce(double dt) {
if (breakingForce == null) return;
if (_joint != null && _active) {
Vector2 reactionForce = new Vector2.zero();
_joint.getReactionForce(1.0 / dt, reactionForce);
if (breakingForce * breakingForce < reactionForce.length2) {
// TODO: Add callback
destroy();
}
}
}
}
class PhysicsJointRevolute extends PhysicsJoint {
PhysicsJointRevolute(
PhysicsBody bodyA,
PhysicsBody bodyB,
this.worldAnchor, {
this.lowerAngle: 0.0,
this.upperAngle: 0.0,
this.enableLimit: false,
double breakingForce
}) : super(bodyA, bodyB, breakingForce) {
_completeCreation();
}
final Point worldAnchor;
final double lowerAngle;
final double upperAngle;
final bool enableLimit;
box2d.Joint _createB2Joint(PhysicsNode physicsNode) {
// Create Joint Definition
Vector2 vecAnchor = new Vector2(
worldAnchor.x / physicsNode.b2WorldToNodeConversionFactor,
worldAnchor.y / physicsNode.b2WorldToNodeConversionFactor
);
box2d.RevoluteJointDef b2Def = new box2d.RevoluteJointDef();
b2Def.initialize(bodyA._body, bodyB._body, vecAnchor);
b2Def.enableLimit = enableLimit;
b2Def.lowerAngle = lowerAngle;
b2Def.upperAngle = upperAngle;
// Create joint
return physicsNode.b2World.createJoint(b2Def);
}
}
class PhysicsJointPrismatic extends PhysicsJoint {
PhysicsJointPrismatic(
PhysicsBody bodyA,
PhysicsBody bodyB,
this.axis, {
double breakingForce
}
) : super(bodyA, bodyB, breakingForce) {
_completeCreation();
}
Offset axis;
box2d.Joint _createB2Joint(PhysicsNode physicsNode) {
box2d.PrismaticJointDef b2Def = new box2d.PrismaticJointDef();
b2Def.initialize(bodyA._body, bodyB._body, bodyA._body.position, new Vector2(axis.dx, axis.dy));
return physicsNode.b2World.createJoint(b2Def);
}
}
class PhysicsJointWeld extends PhysicsJoint {
PhysicsJointWeld(
PhysicsBody bodyA,
PhysicsBody bodyB, {
double breakingForce
}
) : super(bodyA, bodyB, breakingForce) {
_completeCreation();
}
box2d.Joint _createB2Joint(PhysicsNode physicsNode) {
box2d.WeldJointDef b2Def = new box2d.WeldJointDef();
Vector2 middle = new Vector2(
(bodyA._body.position.x + bodyB._body.position.x) / 2.0,
(bodyA._body.position.y + bodyB._body.position.y) / 2.0
);
b2Def.initialize(bodyA._body, bodyB._body, middle);
return physicsNode.b2World.createJoint(b2Def);
}
}
class PhysicsJointPulley extends PhysicsJoint {
PhysicsJointPulley(
PhysicsBody bodyA,
PhysicsBody bodyB,
this.groundAnchorA,
this.groundAnchorB,
this.anchorA,
this.anchorB,
this.ratio, {
double breakingForce
}
) : super(bodyA, bodyB, breakingForce) {
_completeCreation();
}
final Point groundAnchorA;
final Point groundAnchorB;
final Point anchorA;
final Point anchorB;
final double ratio;
box2d.Joint _createB2Joint(PhysicsNode physicsNode) {
box2d.PulleyJointDef b2Def = new box2d.PulleyJointDef();
b2Def.initialize(
bodyA._body,
bodyB._body,
_convertPosToVec(groundAnchorA, physicsNode),
_convertPosToVec(groundAnchorB, physicsNode),
_convertPosToVec(anchorA, physicsNode),
_convertPosToVec(anchorB, physicsNode),
ratio
);
return physicsNode.b2World.createJoint(b2Def);
}
}
Vector2 _convertPosToVec(Point pt, PhysicsNode physicsNode) {
return new Vector2(
pt.x / physicsNode.b2WorldToNodeConversionFactor,
pt.y / physicsNode.b2WorldToNodeConversionFactor
);
}