Commit 37086673 authored by Viktor Lidholt's avatar Viktor Lidholt

Fixes sprite physics to work correctly with the node graph

Teleportation for physics bodies works again
parent 545db87a
...@@ -47,12 +47,17 @@ main() async { ...@@ -47,12 +47,17 @@ main() async {
class TestBed extends NodeWithSize { class TestBed extends NodeWithSize {
Sprite _obstacle; Sprite _obstacle;
PhysicsWorld _physicsNode; PhysicsWorld _world;
PhysicsGroup _group;
PhysicsGroup _group2;
TestBed() : super(new Size(1024.0, 1024.0)) { TestBed() : super(new Size(1024.0, 1024.0)) {
_physicsNode = new PhysicsWorld(new Offset(0.0, 100.0)); _world = new PhysicsWorld(new Offset(0.0, 100.0));
PhysicsGroup group = new PhysicsGroup(); _group = new PhysicsGroup();
_physicsNode.addChild(group); _group2 = new PhysicsGroup();
_group2.position = new Point(50.0, 50.0);
_world.addChild(_group);
_world.addChild(_group2);
_obstacle = new Sprite(_spriteSheet["ship.png"]); _obstacle = new Sprite(_spriteSheet["ship.png"]);
_obstacle.position = new Point(512.0, 800.0); _obstacle.position = new Point(512.0, 800.0);
...@@ -64,23 +69,17 @@ class TestBed extends NodeWithSize { ...@@ -64,23 +69,17 @@ class TestBed extends NodeWithSize {
friction: 0.5, friction: 0.5,
tag: "obstacle" tag: "obstacle"
); );
group.addChild(_obstacle); _group.addChild(_obstacle);
_physicsNode.addContactCallback(myCallback, "obstacle", "ship", PhysicsContactType.begin); _world.addContactCallback(myCallback, "obstacle", "ship", PhysicsContactType.begin);
// Animate obstacle // Animate group
ActionSequence seq = new ActionSequence([ 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) => _group.position = a, new Point(-256.0, 0.0), new Point(256.0, 0.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)
]); ]);
_obstacle.actions.run(new ActionRepeatForever(seq)); _group.actions.run(new ActionRepeatForever(seq));
seq = new ActionSequence([ addChild(_world);
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);
userInteractionEnabled = true; userInteractionEnabled = true;
} }
...@@ -93,35 +92,36 @@ class TestBed extends NodeWithSize { ...@@ -93,35 +92,36 @@ class TestBed extends NodeWithSize {
if (event.type == "pointerdown") { if (event.type == "pointerdown") {
Point pos = convertPointToNodeSpace(event.boxPosition); 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; Sprite shipA;
shipA = new Sprite(_spriteSheet["ship.png"]); shipA = new Sprite(_spriteSheet["ship.png"]);
shipA.opacity = 0.3; 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.size = new Size(64.0, 64.0);
shipA.physicsBody = new PhysicsBody(new PhysicsShapeCircle(Point.origin, 32.0), shipA.physicsBody = new PhysicsBody(new PhysicsShapeCircle(Point.origin, 32.0),
friction: 0.5, friction: 0.5,
restitution: 0.5, restitution: 0.5,
tag: "ship" tag: "ship"
); );
_physicsNode.addChild(shipA); group.addChild(shipA);
shipA.physicsBody.applyLinearImpulse(
new Offset(randomSignedDouble() * 5000.0, randomSignedDouble() * 5000.0),
shipA.position
);
Sprite shipB; Sprite shipB;
shipB = new Sprite(_spriteSheet["ship.png"]); shipB = new Sprite(_spriteSheet["ship.png"]);
shipB.opacity = 0.3; 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.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)]), 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, friction: 0.5,
restitution: 0.5, restitution: 0.5,
tag: "ship" tag: "ship"
); );
_physicsNode.addChild(shipB); group.addChild(shipB);
new PhysicsJointRevolute(shipA.physicsBody, shipB.physicsBody, pos);
} }
return true; return true;
} }
......
...@@ -142,32 +142,61 @@ class Node { ...@@ -142,32 +142,61 @@ class Node {
} }
void _updatePhysicsRotation(PhysicsBody body, double rotation, Node physicsParent) { 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));
}
PhysicsWorld _physicsWorld(Node parent) {
if (parent is PhysicsWorld) {
return parent;
}
else if (parent is PhysicsGroup) {
return _physicsWorld(parent.parent);
}
else {
print("physics not found");
return null;
}
}
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) { if (physicsParent is PhysicsWorld) {
PhysicsWorld world = physicsParent; return rotation;
world._updateRotation(body, rotation);
} else if (physicsParent is PhysicsGroup) { } else if (physicsParent is PhysicsGroup) {
_updatePhysicsRotation(body, rotation + physicsParent.rotation, physicsParent.parent); return _rotationToPhysics(rotation - physicsParent.rotation, physicsParent.parent);
} else { } else {
assert(false); assert(false);
return null;
} }
} }
void _setRotationFromPhysics(double rotation) { void _setRotationFromPhysics(double rotation, Node physicsParent) {
assert(rotation != null); assert(rotation != null);
_rotation = rotation; _rotation = _rotationFromPhysics(rotation, physicsParent);
invalidateTransformMatrix(); invalidateTransformMatrix();
} }
void teleportRotation(double rotation) { void teleportRotation(double rotation) {
assert(rotation != null); 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.setTransform(_physicsBody._body.position, radians(rotation));
_physicsBody._body.angularVelocity = 0.0; _physicsBody._body.angularVelocity = 0.0;
_physicsBody._body.setType(box2d.BodyType.STATIC); _physicsBody._body.setType(box2d.BodyType.STATIC);
} }
_setRotationFromPhysics(rotation); _setRotationFromPhysics(rotation, parent);
} }
/// The position of this node relative to its parent. /// The position of this node relative to its parent.
...@@ -188,29 +217,51 @@ class Node { ...@@ -188,29 +217,51 @@ class Node {
} }
void _updatePhysicsPosition(PhysicsBody body, Point position, Node physicsParent) { 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) { if (physicsParent is PhysicsWorld) {
PhysicsWorld world = physicsParent; return position;
world._updatePosition(body, position);
} else if (physicsParent is PhysicsGroup) { } else if (physicsParent is PhysicsGroup) {
// Transform the position
Vector4 parentPos = physicsParent.transformMatrix.transform(new Vector4(position.x, position.y, 0.0, 1.0)); 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 { } else {
assert(false); assert(false);
return null;
} }
} }
void _setPositionFromPhysics(Point position) { void _setPositionFromPhysics(Point position, Node physicsParent) {
assert(position != null); assert(position != null);
_position = position; _position = _positionFromPhysics(position, physicsParent);
invalidateTransformMatrix(); 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) { void teleportPosition(Point position) {
assert(position != null); assert(position != null);
if (_physicsBody != null && parent is PhysicsWorld) { if (_physicsBody != null && (parent is PhysicsWorld || parent is PhysicsGroup)) {
PhysicsWorld physicsNode = parent; position = _positionToPhysics(position, parent);
_physicsBody._body.setTransform( _physicsBody._body.setTransform(
new Vector2( new Vector2(
position.x / physicsNode.b2WorldToNodeConversionFactor, position.x / physicsNode.b2WorldToNodeConversionFactor,
...@@ -221,7 +272,7 @@ class Node { ...@@ -221,7 +272,7 @@ class Node {
_physicsBody._body.linearVelocity = new Vector2.zero(); _physicsBody._body.linearVelocity = new Vector2.zero();
_physicsBody._body.setType(box2d.BodyType.STATIC); _physicsBody._body.setType(box2d.BodyType.STATIC);
} }
_setPositionFromPhysics(position); _setPositionFromPhysics(position, parent);
} }
/// The skew along the x-axis of this node in degrees. /// The skew along the x-axis of this node in degrees.
...@@ -287,14 +338,17 @@ class Node { ...@@ -287,14 +338,17 @@ class Node {
void _updatePhysicsScale(PhysicsBody body, double scale, Node physicsParent) { void _updatePhysicsScale(PhysicsBody body, double scale, Node physicsParent) {
if (physicsParent == null) return; if (physicsParent == null) return;
_physicsWorld(physicsParent)._updateScale(body, _scaleToPhysics(scale, physicsParent));
}
double _scaleToPhysics(double scale, Node physicsParent) {
if (physicsParent is PhysicsWorld) { if (physicsParent is PhysicsWorld) {
PhysicsWorld world = physicsParent; return scale;
world._updateScale(body, scale);
} else if (physicsParent is PhysicsGroup) { } else if (physicsParent is PhysicsGroup) {
_updatePhysicsScale(body, scale * physicsParent.scale, physicsParent.parent); return _scaleToPhysics(scale * physicsParent.scale, physicsParent.parent);
} else { } else {
assert(false); assert(false);
return null;
} }
} }
......
...@@ -296,8 +296,13 @@ class PhysicsBody { ...@@ -296,8 +296,13 @@ class PhysicsBody {
void _attach(PhysicsWorld physicsNode, Node node) { void _attach(PhysicsWorld physicsNode, Node node) {
assert(_attached == false); 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 // Update scale
_scale = node.scale; _scale = scaleWorld;
// Create BodyDef // Create BodyDef
box2d.BodyDef bodyDef = new box2d.BodyDef(); box2d.BodyDef bodyDef = new box2d.BodyDef();
...@@ -316,9 +321,10 @@ class PhysicsBody { ...@@ -316,9 +321,10 @@ class PhysicsBody {
else else
bodyDef.type = box2d.BodyType.STATIC; bodyDef.type = box2d.BodyType.STATIC;
// Convert to world coordinates and set position and angle
double conv = physicsNode.b2WorldToNodeConversionFactor; double conv = physicsNode.b2WorldToNodeConversionFactor;
bodyDef.position = new Vector2(node.position.x / conv, node.position.y / conv); bodyDef.position = new Vector2(positionWorld.x / conv, positionWorld.y / conv);
bodyDef.angle = radians(node.rotation); bodyDef.angle = radians(rotationWorld);
// Create Body // Create Body
_body = physicsNode.b2World.createBody(bodyDef); _body = physicsNode.b2World.createBody(bodyDef);
......
...@@ -97,7 +97,7 @@ class PhysicsWorld extends Node { ...@@ -97,7 +97,7 @@ class PhysicsWorld extends Node {
} }
// Update linear velocity // Update linear velocity
if (body._lastPosition == null) { if (body._lastPosition == null || body._targetPosition == null) {
b2Body.linearVelocity.setZero(); b2Body.linearVelocity.setZero();
} else { } else {
Vector2 velocity = (body._targetPosition - body._lastPosition) / dt; Vector2 velocity = (body._targetPosition - body._lastPosition) / dt;
...@@ -106,7 +106,7 @@ class PhysicsWorld extends Node { ...@@ -106,7 +106,7 @@ class PhysicsWorld extends Node {
} }
// Update angular velocity // Update angular velocity
if (body._lastRotation == null) { if (body._lastRotation == null || body._targetAngle == null) {
b2Body.angularVelocity = 0.0; b2Body.angularVelocity = 0.0;
} else { } else {
double angularVelocity = (body._targetAngle - body._lastRotation) / dt; double angularVelocity = (body._targetAngle - body._lastRotation) / dt;
...@@ -129,12 +129,20 @@ class PhysicsWorld extends Node { ...@@ -129,12 +129,20 @@ class PhysicsWorld extends Node {
} }
// Update visual position and rotation // Update visual position and rotation
body._node._setPositionFromPhysics(new Point( if (body.type == PhysicsBodyType.dynamic) {
b2Body.position.x * b2WorldToNodeConversionFactor, body._node._setPositionFromPhysics(
b2Body.position.y * b2WorldToNodeConversionFactor 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 // Break joints
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment