mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Merge pull request #1746 from vlidholt/master
Working node to physics world conversions
This commit is contained in:
commit
5a481ed554
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user