| part of flutter_sprites; |
| |
| enum PhysicsBodyType { |
| static, |
| dynamic |
| } |
| |
| class PhysicsBody { |
| PhysicsBody(this.shape, { |
| this.tag: null, |
| this.type: PhysicsBodyType.dynamic, |
| double density: 1.0, |
| double friction: 0.0, |
| double restitution: 0.0, |
| bool isSensor: false, |
| Offset linearVelocity: Offset.zero, |
| double angularVelocity: 0.0, |
| this.linearDampening: 0.0, |
| double angularDampening: 0.0, |
| bool allowSleep: true, |
| bool awake: true, |
| bool fixedRotation: false, |
| bool bullet: false, |
| bool active: true, |
| this.gravityScale: 1.0 |
| }) { |
| this.density = density; |
| this.friction = friction; |
| this.restitution = restitution; |
| this.isSensor = isSensor; |
| |
| this.linearVelocity = linearVelocity; |
| this.angularVelocity = angularVelocity; |
| this.angularDampening = angularDampening; |
| |
| this.allowSleep = allowSleep; |
| this.awake = awake; |
| this.fixedRotation = fixedRotation; |
| this.bullet = bullet; |
| this.active = active; |
| } |
| |
| Vector2 _lastPosition; |
| double _lastRotation; |
| Vector2 _targetPosition; |
| double _targetAngle; |
| |
| Object tag; |
| |
| final PhysicsShape shape; |
| |
| PhysicsBodyType type; |
| |
| double _density; |
| |
| double get density => _density; |
| |
| set density(double density) { |
| _density = density; |
| |
| if (_body == null) |
| return; |
| for (box2d.Fixture f = _body.getFixtureList(); f != null; f = f.getNext()) { |
| f.setDensity(density); |
| } |
| } |
| |
| double _friction; |
| |
| double get friction => _friction; |
| |
| set friction(double friction) { |
| _friction = friction; |
| |
| if (_body == null) |
| return; |
| for (box2d.Fixture f = _body.getFixtureList(); f != null; f = f.getNext()) { |
| f.setFriction(friction); |
| } |
| } |
| |
| double _restitution; |
| |
| double get restitution => _restitution; |
| |
| set restitution(double restitution) { |
| _restitution = restitution; |
| |
| if (_body == null) |
| return; |
| for (box2d.Fixture f = _body.getFixtureList(); f != null; f = f.getNext()) { |
| f.setRestitution(restitution); |
| } |
| } |
| |
| bool _isSensor; |
| |
| bool get isSensor => _isSensor; |
| |
| set isSensor(bool isSensor) { |
| _isSensor = isSensor; |
| |
| if (_body == null) |
| return; |
| for (box2d.Fixture f = _body.getFixtureList(); f != null; f = f.getNext()) { |
| f.setSensor(isSensor); |
| } |
| } |
| |
| Offset _linearVelocity; |
| |
| Offset get linearVelocity { |
| if (_body == null) |
| return _linearVelocity; |
| else { |
| double dx = _body.linearVelocity.x * _physicsNode.b2WorldToNodeConversionFactor; |
| double dy = _body.linearVelocity.y * _physicsNode.b2WorldToNodeConversionFactor; |
| return new Offset(dx, dy); |
| } |
| } |
| |
| set linearVelocity(Offset linearVelocity) { |
| _linearVelocity = linearVelocity; |
| |
| if (_body != null) { |
| Vector2 vec = new Vector2( |
| linearVelocity.dx / _physicsNode.b2WorldToNodeConversionFactor, |
| linearVelocity.dy / _physicsNode.b2WorldToNodeConversionFactor |
| ); |
| _body.linearVelocity = vec; |
| } |
| } |
| |
| double _angularVelocity; |
| |
| double get angularVelocity { |
| if (_body == null) |
| return _angularVelocity; |
| else |
| return _body.angularVelocity; |
| } |
| |
| set angularVelocity(double angularVelocity) { |
| _angularVelocity = angularVelocity; |
| |
| if (_body != null) { |
| _body.angularVelocity = angularVelocity; |
| } |
| } |
| |
| // TODO: Should this be editable in box2d.Body ? |
| final double linearDampening; |
| |
| double _angularDampening; |
| |
| double get angularDampening => _angularDampening; |
| |
| set angularDampening(double angularDampening) { |
| _angularDampening = angularDampening; |
| |
| if (_body != null) |
| _body.angularDamping = angularDampening; |
| } |
| |
| bool _allowSleep; |
| |
| bool get allowSleep => _allowSleep; |
| |
| set allowSleep(bool allowSleep) { |
| _allowSleep = allowSleep; |
| |
| if (_body != null) |
| _body.setSleepingAllowed(allowSleep); |
| } |
| |
| bool _awake; |
| |
| bool get awake { |
| if (_body != null) |
| return _body.isAwake(); |
| else |
| return _awake; |
| } |
| |
| set awake(bool awake) { |
| _awake = awake; |
| |
| if (_body != null) |
| _body.setAwake(awake); |
| } |
| |
| bool _fixedRotation; |
| |
| bool get fixedRotation => _fixedRotation; |
| |
| set fixedRotation(bool fixedRotation) { |
| _fixedRotation = fixedRotation; |
| |
| if (_body != null) |
| _body.setFixedRotation(fixedRotation); |
| } |
| |
| bool _bullet; |
| |
| bool get bullet => _bullet; |
| |
| set bullet(bool bullet) { |
| _bullet = bullet; |
| |
| if (_body != null) { |
| _body.setBullet(bullet); |
| } |
| } |
| |
| bool _active; |
| |
| bool get active { |
| if (_body != null) |
| return _body.isActive(); |
| else |
| return _active; |
| } |
| |
| set active(bool active) { |
| _active = active; |
| |
| if (_body != null) |
| _body.setActive(active); |
| } |
| |
| double gravityScale; |
| |
| PhysicsNode _physicsNode; |
| Node _node; |
| |
| box2d.Body _body; |
| |
| List<PhysicsJoint> _joints = []; |
| |
| bool _attached = false; |
| |
| void applyForce(Offset force, Point worldPoint) { |
| assert(_body != null); |
| |
| Vector2 b2Force = new Vector2( |
| force.dx / _physicsNode.b2WorldToNodeConversionFactor, |
| force.dy / _physicsNode.b2WorldToNodeConversionFactor); |
| |
| Vector2 b2Point = new Vector2( |
| worldPoint.x / _physicsNode.b2WorldToNodeConversionFactor, |
| worldPoint.y / _physicsNode.b2WorldToNodeConversionFactor |
| ); |
| |
| _body.applyForce(b2Force, b2Point); |
| } |
| |
| void applyForceToCenter(Offset force) { |
| assert(_body != null); |
| |
| Vector2 b2Force = new Vector2( |
| force.dx / _physicsNode.b2WorldToNodeConversionFactor, |
| force.dy / _physicsNode.b2WorldToNodeConversionFactor); |
| |
| _body.applyForceToCenter(b2Force); |
| } |
| |
| void applyTorque(double torque) { |
| assert(_body != null); |
| |
| _body.applyTorque(torque / _physicsNode.b2WorldToNodeConversionFactor); |
| } |
| |
| void applyLinearImpulse(Offset impulse, Point worldPoint, [bool wake = true]) { |
| assert(_body != null); |
| |
| Vector2 b2Impulse = new Vector2( |
| impulse.dx / _physicsNode.b2WorldToNodeConversionFactor, |
| impulse.dy / _physicsNode.b2WorldToNodeConversionFactor); |
| |
| Vector2 b2Point = new Vector2( |
| worldPoint.x / _physicsNode.b2WorldToNodeConversionFactor, |
| worldPoint.y / _physicsNode.b2WorldToNodeConversionFactor |
| ); |
| |
| _body.applyLinearImpulse(b2Impulse, b2Point, wake); |
| } |
| |
| void applyAngularImpulse(double impulse) { |
| assert(_body != null); |
| |
| _body.applyAngularImpulse(impulse / _physicsNode.b2WorldToNodeConversionFactor); |
| } |
| |
| void _attach(PhysicsNode physicsNode, Node node) { |
| assert(_attached == false); |
| |
| // Create BodyDef |
| box2d.BodyDef bodyDef = new box2d.BodyDef(); |
| bodyDef.linearVelocity = new Vector2(linearVelocity.dx, linearVelocity.dy); |
| bodyDef.angularVelocity = angularVelocity; |
| bodyDef.linearDamping = linearDampening; |
| bodyDef.angularDamping = angularDampening; |
| bodyDef.allowSleep = allowSleep; |
| bodyDef.awake = awake; |
| bodyDef.fixedRotation = fixedRotation; |
| bodyDef.bullet = bullet; |
| bodyDef.active = active; |
| bodyDef.gravityScale = gravityScale; |
| if (type == PhysicsBodyType.dynamic) |
| bodyDef.type = box2d.BodyType.DYNAMIC; |
| else |
| bodyDef.type = box2d.BodyType.STATIC; |
| |
| double conv = physicsNode.b2WorldToNodeConversionFactor; |
| bodyDef.position = new Vector2(node.position.x / conv, node.position.y / conv); |
| bodyDef.angle = radians(node.rotation); |
| |
| // Create Body |
| _body = physicsNode.b2World.createBody(bodyDef); |
| |
| // Create FixtureDef |
| box2d.FixtureDef fixtureDef = new box2d.FixtureDef(); |
| fixtureDef.friction = friction; |
| fixtureDef.restitution = restitution; |
| fixtureDef.density = density; |
| fixtureDef.isSensor = isSensor; |
| |
| // Get shapes |
| List<box2d.Shape> b2Shapes = []; |
| List<PhysicsShape> physicsShapes = []; |
| _addB2Shapes(physicsNode, shape, b2Shapes, physicsShapes); |
| |
| // Create fixtures |
| for (int i = 0; i < b2Shapes.length; i++) { |
| box2d.Shape b2Shape = b2Shapes[i]; |
| PhysicsShape physicsShape = physicsShapes[i]; |
| |
| fixtureDef.shape = b2Shape; |
| box2d.Fixture fixture = _body.createFixtureFromFixtureDef(fixtureDef); |
| fixture.userData = physicsShape; |
| } |
| _body.userData = this; |
| |
| _physicsNode = physicsNode; |
| _node = node; |
| |
| _attached = true; |
| |
| // Attach any joints |
| for (PhysicsJoint joint in _joints) { |
| if (joint.bodyA._attached && joint.bodyB._attached) { |
| joint._attach(physicsNode); |
| } |
| } |
| } |
| |
| void _detach() { |
| if (_attached) { |
| _physicsNode._bodiesScheduledForDestruction.add(_body); |
| _attached = false; |
| } |
| } |
| |
| void _addB2Shapes(PhysicsNode physicsNode, PhysicsShape shape, List<box2d.Shape> b2Shapes, List<PhysicsShape> physicsShapes) { |
| if (shape is PhysicsShapeGroup) { |
| for (PhysicsShape child in shape.shapes) { |
| _addB2Shapes(physicsNode, child, b2Shapes, physicsShapes); |
| } |
| } else { |
| b2Shapes.add(shape.getB2Shape(physicsNode)); |
| physicsShapes.add(shape); |
| } |
| } |
| } |