diff --git a/examples/game/test_physics.dart b/examples/game/test_physics.dart index 00fc9e0e3f6..782f334d64c 100644 --- a/examples/game/test_physics.dart +++ b/examples/game/test_physics.dart @@ -47,12 +47,17 @@ main() async { class TestBed extends NodeWithSize { Sprite _obstacle; - PhysicsWorld _physicsNode; + PhysicsWorld _world; + PhysicsGroup _group; + PhysicsGroup _group2; TestBed() : super(new Size(1024.0, 1024.0)) { - _physicsNode = new PhysicsWorld(new Offset(0.0, 100.0)); - PhysicsGroup group = new PhysicsGroup(); - _physicsNode.addChild(group); + _world = new PhysicsWorld(new Offset(0.0, 100.0)); + _group = new PhysicsGroup(); + _group2 = new PhysicsGroup(); + _group2.position = new Point(50.0, 50.0); + _world.addChild(_group); + _world.addChild(_group2); _obstacle = new Sprite(_spriteSheet["ship.png"]); _obstacle.position = new Point(512.0, 800.0); @@ -64,64 +69,58 @@ class TestBed extends NodeWithSize { friction: 0.5, tag: "obstacle" ); - group.addChild(_obstacle); - _physicsNode.addContactCallback(myCallback, "obstacle", "ship", PhysicsContactType.begin); + _group.addChild(_obstacle); + _world.addContactCallback(myCallback, "obstacle", "ship", PhysicsContactType.begin); - // Animate obstacle + // Animate group ActionSequence seq = new ActionSequence([ - new ActionTween((a) => _obstacle.position = a, new Point(256.0, 800.0), new Point(768.0, 800.0), 1.0, Curves.easeInOut), - new ActionTween((a) => _obstacle.position = a, new Point(768.0, 800.0), new Point(256.0, 800.0), 1.0, Curves.easeInOut) + new ActionTween((a) => _group.position = a, new Point(-256.0, 0.0), new Point(256.0, 0.0), 1.0, Curves.easeInOut), + new ActionTween((a) => _group.position = a, new Point(256.0, 0.0), new Point(-256.0, 0.0), 1.0, Curves.easeInOut) ]); - _obstacle.actions.run(new ActionRepeatForever(seq)); + _group.actions.run(new ActionRepeatForever(seq)); - seq = new ActionSequence([ - new ActionTween((a) => _obstacle.scale = a, 1.0, 2.0, 2.0, Curves.easeInOut), - new ActionTween((a) => _obstacle.scale = a, 2.0, 1.0, 2.0, Curves.easeInOut) - ]); - _obstacle.actions.run(new ActionRepeatForever(seq)); - - addChild(_physicsNode); + addChild(_world); userInteractionEnabled = true; } void myCallback(PhysicsContactType type, PhysicsContact contact) { - print("CONTACT type: $type"); } bool handleEvent(SpriteBoxEvent event) { if (event.type == "pointerdown") { Point pos = convertPointToNodeSpace(event.boxPosition); + print("ADDING SHIPS"); + PhysicsGroup group = new PhysicsGroup(); + group.position = pos; + group.rotation = 10.0; + group.scale = 0.5; + _world.addChild(group); + Sprite shipA; shipA = new Sprite(_spriteSheet["ship.png"]); shipA.opacity = 0.3; - shipA.position = new Point(pos.x - 40.0, pos.y); + shipA.position = new Point(-40.0, 0.0); shipA.size = new Size(64.0, 64.0); shipA.physicsBody = new PhysicsBody(new PhysicsShapeCircle(Point.origin, 32.0), friction: 0.5, restitution: 0.5, tag: "ship" ); - _physicsNode.addChild(shipA); - shipA.physicsBody.applyLinearImpulse( - new Offset(randomSignedDouble() * 5000.0, randomSignedDouble() * 5000.0), - shipA.position - ); + group.addChild(shipA); Sprite shipB; shipB = new Sprite(_spriteSheet["ship.png"]); shipB.opacity = 0.3; - shipB.position = new Point(pos.x + 40.0, pos.y); + shipB.position = new Point(40.0, 0.0); shipB.size = new Size(64.0, 64.0); shipB.physicsBody = new PhysicsBody(new PhysicsShapePolygon([new Point(-25.0, -25.0), new Point(25.0, -25.0), new Point(25.0, 25.0), new Point(-25.0, 25.0)]), friction: 0.5, restitution: 0.5, tag: "ship" ); - _physicsNode.addChild(shipB); - - new PhysicsJointRevolute(shipA.physicsBody, shipB.physicsBody, pos); + group.addChild(shipB); } return true; } diff --git a/packages/flutter_sprites/lib/src/node.dart b/packages/flutter_sprites/lib/src/node.dart index 67982bf59cd..7189fc112ae 100644 --- a/packages/flutter_sprites/lib/src/node.dart +++ b/packages/flutter_sprites/lib/src/node.dart @@ -142,32 +142,61 @@ class Node { } void _updatePhysicsRotation(PhysicsBody body, double rotation, Node physicsParent) { - if (physicsParent == null) return; + PhysicsWorld world = _physicsWorld(physicsParent); + if (world == null) return; + world._updateRotation(body, _rotationToPhysics(rotation, physicsParent)); + } - if (physicsParent is PhysicsWorld) { - PhysicsWorld world = physicsParent; - world._updateRotation(body, rotation); - } else if (physicsParent is PhysicsGroup) { - _updatePhysicsRotation(body, rotation + physicsParent.rotation, physicsParent.parent); - } else { + PhysicsWorld _physicsWorld(Node parent) { + if (parent is PhysicsWorld) { + return parent; + } + else if (parent is PhysicsGroup) { + return _physicsWorld(parent.parent); + } + else { assert(false); + return null; } } - void _setRotationFromPhysics(double rotation) { + double _rotationToPhysics(double rotation, Node physicsParent) { + if (physicsParent is PhysicsWorld) { + return rotation; + } else if (physicsParent is PhysicsGroup) { + return _rotationToPhysics(rotation + physicsParent.rotation, physicsParent.parent); + } else { + assert(false); + return null; + } + } + + double _rotationFromPhysics(double rotation, Node physicsParent) { + if (physicsParent is PhysicsWorld) { + return rotation; + } else if (physicsParent is PhysicsGroup) { + return _rotationToPhysics(rotation - physicsParent.rotation, physicsParent.parent); + } else { + assert(false); + return null; + } + } + + void _setRotationFromPhysics(double rotation, Node physicsParent) { assert(rotation != null); - _rotation = rotation; + _rotation = _rotationFromPhysics(rotation, physicsParent); invalidateTransformMatrix(); } void teleportRotation(double rotation) { assert(rotation != null); - if (_physicsBody != null && parent is PhysicsWorld) { + if (_physicsBody != null && (parent is PhysicsWorld || parent is PhysicsGroup)) { + rotation = _rotationToPhysics(rotation, parent); _physicsBody._body.setTransform(_physicsBody._body.position, radians(rotation)); _physicsBody._body.angularVelocity = 0.0; _physicsBody._body.setType(box2d.BodyType.STATIC); } - _setRotationFromPhysics(rotation); + _setRotationFromPhysics(rotation, parent); } /// The position of this node relative to its parent. @@ -188,29 +217,51 @@ class Node { } void _updatePhysicsPosition(PhysicsBody body, Point position, Node physicsParent) { - if (physicsParent == null) return; + PhysicsWorld world = _physicsWorld(physicsParent); + if (world == null) return; + world._updatePosition(body, _positionToPhysics(position, physicsParent)); + } + Point _positionToPhysics(Point position, Node physicsParent) { if (physicsParent is PhysicsWorld) { - PhysicsWorld world = physicsParent; - world._updatePosition(body, position); + return position; } else if (physicsParent is PhysicsGroup) { + // Transform the position Vector4 parentPos = physicsParent.transformMatrix.transform(new Vector4(position.x, position.y, 0.0, 1.0)); - _updatePhysicsPosition(body, new Point(parentPos.x, parentPos.y), physicsParent.parent); + Point newPos = new Point(parentPos.x, parentPos.y); + return _positionToPhysics(newPos, physicsParent.parent); } else { assert(false); + return null; } } - void _setPositionFromPhysics(Point position) { + void _setPositionFromPhysics(Point position, Node physicsParent) { assert(position != null); - _position = position; + _position = _positionFromPhysics(position, physicsParent); invalidateTransformMatrix(); } + Point _positionFromPhysics(Point position, Node physicsParent) { + if (physicsParent is PhysicsWorld) { + return position; + } else if (physicsParent is PhysicsGroup) { + // Transform the position + Matrix4 inverseTransform = new Matrix4.copy(physicsParent.transformMatrix); + inverseTransform.invert(); + Vector4 parentPos = inverseTransform.transform(new Vector4(position.x, position.y, 0.0, 1.0)); + Point newPos = new Point(parentPos.x, parentPos.y); + return _positionToPhysics(newPos, physicsParent.parent); + } else { + assert(false); + return null; + } + } + void teleportPosition(Point position) { assert(position != null); - if (_physicsBody != null && parent is PhysicsWorld) { - PhysicsWorld physicsNode = parent; + if (_physicsBody != null && (parent is PhysicsWorld || parent is PhysicsGroup)) { + position = _positionToPhysics(position, parent); _physicsBody._body.setTransform( new Vector2( position.x / physicsNode.b2WorldToNodeConversionFactor, @@ -221,7 +272,7 @@ class Node { _physicsBody._body.linearVelocity = new Vector2.zero(); _physicsBody._body.setType(box2d.BodyType.STATIC); } - _setPositionFromPhysics(position); + _setPositionFromPhysics(position, parent); } /// The skew along the x-axis of this node in degrees. @@ -287,14 +338,17 @@ class Node { void _updatePhysicsScale(PhysicsBody body, double scale, Node physicsParent) { if (physicsParent == null) return; + _physicsWorld(physicsParent)._updateScale(body, _scaleToPhysics(scale, physicsParent)); + } + double _scaleToPhysics(double scale, Node physicsParent) { if (physicsParent is PhysicsWorld) { - PhysicsWorld world = physicsParent; - world._updateScale(body, scale); + return scale; } else if (physicsParent is PhysicsGroup) { - _updatePhysicsScale(body, scale * physicsParent.scale, physicsParent.parent); + return _scaleToPhysics(scale * physicsParent.scale, physicsParent.parent); } else { assert(false); + return null; } } diff --git a/packages/flutter_sprites/lib/src/physics_body.dart b/packages/flutter_sprites/lib/src/physics_body.dart index 98f71b47a19..095a1ba89a3 100644 --- a/packages/flutter_sprites/lib/src/physics_body.dart +++ b/packages/flutter_sprites/lib/src/physics_body.dart @@ -296,8 +296,13 @@ class PhysicsBody { void _attach(PhysicsWorld physicsNode, Node node) { assert(_attached == false); + // Account for physics groups + Point positionWorld = node._positionToPhysics(node.position, node.parent); + double rotationWorld = node._rotationToPhysics(node.rotation, node.parent); + double scaleWorld = node._scaleToPhysics(node.scale, node.parent); + // Update scale - _scale = node.scale; + _scale = scaleWorld; // Create BodyDef box2d.BodyDef bodyDef = new box2d.BodyDef(); @@ -316,9 +321,10 @@ class PhysicsBody { else bodyDef.type = box2d.BodyType.STATIC; + // Convert to world coordinates and set position and angle double conv = physicsNode.b2WorldToNodeConversionFactor; - bodyDef.position = new Vector2(node.position.x / conv, node.position.y / conv); - bodyDef.angle = radians(node.rotation); + bodyDef.position = new Vector2(positionWorld.x / conv, positionWorld.y / conv); + bodyDef.angle = radians(rotationWorld); // Create Body _body = physicsNode.b2World.createBody(bodyDef); diff --git a/packages/flutter_sprites/lib/src/physics_world.dart b/packages/flutter_sprites/lib/src/physics_world.dart index fd27e95bccb..4f6f3fcb94b 100644 --- a/packages/flutter_sprites/lib/src/physics_world.dart +++ b/packages/flutter_sprites/lib/src/physics_world.dart @@ -97,7 +97,7 @@ class PhysicsWorld extends Node { } // Update linear velocity - if (body._lastPosition == null) { + if (body._lastPosition == null || body._targetPosition == null) { b2Body.linearVelocity.setZero(); } else { Vector2 velocity = (body._targetPosition - body._lastPosition) / dt; @@ -106,7 +106,7 @@ class PhysicsWorld extends Node { } // Update angular velocity - if (body._lastRotation == null) { + if (body._lastRotation == null || body._targetAngle == null) { b2Body.angularVelocity = 0.0; } else { double angularVelocity = (body._targetAngle - body._lastRotation) / dt; @@ -129,12 +129,20 @@ class PhysicsWorld extends Node { } // Update visual position and rotation - body._node._setPositionFromPhysics(new Point( - b2Body.position.x * b2WorldToNodeConversionFactor, - b2Body.position.y * b2WorldToNodeConversionFactor - )); + if (body.type == PhysicsBodyType.dynamic) { + body._node._setPositionFromPhysics( + new Point( + b2Body.position.x * b2WorldToNodeConversionFactor, + b2Body.position.y * b2WorldToNodeConversionFactor + ), + body._node.parent + ); - body._node._setRotationFromPhysics(degrees(b2Body.getAngle())); + body._node._setRotationFromPhysics( + degrees(b2Body.getAngle()), + body._node.parent + ); + } } // Break joints