From 91b1cf9d14373aefbf395ca6465a6b2ccf20a28a Mon Sep 17 00:00:00 2001 From: Viktor Lidholt Date: Tue, 20 Oct 2015 10:35:40 -0700 Subject: [PATCH] Adds sprite physics groups --- skysprites/lib/flutter_sprites.dart | 1 + skysprites/lib/src/node.dart | 46 +++++++++-- skysprites/lib/src/physics_group.dart | 107 ++++++++++++++++++++++++++ skysprites/lib/src/physics_world.dart | 10 +++ 4 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 skysprites/lib/src/physics_group.dart diff --git a/skysprites/lib/flutter_sprites.dart b/skysprites/lib/flutter_sprites.dart index 4203fd978de..97b48b3d5d9 100644 --- a/skysprites/lib/flutter_sprites.dart +++ b/skysprites/lib/flutter_sprites.dart @@ -35,6 +35,7 @@ part 'src/node_with_size.dart'; part 'src/particle_system.dart'; part 'src/physics_body.dart'; part 'src/physics_debug.dart'; +part 'src/physics_group.dart'; part 'src/physics_joint.dart'; part 'src/physics_shape.dart'; part 'src/physics_world.dart'; diff --git a/skysprites/lib/src/node.dart b/skysprites/lib/src/node.dart index 51011e949c2..7b9e0e04642 100644 --- a/skysprites/lib/src/node.dart +++ b/skysprites/lib/src/node.dart @@ -132,9 +132,8 @@ class Node { void set rotation(double rotation) { assert(rotation != null); - if (_physicsBody != null && parent is PhysicsWorld) { - PhysicsWorld physicsNode = parent; - physicsNode._updateRotation(this.physicsBody, rotation); + if (_physicsBody != null && (parent is PhysicsWorld || parent is PhysicsGroup)) { + _updatePhysicsRotation(physicsBody, rotation, parent); return; } @@ -142,6 +141,19 @@ class Node { invalidateTransformMatrix(); } + void _updatePhysicsRotation(PhysicsBody body, double rotation, Node physicsParent) { + if (physicsParent == null) return; + + if (physicsParent is PhysicsWorld) { + PhysicsWorld world = physicsParent; + world._updateRotation(body, rotation); + } else if (physicsParent is PhysicsGroup) { + _updatePhysicsRotation(body, rotation + physicsParent.rotation, physicsParent.parent); + } else { + assert(false); + } + } + void _setRotationFromPhysics(double rotation) { assert(rotation != null); _rotation = rotation; @@ -166,9 +178,8 @@ class Node { void set position(Point position) { assert(position != null); - if (_physicsBody != null && parent is PhysicsWorld) { - PhysicsWorld physicsNode = parent; - physicsNode._updatePosition(this.physicsBody, position); + if (_physicsBody != null && (parent is PhysicsWorld || parent is PhysicsGroup)) { + _updatePhysicsPosition(this.physicsBody, position, parent); return; } @@ -176,6 +187,20 @@ class Node { invalidateTransformMatrix(); } + void _updatePhysicsPosition(PhysicsBody body, Point position, Node physicsParent) { + if (physicsParent == null) return; + + if (physicsParent is PhysicsWorld) { + PhysicsWorld world = physicsParent; + world._updatePosition(body, position); + } else if (physicsParent is PhysicsGroup) { + 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); + } else { + assert(false); + } + } + void _setPositionFromPhysics(Point position) { assert(position != null); _position = position; @@ -310,6 +335,7 @@ class Node { void addChild(Node child) { assert(child != null); assert(child._parent == null); + assert(!(child is PhysicsGroup) || this is PhysicsGroup || this is PhysicsWorld); _childrenNeedSorting = true; _children.add(child); @@ -318,6 +344,10 @@ class Node { _childrenLastAddedOrder += 1; child._addedOrder = _childrenLastAddedOrder; if (_spriteBox != null) _spriteBox._registerNode(child); + + if (child is PhysicsGroup) { + child._attachGroup(child, child._world); + } } /// Removes a child from this node. @@ -330,6 +360,10 @@ class Node { child._spriteBox = null; if (_spriteBox != null) _spriteBox._deregisterNode(child); } + + if (child is PhysicsGroup) { + child._detachGroup(child); + } } /// Removes this node from its parent node. diff --git a/skysprites/lib/src/physics_group.dart b/skysprites/lib/src/physics_group.dart new file mode 100644 index 00000000000..b858a8eda03 --- /dev/null +++ b/skysprites/lib/src/physics_group.dart @@ -0,0 +1,107 @@ +part of flutter_sprites; + +class PhysicsGroup extends Node { + + set scaleX(double scaleX) { + assert(false); + } + + set scaleY(double scaleX) { + assert(false); + } + + set skewX(double scaleX) { + assert(false); + } + + set skewY(double scaleX) { + assert(false); + } + + set physicsBody(PhysicsBody body) { + assert(false); + } + + set position(Point position) { + super.position = position; + _invalidatePhysicsBodies(this); + } + + set rotation(double rotation) { + super.rotation = rotation; + _invalidatePhysicsBodies(this); + } + + set scale(double scale) { + super.scale = scale; + _invalidatePhysicsBodies(this); + } + + void _invalidatePhysicsBodies(Node node) { + if (_world == null) return; + + if (node.physicsBody != null) { + // TODO: Add to list + _world._bodiesScheduledForUpdate.add(node.physicsBody); + } + + for (Node child in node.children) { + _invalidatePhysicsBodies(child); + } + } + + void addChild(Node node) { + super.addChild(node); + + PhysicsWorld world = _world; + if (node.physicsBody != null && world != null) { + node.physicsBody._attach(world, node); + } + + if (node is PhysicsGroup) { + _attachGroup(this, world); + } + } + + void _attachGroup(PhysicsGroup group, PhysicsWorld world) { + for (Node child in group.children) { + if (child is PhysicsGroup) { + _attachGroup(child, world); + } else if (child.physicsBody != null) { + child.physicsBody._attach(world, child); + } + } + } + + void removeChild(Node node) { + super.removeChild(node); + + if (node.physicsBody != null) { + node.physicsBody._detach(); + } + + if (node is PhysicsGroup) { + _detachGroup(this); + } + } + + void _detachGroup(PhysicsGroup group) { + for (Node child in group.children) { + if (child is PhysicsGroup) { + _detachGroup(child); + } else if (child.physicsBody != null) { + child.physicsBody._detach(); + } + } + } + + PhysicsWorld get _world { + if (this.parent is PhysicsWorld) + return this.parent; + if (this.parent is PhysicsGroup) { + PhysicsGroup group = this.parent; + return group._world; + } + return null; + } +} diff --git a/skysprites/lib/src/physics_world.dart b/skysprites/lib/src/physics_world.dart index d8bf889b6b6..fd27e95bccb 100644 --- a/skysprites/lib/src/physics_world.dart +++ b/skysprites/lib/src/physics_world.dart @@ -43,6 +43,8 @@ class PhysicsWorld extends Node { List _bodiesScheduledForDestruction = []; + List _bodiesScheduledForUpdate = []; + _PhysicsDebugDraw _debugDraw; double b2WorldToNodeConversionFactor = 10.0; @@ -71,6 +73,14 @@ class PhysicsWorld extends Node { } void _stepPhysics(double dt) { + // Update transformations of bodies whose groups have moved + for (PhysicsBody body in _bodiesScheduledForUpdate) { + Node node = body._node; + node._updatePhysicsPosition(body, node.position, node.parent); + node._updatePhysicsRotation(body, node.rotation, node.parent); + } + _bodiesScheduledForUpdate.clear(); + // Remove bodies that were marked for destruction during the update phase _removeBodiesScheduledForDestruction();