mirror of
https://github.com/Heretek-AI/GDevelop.git
synced 2026-07-23 18:45:48 -04:00
aa7a4a4ff3
* Rename onOwnerRemovedFromScene to onDestroy (because it can be now called when a scene is destroyed) * Fix it being not called when a scene is destroyed (so behavior don't get a chance to clean up what they have created) * Fix onCreated being called before the object is fully initialized (for custom behaviors or behaviors relying on an object type)
3205 lines
95 KiB
JavaScript
3205 lines
95 KiB
JavaScript
gdjs.Physics2SharedData = function(runtimeScene, sharedData) {
|
|
this.gravityX = sharedData.gravityX;
|
|
this.gravityY = sharedData.gravityY;
|
|
this.scaleX =
|
|
sharedData.scaleX === 0 ? 100 : sharedData.scaleX;
|
|
this.scaleY =
|
|
sharedData.scaleY === 0 ? 100 : sharedData.scaleY;
|
|
|
|
this.invScaleX = 1 / this.scaleX;
|
|
this.invScaleY = 1 / this.scaleY;
|
|
this.timeStep = 1 / 60;
|
|
this.frameTime = 0;
|
|
this.stepped = false;
|
|
this.timeScale = 1;
|
|
this.world = new Box2D.b2World(
|
|
new Box2D.b2Vec2(this.gravityX, this.gravityY),
|
|
true
|
|
);
|
|
this.staticBody = this.world.CreateBody(new Box2D.b2BodyDef());
|
|
|
|
// Contact listener to keep track of current collisions
|
|
this.contactListener = new Box2D.JSContactListener();
|
|
this.contactListener.BeginContact = function(contactPtr) {
|
|
// Get the contact
|
|
var contact = Box2D.wrapPointer(contactPtr, Box2D.b2Contact);
|
|
// There is no body, return
|
|
if (
|
|
contact.GetFixtureA().GetBody() === null ||
|
|
contact.GetFixtureB().GetBody() === null
|
|
) {
|
|
return;
|
|
}
|
|
// Get associated behaviors
|
|
var behaviorA = contact.GetFixtureA().GetBody().gdjsAssociatedBehavior;
|
|
var behaviorB = contact.GetFixtureB().GetBody().gdjsAssociatedBehavior;
|
|
// Let each behavior know about the contact against the other
|
|
behaviorA.currentContacts.push(behaviorB);
|
|
behaviorB.currentContacts.push(behaviorA);
|
|
};
|
|
|
|
this.contactListener.EndContact = function(contactPtr) {
|
|
// Get the contact
|
|
var contact = Box2D.wrapPointer(contactPtr, Box2D.b2Contact);
|
|
// There is no body, return
|
|
if (
|
|
contact.GetFixtureA().GetBody() === null ||
|
|
contact.GetFixtureB().GetBody() === null
|
|
) {
|
|
return;
|
|
}
|
|
// Get associated behaviors
|
|
var behaviorA = contact.GetFixtureA().GetBody().gdjsAssociatedBehavior;
|
|
var behaviorB = contact.GetFixtureB().GetBody().gdjsAssociatedBehavior;
|
|
// Remove each other contact
|
|
var i = behaviorA.currentContacts.indexOf(behaviorB);
|
|
if (i !== -1) behaviorA.currentContacts.remove(i);
|
|
i = behaviorB.currentContacts.indexOf(behaviorA);
|
|
if (i !== -1) behaviorB.currentContacts.remove(i);
|
|
};
|
|
|
|
this.contactListener.PreSolve = function() {};
|
|
this.contactListener.PostSolve = function() {};
|
|
|
|
this.world.SetContactListener(this.contactListener);
|
|
|
|
this._nextJointId = 1; // Start with 1 so the user is safe from default variables value (0)
|
|
this.joints = {}; // (string)jointId -> (b2Joint)b2Joint
|
|
};
|
|
|
|
gdjs.Physics2SharedData.getSharedData = function(runtimeScene, behaviorName) {
|
|
// Create one if needed
|
|
if (!runtimeScene.physics2SharedData) {
|
|
var initialData = runtimeScene.getInitialSharedDataForBehavior(
|
|
behaviorName
|
|
);
|
|
runtimeScene.physics2SharedData = new gdjs.Physics2SharedData(
|
|
runtimeScene,
|
|
initialData
|
|
);
|
|
}
|
|
|
|
return runtimeScene.physics2SharedData;
|
|
};
|
|
|
|
gdjs.Physics2SharedData.prototype.step = function(deltaTime) {
|
|
this.frameTime += deltaTime;
|
|
if (this.frameTime >= this.timeStep) {
|
|
var numberOfSteps = Math.floor(this.frameTime / this.timeStep);
|
|
this.frameTime -= numberOfSteps * this.timeStep;
|
|
|
|
if (numberOfSteps > 5) numberOfSteps = 5;
|
|
|
|
for (var i = 0; i < numberOfSteps; i++) {
|
|
this.world.Step(this.timeStep * this.timeScale, 8, 10);
|
|
}
|
|
this.world.ClearForces();
|
|
}
|
|
|
|
this.stepped = true;
|
|
};
|
|
|
|
gdjs.Physics2SharedData.gdjsCallbackRuntimeSceneUnloaded = function(
|
|
runtimeScene
|
|
) {
|
|
if (
|
|
runtimeScene.physics2SharedData &&
|
|
runtimeScene.physics2SharedData.world
|
|
) {
|
|
Box2D.destroy(runtimeScene.physics2SharedData.world);
|
|
}
|
|
};
|
|
|
|
gdjs.Physics2SharedData.prototype.clearBodyJoints = function(body) {
|
|
// Iterate through all the joints
|
|
for (var jointId in this.joints) {
|
|
if (this.joints.hasOwnProperty(jointId)) {
|
|
// If the joint is attached to the body, delete it
|
|
if (
|
|
this.joints[jointId].GetBodyA() === body ||
|
|
this.joints[jointId].GetBodyB() === body
|
|
) {
|
|
this.removeJoint(jointId);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
gdjs.Physics2SharedData.prototype.addJoint = function(joint) {
|
|
// Add the joint to the list
|
|
this.joints[this._nextJointId.toString(10)] = joint;
|
|
// Return the current joint id and then increase it
|
|
return this._nextJointId++;
|
|
};
|
|
|
|
gdjs.Physics2SharedData.prototype.getJoint = function(jointId) {
|
|
// Cast to string
|
|
jointId = jointId.toString(10);
|
|
// Get the joint
|
|
if (this.joints.hasOwnProperty(jointId)) {
|
|
return this.joints[jointId];
|
|
}
|
|
// Joint not found, return null
|
|
return null;
|
|
};
|
|
|
|
gdjs.Physics2SharedData.prototype.getJointId = function(joint) {
|
|
// Search the joint in the list and return the ID
|
|
for (var jointId in this.joints) {
|
|
if (this.joints.hasOwnProperty(jointId)) {
|
|
if (this.joints[jointId] === joint) {
|
|
return parseInt(jointId, 10);
|
|
}
|
|
}
|
|
}
|
|
// Joint not found, return 0
|
|
return 0;
|
|
};
|
|
|
|
gdjs.Physics2SharedData.prototype.removeJoint = function(jointId) {
|
|
// Cast to string
|
|
jointId = jointId.toString(10);
|
|
// Delete the joint
|
|
if (this.joints.hasOwnProperty(jointId)) {
|
|
var joint = this.joints[jointId];
|
|
// If we delete a joint attached to a gear joint, the gear will crash, so we must delete the gear joint first
|
|
// Search in our joints list gear joints attached to this one we want to remove
|
|
// The joint can be attached to a gear joint if it's revolute or prismatic only
|
|
if (
|
|
joint.GetType() === Box2D.e_revoluteJoint ||
|
|
joint.GetType() === Box2D.e_prismaticJoint
|
|
) {
|
|
for (var jId in this.joints) {
|
|
if (this.joints.hasOwnProperty(jId)) {
|
|
// Must check pointers becuase gears store non-casted joints (b2Joint)
|
|
if (
|
|
this.joints[jId].GetType() === Box2D.e_gearJoint &&
|
|
(Box2D.getPointer(this.joints[jId].GetJoint1()) ===
|
|
Box2D.getPointer(joint) ||
|
|
Box2D.getPointer(this.joints[jId].GetJoint2()) ===
|
|
Box2D.getPointer(joint))
|
|
) {
|
|
// We could pass it a string, but lets do it right
|
|
this.removeJoint(parseInt(jId, 10));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Remove the joint
|
|
this.world.DestroyJoint(joint);
|
|
delete this.joints[jointId];
|
|
}
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior = function(runtimeScene, behaviorData, owner) {
|
|
gdjs.RuntimeBehavior.call(this, runtimeScene, behaviorData, owner);
|
|
|
|
this.bodyType = behaviorData.bodyType;
|
|
this.bullet = behaviorData.bullet;
|
|
this.fixedRotation = behaviorData.fixedRotation;
|
|
this.canSleep = behaviorData.canSleep;
|
|
this.shape = behaviorData.shape;
|
|
this.shapeDimensionA = behaviorData.shapeDimensionA;
|
|
this.shapeDimensionB = behaviorData.shapeDimensionB;
|
|
this.shapeOffsetX = behaviorData.shapeOffsetX;
|
|
this.shapeOffsetY = behaviorData.shapeOffsetY;
|
|
this.polygonOrigin = behaviorData.polygonOrigin;
|
|
this.polygon =
|
|
this.shape === 'Polygon'
|
|
? gdjs.Physics2RuntimeBehavior.getPolygon(behaviorData.vertices)
|
|
: null;
|
|
this.density = behaviorData.density;
|
|
this.friction = behaviorData.friction;
|
|
this.restitution = behaviorData.restitution;
|
|
this.linearDamping = behaviorData.linearDamping;
|
|
this.angularDamping = behaviorData.angularDamping;
|
|
this.gravityScale = behaviorData.gravityScale;
|
|
this.layers = behaviorData.layers;
|
|
this.masks = behaviorData.masks;
|
|
this.shapeScale = 1;
|
|
this.currentContacts = this.currentContacts || [];
|
|
this.currentContacts.length = 0;
|
|
|
|
this._body = null;
|
|
this._sharedData = gdjs.Physics2SharedData.getSharedData(
|
|
runtimeScene,
|
|
behaviorData.name
|
|
);
|
|
this._tempb2Vec2 = new Box2D.b2Vec2(); // Avoid creating new vectors all the time
|
|
this._tempb2Vec2Sec = new Box2D.b2Vec2(); // Sometimes two vectors are needed on the same function call
|
|
this._objectOldX = 0;
|
|
this._objectOldY = 0;
|
|
this._objectOldAngle = 0;
|
|
this._objectOldWidth = 0;
|
|
this._objectOldHeight = 0;
|
|
this._verticesBuffer = 0; // Stores a Box2D pointer of created vertices
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype = Object.create(
|
|
gdjs.RuntimeBehavior.prototype
|
|
);
|
|
gdjs.Physics2RuntimeBehavior.thisIsARuntimeBehaviorConstructor =
|
|
'Physics2::Physics2Behavior';
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.b2Vec2 = function(x, y) {
|
|
this._tempb2Vec2.set_x(x);
|
|
this._tempb2Vec2.set_y(y);
|
|
return this._tempb2Vec2;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.b2Vec2Sec = function(x, y) {
|
|
this._tempb2Vec2Sec.set_x(x);
|
|
this._tempb2Vec2Sec.set_y(y);
|
|
return this._tempb2Vec2Sec;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.onDeActivate = function() {
|
|
if (this._body !== null) {
|
|
// When a body is deleted, Box2D removes automatically its joints, leaving an invalid pointer in our joints list
|
|
this._sharedData.clearBodyJoints(this._body);
|
|
// Delete the vertices
|
|
if (this._verticesBuffer) {
|
|
Box2D._free(this._verticesBuffer);
|
|
this._verticesBuffer = 0;
|
|
}
|
|
// Delete the body
|
|
this._sharedData.world.DestroyBody(this._body);
|
|
this._body = null;
|
|
}
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.onDestroy = function() {
|
|
this.onDeActivate();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.getPolygon = function(verticesData) {
|
|
if (!verticesData) return null;
|
|
|
|
var polygon = new gdjs.Polygon();
|
|
var maxVertices = 8;
|
|
for (
|
|
var i = 0, len = verticesData.length;
|
|
i < Math.min(len, maxVertices);
|
|
i++
|
|
) {
|
|
polygon.vertices.push([verticesData[i].x, verticesData[i].y]);
|
|
}
|
|
return polygon;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.isPolygonConvex = function(polygon) {
|
|
if (!polygon.isConvex()) return false;
|
|
|
|
// Check for repeated vertices or check if all vertices are aligned (would crash Box2D)
|
|
var alignedX = true;
|
|
var alignedY = true;
|
|
for (i = 0; i < polygon.vertices.length - 1; ++i) {
|
|
for (var j = i + 1; j < polygon.vertices.length; ++j) {
|
|
if (
|
|
polygon.vertices[i][0] === polygon.vertices[j][0] &&
|
|
polygon.vertices[i][1] === polygon.vertices[j][1]
|
|
)
|
|
return false;
|
|
}
|
|
if (polygon.vertices[i][0] !== polygon.vertices[i + 1][0]) alignedX = false;
|
|
if (polygon.vertices[i][1] !== polygon.vertices[i + 1][1]) alignedY = false;
|
|
}
|
|
if (alignedX || alignedY) return false;
|
|
|
|
return true;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.createShape = function() {
|
|
// Get the scaled offset
|
|
var offsetX = this.shapeOffsetX
|
|
? this.shapeOffsetX * this.shapeScale * this._sharedData.invScaleX
|
|
: 0;
|
|
var offsetY = this.shapeOffsetY
|
|
? this.shapeOffsetY * this.shapeScale * this._sharedData.invScaleY
|
|
: 0;
|
|
// Generate the base shape
|
|
var shape;
|
|
if (this.shape === 'Circle') {
|
|
shape = new Box2D.b2CircleShape();
|
|
// Radius determined by the custom dimension
|
|
if (this.shapeDimensionA > 0) {
|
|
shape.set_m_radius(
|
|
this.shapeDimensionA * this.shapeScale * this._sharedData.invScaleX
|
|
);
|
|
}
|
|
// Average radius from width and height
|
|
else {
|
|
var radius =
|
|
(this.owner.getWidth() * this._sharedData.invScaleX +
|
|
this.owner.getHeight() * this._sharedData.invScaleY) /
|
|
4;
|
|
shape.set_m_radius(radius > 0 ? radius : 1);
|
|
}
|
|
// Set the offset
|
|
shape.set_m_p(this.b2Vec2(offsetX, offsetY));
|
|
} else if (this.shape === 'Polygon') {
|
|
shape = new Box2D.b2PolygonShape();
|
|
// Not convex, fall back to a box
|
|
if (
|
|
!this.polygon ||
|
|
!gdjs.Physics2RuntimeBehavior.isPolygonConvex(this.polygon)
|
|
) {
|
|
var width =
|
|
(this.owner.getWidth() > 0 ? this.owner.getWidth() : 1) *
|
|
this._sharedData.invScaleX;
|
|
var height =
|
|
(this.owner.getHeight() > 0 ? this.owner.getHeight() : 1) *
|
|
this._sharedData.invScaleY;
|
|
// Set the shape box
|
|
shape.SetAsBox(width / 2, height / 2, this.b2Vec2(offsetX, offsetY), 0);
|
|
} else {
|
|
var originOffsetX = 0;
|
|
var originOffsetY = 0;
|
|
if (this.polygonOrigin === 'Origin') {
|
|
originOffsetX =
|
|
(this.owner.getWidth() > 0 ? -this.owner.getWidth() / 2 : 0) +
|
|
(this.owner.getX() - this.owner.getDrawableX());
|
|
originOffsetY =
|
|
(this.owner.getHeight() > 0 ? -this.owner.getHeight() / 2 : 0) +
|
|
(this.owner.getY() - this.owner.getDrawableY());
|
|
} else if (this.polygonOrigin === 'TopLeft') {
|
|
originOffsetX =
|
|
this.owner.getWidth() > 0 ? -this.owner.getWidth() / 2 : 0;
|
|
originOffsetY =
|
|
this.owner.getHeight() > 0 ? -this.owner.getHeight() / 2 : 0;
|
|
}
|
|
// Generate vertices if not done already
|
|
if (!this._verticesBuffer) {
|
|
// Store the vertices using a memory allocation function
|
|
var buffer = Box2D._malloc(
|
|
this.polygon.vertices.length * 8,
|
|
'float',
|
|
Box2D.ALLOC_STACK
|
|
);
|
|
this._verticesBuffer = buffer;
|
|
}
|
|
// Overwrite the vertices stored in the buffer
|
|
var offset = 0;
|
|
for (var i = 0, len = this.polygon.vertices.length; i < len; i++) {
|
|
Box2D.HEAPF32[(this._verticesBuffer + offset) >> 2] =
|
|
(this.polygon.vertices[i][0] * this.shapeScale + originOffsetX) *
|
|
this._sharedData.invScaleX +
|
|
offsetX;
|
|
Box2D.HEAPF32[(this._verticesBuffer + (offset + 4)) >> 2] =
|
|
(this.polygon.vertices[i][1] * this.shapeScale + originOffsetY) *
|
|
this._sharedData.invScaleY +
|
|
offsetY;
|
|
offset += 8;
|
|
}
|
|
// Set the shape vertices
|
|
var b2Vertices = Box2D.wrapPointer(this._verticesBuffer, Box2D.b2Vec2);
|
|
shape.Set(b2Vertices, this.polygon.vertices.length);
|
|
}
|
|
} else if (this.shape === 'Edge') {
|
|
shape = new Box2D.b2EdgeShape();
|
|
// Length from the custom dimension or from the object width
|
|
var length =
|
|
(this.shapeDimensionA > 0
|
|
? this.shapeDimensionA * this.shapeScale
|
|
: this.owner.getWidth() > 0
|
|
? this.owner.getWidth()
|
|
: 1) * this._sharedData.invScaleX;
|
|
var height =
|
|
this.owner.getHeight() > 0
|
|
? this.owner.getHeight() * this._sharedData.invScaleY
|
|
: 0;
|
|
// Angle from custom dimension, otherwise is 0
|
|
var angle = this.shapeDimensionB ? gdjs.toRad(this.shapeDimensionB) : 0;
|
|
// Set the edge vertices from the length, the angle and the offset
|
|
shape.Set(
|
|
this.b2Vec2(
|
|
(-length / 2) * Math.cos(angle) + offsetX,
|
|
height / 2 - (length / 2) * Math.sin(angle) + offsetY
|
|
),
|
|
this.b2Vec2Sec(
|
|
(length / 2) * Math.cos(angle) + offsetX,
|
|
height / 2 + (length / 2) * Math.sin(angle) + offsetY
|
|
)
|
|
);
|
|
} else {
|
|
// Box
|
|
shape = new Box2D.b2PolygonShape();
|
|
// Width and height from custom dimensions or object size
|
|
var width =
|
|
(this.shapeDimensionA > 0
|
|
? this.shapeDimensionA * this.shapeScale
|
|
: this.owner.getWidth() > 0
|
|
? this.owner.getWidth()
|
|
: 1) * this._sharedData.invScaleX;
|
|
var height =
|
|
(this.shapeDimensionB > 0
|
|
? this.shapeDimensionB * this.shapeScale
|
|
: this.owner.getHeight() > 0
|
|
? this.owner.getHeight()
|
|
: 1) * this._sharedData.invScaleY;
|
|
// Set the shape box, the offset must be added here too
|
|
shape.SetAsBox(width / 2, height / 2, this.b2Vec2(offsetX, offsetY), 0);
|
|
}
|
|
|
|
// Generate filter data
|
|
var filter = new Box2D.b2Filter();
|
|
filter.set_categoryBits(this.layers);
|
|
filter.set_maskBits(this.masks);
|
|
|
|
// Generate the fixture definition
|
|
var fixDef = new Box2D.b2FixtureDef();
|
|
|
|
// Set fixture settings
|
|
fixDef.set_shape(shape);
|
|
fixDef.set_filter(filter);
|
|
if (this.density < 0) this.density = 0;
|
|
fixDef.set_density(this.density);
|
|
if (this.friction < 0) this.friction = 0;
|
|
fixDef.set_friction(this.friction);
|
|
if (this.restitution < 0) this.restitution = 0;
|
|
fixDef.set_restitution(this.restitution);
|
|
|
|
// Return the fixture
|
|
return fixDef;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.recreateShape = function() {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Destroy the old shape
|
|
this._body.DestroyFixture(this._body.GetFixtureList());
|
|
this._body.CreateFixture(this.createShape());
|
|
// Update cached size
|
|
this._objectOldWidth = this.owner.getWidth();
|
|
this._objectOldHeight = this.owner.getHeight();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getShapeScale = function() {
|
|
return this.shapeScale;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setShapeScale = function(shapeScale) {
|
|
if (shapeScale !== this.shapeScale && shapeScale > 0) {
|
|
this.shapeScale = shapeScale;
|
|
this.recreateShape();
|
|
}
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getBody = function() {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
|
|
return this._body;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.createBody = function() {
|
|
// Generate the body definition
|
|
var bodyDef = new Box2D.b2BodyDef();
|
|
|
|
// Set the initial body transformation from the GD object
|
|
bodyDef.set_position(
|
|
this.b2Vec2(
|
|
(this.owner.getDrawableX() + this.owner.getWidth() / 2) *
|
|
this._sharedData.invScaleX,
|
|
(this.owner.getDrawableY() + this.owner.getHeight() / 2) *
|
|
this._sharedData.invScaleY
|
|
)
|
|
);
|
|
bodyDef.set_angle(gdjs.toRad(this.owner.getAngle()));
|
|
|
|
// Set body settings
|
|
bodyDef.set_type(
|
|
this.bodyType === 'Static'
|
|
? Box2D.b2_staticBody
|
|
: this.bodyType === 'Kinematic'
|
|
? Box2D.b2_kinematicBody
|
|
: Box2D.b2_dynamicBody
|
|
);
|
|
bodyDef.set_bullet(this.bullet);
|
|
bodyDef.set_fixedRotation(this.fixedRotation);
|
|
bodyDef.set_allowSleep(this.canSleep);
|
|
bodyDef.set_linearDamping(this.linearDamping);
|
|
bodyDef.set_angularDamping(this.angularDamping);
|
|
bodyDef.set_gravityScale(this.gravityScale);
|
|
|
|
// Create the body
|
|
this._body = this._sharedData.world.CreateBody(bodyDef);
|
|
this._body.CreateFixture(this.createShape());
|
|
this._body.gdjsAssociatedBehavior = this;
|
|
|
|
// Update cached size
|
|
this._objectOldWidth = this.owner.getWidth();
|
|
this._objectOldHeight = this.owner.getHeight();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.doStepPreEvents = function(
|
|
runtimeScene
|
|
) {
|
|
// Create a body if there is not one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
}
|
|
|
|
// Step the world if not done this frame yet
|
|
if (!this._sharedData.stepped) {
|
|
this._sharedData.step(
|
|
runtimeScene.getTimeManager().getElapsedTime() / 1000.0
|
|
);
|
|
}
|
|
|
|
// Copy transform from body to the GD object
|
|
this.owner.setX(
|
|
this._body.GetPosition().get_x() * this._sharedData.scaleX -
|
|
this.owner.getWidth() / 2 +
|
|
this.owner.getX() -
|
|
this.owner.getDrawableX()
|
|
);
|
|
this.owner.setY(
|
|
this._body.GetPosition().get_y() * this._sharedData.scaleY -
|
|
this.owner.getHeight() / 2 +
|
|
this.owner.getY() -
|
|
this.owner.getDrawableY()
|
|
);
|
|
this.owner.setAngle(gdjs.toDegrees(this._body.GetAngle()));
|
|
|
|
// Update cached transform
|
|
this._objectOldX = this.owner.getX();
|
|
this._objectOldY = this.owner.getY();
|
|
this._objectOldAngle = this.owner.getAngle();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.doStepPostEvents = function(
|
|
runtimeScene
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
|
|
// GD object size has changed, recreate shape
|
|
// The width has changed and there is no custom dimension A (box: width, circle: radius, edge: length) or
|
|
// The height has changed, the shape is not an edge (edges doesn't have height),
|
|
// it isn't a box with custom height or a circle with custom radius
|
|
if (
|
|
(this._objectOldWidth !== this.owner.getWidth() &&
|
|
this.shapeDimensionA <= 0) ||
|
|
(this._objectOldHeight !== this.owner.getHeight() &&
|
|
this.shape !== 'Edge' &&
|
|
!(this.shape === 'Box' && this.shapeDimensionB > 0) &&
|
|
!(this.shape === 'Ciecle' && this.shapeDimensionA > 0))
|
|
) {
|
|
this.recreateShape();
|
|
}
|
|
|
|
// GD object transform has changed, update body transform
|
|
if (
|
|
this._objectOldX !== this.owner.getX() ||
|
|
this._objectOldY !== this.owner.getY() ||
|
|
this._objectOldAngle !== this.owner.getAngle()
|
|
) {
|
|
var pos = this.b2Vec2(
|
|
(this.owner.getDrawableX() + this.owner.getWidth() / 2) *
|
|
this._sharedData.invScaleX,
|
|
(this.owner.getDrawableY() + this.owner.getHeight() / 2) *
|
|
this._sharedData.invScaleY
|
|
);
|
|
this._body.SetTransform(pos, gdjs.toRad(this.owner.getAngle()));
|
|
this._body.SetAwake(true);
|
|
}
|
|
|
|
// Reset world step to update next frame
|
|
this._sharedData.stepped = false;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getGravityX = function() {
|
|
return this._sharedData.gravityX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getGravityY = function() {
|
|
return this._sharedData.gravityY;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setGravity = function(x, y) {
|
|
// Check if there is no modification
|
|
if (this._sharedData.gravityX === x && this._sharedData.gravityY === y)
|
|
return;
|
|
// Change the gravity
|
|
this._sharedData.gravityX = x;
|
|
this._sharedData.gravityY = y;
|
|
this._sharedData.world.SetGravity(
|
|
this.b2Vec2(this._sharedData.gravityX, this._sharedData.gravityY)
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getTimeScale = function() {
|
|
// Get the time scale
|
|
return this._sharedData.timeScale;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setTimeScale = function(timeScale) {
|
|
// Invalid value
|
|
if (timeScale < 0) return;
|
|
// Set the time scale
|
|
this._sharedData.timeScale = timeScale;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.setTimeScaleFromObject = function(
|
|
object,
|
|
behaviorName,
|
|
timeScale
|
|
) {
|
|
// Check if the object exist and has the behavior
|
|
if (object === null || !object.hasBehavior(behaviorName)) return;
|
|
// Set the time scale
|
|
object.getBehavior(behaviorName).setTimeScale(timeScale);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isDynamic = function() {
|
|
return this.bodyType === 'Dynamic';
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setDynamic = function() {
|
|
// Check if there is no modification
|
|
if (this.bodyType === 'Dynamic') return;
|
|
// Change body type
|
|
this.bodyType = 'Dynamic';
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update body type
|
|
this._body.SetType(Box2D.b2_dynamicBody);
|
|
this._body.SetAwake(true);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isStatic = function() {
|
|
return this.bodyType === 'Static';
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setStatic = function() {
|
|
// Check if there is no modification
|
|
if (this.bodyType === 'Static') return;
|
|
// Change body type
|
|
this.bodyType = 'Static';
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update body type
|
|
this._body.SetType(Box2D.b2_staticBody);
|
|
this._body.SetAwake(true);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isKinematic = function() {
|
|
return this.bodyType === 'Kinematic';
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setKinematic = function() {
|
|
// Check if there is no modification
|
|
if (this.bodyType === 'Kinematic') return;
|
|
// Change body type
|
|
this.bodyType = 'Kinematic';
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update body type
|
|
this._body.SetType(Box2D.b2_kinematicBody);
|
|
this._body.SetAwake(true);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isBullet = function() {
|
|
return this.bullet;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setBullet = function(enable) {
|
|
// Check if there is no modification
|
|
if (this.bullet === enable) return;
|
|
// Change bullet flag
|
|
this.bullet = enable;
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update body bullet flag
|
|
this._body.SetBullet(this.bullet);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.hasFixedRotation = function() {
|
|
return this.fixedRotation;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setFixedRotation = function(enable) {
|
|
this.fixedRotation = enable;
|
|
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
this._body.SetFixedRotation(this.fixedRotation);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isSleepingAllowed = function() {
|
|
return this.canSleep;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setSleepingAllowed = function(enable) {
|
|
this.canSleep = enable;
|
|
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
this._body.SetSleepingAllowed(this.canSleep);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isSleeping = function() {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
}
|
|
// Get the body sleeping state
|
|
return !this._body.IsAwake();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getDensity = function() {
|
|
return this.density;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setDensity = function(density) {
|
|
// Non-negative values only
|
|
if (density < 0) density = 0;
|
|
// Check if there is no modification
|
|
if (this.density === density) return;
|
|
// Change density
|
|
this.density = density;
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update the body density
|
|
this._body.GetFixtureList().SetDensity(this.density);
|
|
this._body.ResetMassData();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getFriction = function() {
|
|
return this.friction;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setFriction = function(friction) {
|
|
// Non-negative values only
|
|
if (friction < 0) friction = 0;
|
|
// Check if there is no modification
|
|
if (this.friction === friction) return;
|
|
// Change friction
|
|
this.friction = friction;
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update the body friction
|
|
this._body.GetFixtureList().SetFriction(this.friction);
|
|
// Update contacts
|
|
var contact = this._body.GetContactList();
|
|
while (Box2D.getPointer(contact)) {
|
|
contact.get_contact().ResetFriction();
|
|
contact = contact.get_next();
|
|
}
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getRestitution = function() {
|
|
return this.restitution;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setRestitution = function(restitution) {
|
|
// Non-negative values only
|
|
if (restitution < 0) restitution = 0;
|
|
// Check if there is no modification
|
|
if (this.restitution === restitution) return;
|
|
// Change restitution
|
|
this.restitution = restitution;
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update the body restitution
|
|
this._body.GetFixtureList().SetRestitution(this.restitution);
|
|
// Update contacts
|
|
var contact = this._body.GetContactList();
|
|
while (Box2D.getPointer(contact)) {
|
|
contact.get_contact().ResetRestitution();
|
|
contact = contact.get_next();
|
|
}
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getLinearDamping = function() {
|
|
return this.linearDamping;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setLinearDamping = function(
|
|
linearDamping
|
|
) {
|
|
// Check if there is no modification
|
|
if (this.linearDamping === linearDamping) return;
|
|
// Change linearDamping
|
|
this.linearDamping = linearDamping;
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update the body linear damping
|
|
this._body.SetLinearDamping(this.linearDamping);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getAngularDamping = function() {
|
|
return this.angularDamping;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setAngularDamping = function(
|
|
angularDamping
|
|
) {
|
|
// Check if there is no modification
|
|
if (this.angularDamping === angularDamping) return;
|
|
// Change angularDamping
|
|
this.angularDamping = angularDamping;
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update the body angular damping
|
|
this._body.SetAngularDamping(this.angularDamping);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getGravityScale = function() {
|
|
return this.gravityScale;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setGravityScale = function(
|
|
gravityScale
|
|
) {
|
|
// Check if there is no modification
|
|
if (this.gravityScale === gravityScale) return;
|
|
// Change the gravity scale
|
|
this.gravityScale = gravityScale;
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update the body gravity scale
|
|
this._body.SetGravityScale(this.gravityScale);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.layerEnabled = function(layer) {
|
|
// Layer must be an integer
|
|
layer = Math.floor(layer);
|
|
// Layer must be in range [1, 16]
|
|
if (layer < 1 || layer > 16) return false;
|
|
|
|
return !!(this.layers & (1 << (layer - 1)));
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.enableLayer = function(layer, enable) {
|
|
// Layer must be an integer
|
|
layer = Math.floor(layer);
|
|
// Layer must be in range [1, 16]
|
|
if (layer < 1 || layer > 16) return;
|
|
// Change the layers
|
|
if (enable) {
|
|
this.layers |= 1 << (layer - 1);
|
|
} else {
|
|
this.layers &= ~(1 << (layer - 1));
|
|
}
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update the body layers
|
|
var filter = this._body.GetFixtureList().GetFilterData();
|
|
filter.set_categoryBits(this.layers);
|
|
this._body.GetFixtureList().SetFilterData(filter);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.maskEnabled = function(mask) {
|
|
// Mask must be an integer
|
|
mask = Math.floor(mask);
|
|
// Mask must be in range [1, 16]
|
|
if (mask < 1 || mask > 16) return false;
|
|
|
|
return !!(this.masks & (1 << (mask - 1)));
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.enableMask = function(mask, enable) {
|
|
// Mask must be an integer
|
|
mask = Math.floor(mask);
|
|
// Mask must be in range [1, 16]
|
|
if (mask < 1 || mask > 16) return;
|
|
// Change the masks
|
|
if (enable) {
|
|
this.masks |= 1 << (mask - 1);
|
|
} else {
|
|
this.masks &= ~(1 << (mask - 1));
|
|
}
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return;
|
|
}
|
|
// Update the body masks
|
|
var filter = this._body.GetFixtureList().GetFilterData();
|
|
filter.set_maskBits(this.masks);
|
|
this._body.GetFixtureList().SetFilterData(filter);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getLinearVelocityX = function() {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return 0;
|
|
}
|
|
// Get the linear velocity on X
|
|
return this._body.GetLinearVelocity().get_x() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setLinearVelocityX = function(
|
|
linearVelocityX
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Set the linear velocity on X
|
|
this._body.SetLinearVelocity(
|
|
this.b2Vec2(
|
|
linearVelocityX * this._sharedData.invScaleX,
|
|
this._body.GetLinearVelocity().get_y()
|
|
)
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getLinearVelocityY = function() {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return 0;
|
|
}
|
|
// Get the linear velocity on Y
|
|
return this._body.GetLinearVelocity().get_y() * this._sharedData.scaleY;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setLinearVelocityY = function(
|
|
linearVelocityY
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Set the linear velocity on Y
|
|
this._body.SetLinearVelocity(
|
|
this.b2Vec2(
|
|
this._body.GetLinearVelocity().get_x(),
|
|
linearVelocityY * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getLinearVelocityLength = function() {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return 0;
|
|
}
|
|
// Get the linear velocity length
|
|
return this.b2Vec2(
|
|
this._body.GetLinearVelocity().get_x() * this._sharedData.scaleX,
|
|
this._body.GetLinearVelocity().get_y() * this._sharedData.scaleY
|
|
).Length();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getAngularVelocity = function() {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Get the angular velocity
|
|
return gdjs.toDegrees(this._body.GetAngularVelocity());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setAngularVelocity = function(
|
|
angularVelocity
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Set the angular velocity
|
|
this._body.SetAngularVelocity(gdjs.toRad(angularVelocity));
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.applyForce = function(
|
|
forceX,
|
|
forceY,
|
|
positionX,
|
|
positionY
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Wake up the object
|
|
this._body.SetAwake(true);
|
|
// Apply the force
|
|
this._body.ApplyForce(
|
|
this.b2Vec2(forceX, forceY),
|
|
this.b2Vec2Sec(
|
|
positionX * this._sharedData.invScaleX,
|
|
positionY * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.applyPolarForce = function(
|
|
angle,
|
|
length,
|
|
positionX,
|
|
positionY
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Wake up the object
|
|
this._body.SetAwake(true);
|
|
// Apply the force
|
|
angle = gdjs.toRad(angle);
|
|
this._body.ApplyForce(
|
|
this.b2Vec2(length * Math.cos(angle), length * Math.sin(angle)),
|
|
this.b2Vec2Sec(
|
|
positionX * this._sharedData.invScaleX,
|
|
positionY * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.applyForceTowardPosition = function(
|
|
length,
|
|
towardX,
|
|
towardY,
|
|
positionX,
|
|
positionY
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Wake up the object
|
|
this._body.SetAwake(true);
|
|
// Apply the force
|
|
var angle = Math.atan2(
|
|
towardY * this._sharedData.invScaleY - this._body.GetPosition().get_y(),
|
|
towardX * this._sharedData.invScaleX - this._body.GetPosition().get_x()
|
|
);
|
|
this._body.ApplyForce(
|
|
this.b2Vec2(length * Math.cos(angle), length * Math.sin(angle)),
|
|
this.b2Vec2Sec(
|
|
positionX * this._sharedData.invScaleX,
|
|
positionY * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.applyImpulse = function(
|
|
impulseX,
|
|
impulseY,
|
|
positionX,
|
|
positionY
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Wake up the object
|
|
this._body.SetAwake(true);
|
|
// Apply the impulse
|
|
this._body.ApplyLinearImpulse(
|
|
this.b2Vec2(impulseX, impulseY),
|
|
this.b2Vec2Sec(
|
|
positionX * this._sharedData.invScaleX,
|
|
positionY * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.applyPolarImpulse = function(
|
|
angle,
|
|
length,
|
|
positionX,
|
|
positionY
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) his.createBody();
|
|
// Wake up the object
|
|
this._body.SetAwake(true);
|
|
// Apply the impulse
|
|
angle = gdjs.toRad(angle);
|
|
this._body.ApplyLinearImpulse(
|
|
this.b2Vec2(length * Math.cos(angle), length * Math.sin(angle)),
|
|
this.b2Vec2Sec(
|
|
positionX * this._sharedData.invScaleX,
|
|
positionY * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.applyImpulseTowardPosition = function(
|
|
length,
|
|
towardX,
|
|
towardY,
|
|
positionX,
|
|
positionY
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Wake up the object
|
|
this._body.SetAwake(true);
|
|
// Apply the impulse
|
|
var angle = Math.atan2(
|
|
towardY * this._sharedData.invScaleY - this._body.GetPosition().get_y(),
|
|
towardX * this._sharedData.invScaleX - this._body.GetPosition().get_x()
|
|
);
|
|
this._body.ApplyLinearImpulse(
|
|
this.b2Vec2(length * Math.cos(angle), length * Math.sin(angle)),
|
|
this.b2Vec2Sec(
|
|
positionX * this._sharedData.invScaleX,
|
|
positionY * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.applyTorque = function(torque) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Wake up the object
|
|
this._body.SetAwake(true);
|
|
// Apply the torque
|
|
this._body.ApplyTorque(torque);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.applyAngularImpulse = function(
|
|
angularImpulse
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Wake up the object
|
|
this._body.SetAwake(true);
|
|
// Apply the angular impulse
|
|
this._body.ApplyAngularImpulse(angularImpulse);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMassCenterX = function() {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
}
|
|
// Get the mass center on X
|
|
return this._body.GetWorldCenter().get_x() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMassCenterY = function() {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
}
|
|
// Get the mass center on Y
|
|
return this._body.GetWorldCenter().get_y() * this._sharedData.scaleY;
|
|
};
|
|
|
|
// Joints
|
|
gdjs.Physics2RuntimeBehavior.prototype.isJointFirstObject = function(jointId) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return false;
|
|
}
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found
|
|
if (joint === null) return false;
|
|
// Check the joint object
|
|
return joint.GetBodyA() === this._body;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isJointSecondObject = function(jointId) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) {
|
|
this.createBody();
|
|
return false;
|
|
}
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found
|
|
if (joint === null) return false;
|
|
// Check the joint object
|
|
return joint.GetBodyB() === this._body;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getJointFirstAnchorX = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found
|
|
if (joint === null) return 0;
|
|
// Get the joint anchor
|
|
return joint
|
|
.GetBodyA()
|
|
.GetWorldPoint(joint.GetLocalAnchorA())
|
|
.get_x();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getJointFirstAnchorY = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found
|
|
if (joint === null) return 0;
|
|
// Get the joint anchor
|
|
return joint
|
|
.GetBodyA()
|
|
.GetWorldPoint(joint.GetLocalAnchorA())
|
|
.get_y();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getJointSecondAnchorX = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found
|
|
if (joint === null) return 0;
|
|
// Get the joint anchor
|
|
return joint
|
|
.GetBodyB()
|
|
.GetWorldPoint(joint.GetLocalAnchorB())
|
|
.get_x();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getJointSecondAnchorY = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found
|
|
if (joint === null) return 0;
|
|
// Get the joint anchor
|
|
return joint
|
|
.GetBodyB()
|
|
.GetWorldPoint(joint.GetLocalAnchorB())
|
|
.get_y();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getJointReactionForce = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found
|
|
if (joint === null) return 0;
|
|
// Get the reaction force
|
|
return joint.GetReactionForce(1 / this._sharedData.timeStep).Length();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getJointReactionTorque = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found
|
|
if (joint === null) return 0;
|
|
// Get the reaction torque
|
|
return joint.GetReactionTorque(1 / this._sharedData.timeStep);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.removeJoint = function(jointId) {
|
|
// Just let the sharedData to manage and delete the joint
|
|
this._sharedData.removeJoint(jointId);
|
|
};
|
|
|
|
// Distance joint
|
|
gdjs.Physics2RuntimeBehavior.prototype.addDistanceJoint = function(
|
|
x1,
|
|
y1,
|
|
other,
|
|
x2,
|
|
y2,
|
|
length,
|
|
frequency,
|
|
dampingRatio,
|
|
collideConnected,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// If there is no second object or it doesn't share the behavior, return
|
|
if (other == null || !other.hasBehavior(this.name)) return;
|
|
// Get the second body
|
|
var otherBody = other.getBehavior(this.name).getBody();
|
|
// If the first and second objects/bodies are the same, return
|
|
if (this._body === otherBody) return;
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2DistanceJointDef();
|
|
jointDef.set_bodyA(this._body);
|
|
jointDef.set_localAnchorA(
|
|
this._body.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x1 * this._sharedData.invScaleX,
|
|
y1 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_bodyB(otherBody);
|
|
jointDef.set_localAnchorB(
|
|
otherBody.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x2 * this._sharedData.invScaleX,
|
|
y2 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_length(
|
|
length > 0
|
|
? length * this._sharedData.invScaleX
|
|
: this.b2Vec2(
|
|
(x2 - x1) * this._sharedData.invScaleX,
|
|
(y2 - y1) * this._sharedData.invScaleY
|
|
).Length()
|
|
);
|
|
jointDef.set_frequencyHz(frequency >= 0 ? frequency : 0);
|
|
jointDef.set_dampingRatio(dampingRatio >= 0 ? dampingRatio : 1);
|
|
jointDef.set_collideConnected(collideConnected);
|
|
// Create the joint and get the id
|
|
var jointId = this._sharedData.addJoint(
|
|
Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2DistanceJoint
|
|
)
|
|
);
|
|
// Store the id in the variable
|
|
variable.setNumber(jointId);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getDistanceJointLength = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_distanceJoint) return 0;
|
|
// Get the joint length
|
|
return joint.GetLength() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setDistanceJointLength = function(
|
|
jointId,
|
|
length
|
|
) {
|
|
// Invalid value
|
|
if (length <= 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_distanceJoint) return;
|
|
// Set the joint length
|
|
joint.SetLength(length * this._sharedData.invScaleX);
|
|
// Awake the bodies
|
|
joint.GetBodyA().SetAwake(true);
|
|
joint.GetBodyB().SetAwake(true);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getDistanceJointFrequency = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_distanceJoint) return 0;
|
|
// Get the joint frequency
|
|
return joint.GetFrequency();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setDistanceJointFrequency = function(
|
|
jointId,
|
|
frequency
|
|
) {
|
|
// Invalid value
|
|
if (frequency < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_distanceJoint) return;
|
|
// Set the joint frequency
|
|
joint.SetFrequency(frequency);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getDistanceJointDampingRatio = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_distanceJoint) return 0;
|
|
// Get the joint damping ratio
|
|
return joint.GetDampingRatio();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setDistanceJointDampingRatio = function(
|
|
jointId,
|
|
dampingRatio
|
|
) {
|
|
// Invalid value
|
|
if (dampingRatio < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_distanceJoint);
|
|
// Set the joint damping ratio
|
|
joint.SetDampingRatio(dampingRatio);
|
|
};
|
|
|
|
// Revolute joint
|
|
gdjs.Physics2RuntimeBehavior.prototype.addRevoluteJoint = function(
|
|
x,
|
|
y,
|
|
enableLimit,
|
|
referenceAngle,
|
|
lowerAngle,
|
|
upperAngle,
|
|
enableMotor,
|
|
motorSpeed,
|
|
maxMotorTorque,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2RevoluteJointDef();
|
|
jointDef.set_bodyA(this._sharedData.staticBody);
|
|
jointDef.set_localAnchorA(
|
|
this._sharedData.staticBody.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x * this._sharedData.invScaleX,
|
|
y * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_bodyB(this._body);
|
|
jointDef.set_localAnchorB(
|
|
this._body.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x * this._sharedData.invScaleX,
|
|
y * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_enableLimit(enableLimit);
|
|
jointDef.set_referenceAngle(gdjs.toRad(referenceAngle));
|
|
// Lower angle must be lower than upper angle
|
|
if (upperAngle < lowerAngle) {
|
|
var temp = lowerAngle;
|
|
lowerAngle = upperAngle;
|
|
upperAngle = temp;
|
|
}
|
|
jointDef.set_lowerAngle(gdjs.toRad(lowerAngle));
|
|
jointDef.set_upperAngle(gdjs.toRad(upperAngle));
|
|
jointDef.set_enableMotor(enableMotor);
|
|
jointDef.set_motorSpeed(gdjs.toRad(motorSpeed));
|
|
jointDef.set_maxMotorTorque(maxMotorTorque >= 0 ? maxMotorTorque : 0);
|
|
jointDef.set_collideConnected(false);
|
|
// Create the joint and get the id
|
|
var jointId = this._sharedData.addJoint(
|
|
Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2RevoluteJoint
|
|
)
|
|
);
|
|
// Store the id in the variable
|
|
variable.setNumber(jointId);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.addRevoluteJointBetweenTwoBodies = function(
|
|
x1,
|
|
y1,
|
|
other,
|
|
x2,
|
|
y2,
|
|
enableLimit,
|
|
referenceAngle,
|
|
lowerAngle,
|
|
upperAngle,
|
|
enableMotor,
|
|
motorSpeed,
|
|
maxMotorTorque,
|
|
collideConnected,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// If there is no second object or it doesn't share the behavior, return
|
|
if (other == null || !other.hasBehavior(this.name)) return;
|
|
// Get the second body
|
|
var otherBody = other.getBehavior(this.name).getBody();
|
|
// If the first and second objects/bodies are the same, return
|
|
if (this._body === otherBody) return;
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2RevoluteJointDef();
|
|
jointDef.set_bodyA(this._body);
|
|
jointDef.set_localAnchorA(
|
|
this._body.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x1 * this._sharedData.invScaleX,
|
|
y1 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_bodyB(otherBody);
|
|
jointDef.set_localAnchorB(
|
|
otherBody.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x2 * this._sharedData.invScaleX,
|
|
y2 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_enableLimit(enableLimit);
|
|
jointDef.set_referenceAngle(gdjs.toRad(referenceAngle));
|
|
// Lower angle must be lower than upper angle
|
|
if (upperAngle < lowerAngle) {
|
|
var temp = lowerAngle;
|
|
lowerAngle = upperAngle;
|
|
upperAngle = temp;
|
|
}
|
|
jointDef.set_lowerAngle(gdjs.toRad(lowerAngle));
|
|
jointDef.set_upperAngle(gdjs.toRad(upperAngle));
|
|
jointDef.set_enableMotor(enableMotor);
|
|
jointDef.set_motorSpeed(gdjs.toRad(motorSpeed));
|
|
jointDef.set_maxMotorTorque(maxMotorTorque >= 0 ? maxMotorTorque : 0);
|
|
jointDef.set_collideConnected(collideConnected);
|
|
// Create the joint and get the id
|
|
var jointId = this._sharedData.addJoint(
|
|
Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2RevoluteJoint
|
|
)
|
|
);
|
|
// Store the id in the variable
|
|
variable.setNumber(jointId);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getRevoluteJointReferenceAngle = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return 0;
|
|
// Get the joint reference angle
|
|
return gdjs.toDegrees(joint.GetReferenceAngle());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getRevoluteJointAngle = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return 0;
|
|
// Get the joint current angle
|
|
return gdjs.toDegrees(joint.GetJointAngle());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getRevoluteJointSpeed = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return 0;
|
|
// Get the joint angular speed
|
|
return gdjs.toDegrees(joint.GetJointSpeed());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isRevoluteJointLimitsEnabled = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return false;
|
|
// Get the joint limits state
|
|
return joint.IsLimitEnabled();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.enableRevoluteJointLimits = function(
|
|
jointId,
|
|
enable
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return;
|
|
// Set the joint limits state
|
|
joint.EnableLimit(enable);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getRevoluteJointMinAngle = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return 0;
|
|
// Get the joint lower angle
|
|
return gdjs.toDegrees(joint.GetLowerLimit());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getRevoluteJointMaxAngle = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return 0;
|
|
// Get the joint upper angle
|
|
return gdjs.toDegrees(joint.GetUpperLimit());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setRevoluteJointLimits = function(
|
|
jointId,
|
|
lowerAngle,
|
|
upperAngle
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return;
|
|
// Lower angle must be lower than upper angle
|
|
if (upperAngle < lowerAngle) {
|
|
var temp = lowerAngle;
|
|
lowerAngle = upperAngle;
|
|
upperAngle = temp;
|
|
}
|
|
// Set the joint limits
|
|
joint.SetLimits(gdjs.toRad(lowerAngle), gdjs.toRad(upperAngle));
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isRevoluteJointMotorEnabled = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return false;
|
|
// Get the joint motor state
|
|
return joint.IsMotorEnabled();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.enableRevoluteJointMotor = function(
|
|
jointId,
|
|
enable
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return;
|
|
// Set the joint motor state
|
|
joint.EnableMotor(enable);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getRevoluteJointMotorSpeed = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return 0;
|
|
// Get the joint motor speed
|
|
return gdjs.toDegrees(joint.GetMotorSpeed());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setRevoluteJointMotorSpeed = function(
|
|
jointId,
|
|
speed
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return;
|
|
// Set the joint motor speed
|
|
joint.SetMotorSpeed(gdjs.toRad(speed));
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getRevoluteJointMaxMotorTorque = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return 0;
|
|
// Get the joint max motor
|
|
return joint.GetMaxMotorTorque();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setRevoluteJointMaxMotorTorque = function(
|
|
jointId,
|
|
maxTorque
|
|
) {
|
|
// Invalid value
|
|
if (maxTorque < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return;
|
|
// Set the joint max motor
|
|
joint.SetMaxMotorTorque(maxTorque);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getRevoluteJointMotorTorque = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_revoluteJoint) return 0;
|
|
// Get the joint motor torque
|
|
return joint.GetMotorTorque(1 / this._sharedData.timeStep);
|
|
};
|
|
|
|
// Prismatic joint
|
|
gdjs.Physics2RuntimeBehavior.prototype.addPrismaticJoint = function(
|
|
x1,
|
|
y1,
|
|
other,
|
|
x2,
|
|
y2,
|
|
axisAngle,
|
|
referenceAngle,
|
|
enableLimit,
|
|
lowerTranslation,
|
|
upperTranslation,
|
|
enableMotor,
|
|
motorSpeed,
|
|
maxMotorForce,
|
|
collideConnected,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// If there is no second object or it doesn't share the behavior, return
|
|
if (other == null || !other.hasBehavior(this.name)) return;
|
|
// Get the second body
|
|
var otherBody = other.getBehavior(this.name).getBody();
|
|
// If the first and second objects/bodies are the same, return
|
|
if (this._body === otherBody) return;
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2PrismaticJointDef();
|
|
jointDef.set_bodyA(this._body);
|
|
jointDef.set_localAnchorA(
|
|
this._body.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x1 * this._sharedData.invScaleX,
|
|
y1 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_bodyB(otherBody);
|
|
jointDef.set_localAnchorB(
|
|
otherBody.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x2 * this._sharedData.invScaleX,
|
|
y2 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
axisAngle = gdjs.toRad(axisAngle) - this._body.GetAngle();
|
|
jointDef.set_localAxisA(
|
|
this.b2Vec2(Math.cos(axisAngle), Math.sin(axisAngle))
|
|
);
|
|
jointDef.set_referenceAngle(gdjs.toRad(referenceAngle));
|
|
jointDef.set_enableLimit(enableLimit);
|
|
// Lower translation must be lower than upper translation
|
|
if (upperTranslation < lowerTranslation) {
|
|
var temp = lowerTranslation;
|
|
lowerTranslation = upperTranslation;
|
|
upperTranslation = temp;
|
|
}
|
|
// The translation range must include zero
|
|
jointDef.set_lowerTranslation(
|
|
lowerTranslation < 0 ? lowerTranslation * this._sharedData.invScaleX : 0
|
|
);
|
|
jointDef.set_upperTranslation(
|
|
upperTranslation > 0 ? upperTranslation * this._sharedData.invScaleX : 0
|
|
);
|
|
jointDef.set_enableMotor(enableMotor);
|
|
jointDef.set_motorSpeed(motorSpeed * this._sharedData.invScaleX);
|
|
jointDef.set_maxMotorForce(maxMotorForce);
|
|
jointDef.set_collideConnected(collideConnected);
|
|
// Create the joint and get the id
|
|
var jointId = this._sharedData.addJoint(
|
|
Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2PrismaticJoint
|
|
)
|
|
);
|
|
// Store the id in the variable
|
|
variable.setNumber(jointId);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPrismaticJointAxisAngle = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return 0;
|
|
// Get the joint axis angle
|
|
return gdjs.toDegrees(
|
|
Math.atan2(joint.GetLocalAxisA().get_y(), joint.GetLocalAxisA().get_x()) +
|
|
joint.GetBodyA().GetAngle()
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPrismaticJointReferenceAngle = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return 0;
|
|
// Get the joint reference angle
|
|
return gdjs.toDegrees(joint.GetReferenceAngle());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPrismaticJointTranslation = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return 0;
|
|
// Get the joint current translation
|
|
return joint.GetJointTranslation() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPrismaticJointSpeed = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return 0;
|
|
// Get the joint speed
|
|
return joint.GetJointSpeed() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isPrismaticJointLimitsEnabled = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint)
|
|
return false;
|
|
// Get the joint limits state
|
|
return joint.IsLimitEnabled();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.enablePrismaticJointLimits = function(
|
|
jointId,
|
|
enable
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return;
|
|
// Set the joint limits state
|
|
joint.EnableLimit(enable);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPrismaticJointMinTranslation = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return 0;
|
|
// Get the joint lower limit
|
|
return joint.GetLowerLimit() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPrismaticJointMaxTranslation = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return 0;
|
|
// Get the joint upper angle
|
|
return joint.GetUpperLimit() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setPrismaticJointLimits = function(
|
|
jointId,
|
|
lowerTranslation,
|
|
upperTranslation
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return;
|
|
// Lower translation must be lower than upper translation
|
|
if (upperTranslation < lowerTranslation) {
|
|
var temp = lowerTranslation;
|
|
lowerTranslation = upperTranslation;
|
|
upperTranslation = temp;
|
|
}
|
|
// The translation range must include zero
|
|
lowerTranslation = lowerTranslation < 0 ? lowerTranslation : 0;
|
|
upperTranslation = upperTranslation > 0 ? upperTranslation : 0;
|
|
// Set the joint limits
|
|
joint.SetLimits(
|
|
lowerTranslation * this._sharedData.invScaleX,
|
|
upperTranslation * this._sharedData.invScaleX
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isPrismaticJointMotorEnabled = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint)
|
|
return false;
|
|
// Get the joint motor state
|
|
return joint.IsMotorEnabled();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.enablePrismaticJointMotor = function(
|
|
jointId,
|
|
enable
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return;
|
|
// Set the joint motor state
|
|
joint.EnableMotor(enable);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPrismaticJointMotorSpeed = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return 0;
|
|
// Get the joint motor speed
|
|
return joint.GetMotorSpeed() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setPrismaticJointMotorSpeed = function(
|
|
jointId,
|
|
speed
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return;
|
|
// Set the joint motor speed
|
|
joint.SetMotorSpeed(speed * this._sharedData.invScaleX);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPrismaticJointMaxMotorForce = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return 0;
|
|
// Get the joint max motor force
|
|
return joint.GetMaxMotorForce();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setPrismaticJointMaxMotorForce = function(
|
|
jointId,
|
|
maxForce
|
|
) {
|
|
// Invalid value
|
|
if (maxForce < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return;
|
|
// Set the joint max motor force
|
|
joint.SetMaxMotorForce(maxForce);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPrismaticJointMotorForce = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_prismaticJoint) return 0;
|
|
// Get the joint motor torque
|
|
return joint.GetMotorForce(1 / this._sharedData.timeStep);
|
|
};
|
|
|
|
// Pulley joint
|
|
gdjs.Physics2RuntimeBehavior.prototype.addPulleyJoint = function(
|
|
x1,
|
|
y1,
|
|
other,
|
|
x2,
|
|
y2,
|
|
groundX1,
|
|
groundY1,
|
|
groundX2,
|
|
groundY2,
|
|
lengthA,
|
|
lengthB,
|
|
ratio,
|
|
collideConnected,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// If there is no second object or it doesn't share the behavior, return
|
|
if (other == null || !other.hasBehavior(this.name)) return;
|
|
// Get the second body
|
|
var otherBody = other.getBehavior(this.name).getBody();
|
|
// If the first and second objects/bodies are the same, return
|
|
if (this._body === otherBody) return;
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2PulleyJointDef();
|
|
jointDef.set_bodyA(this._body);
|
|
jointDef.set_localAnchorA(
|
|
this._body.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x1 * this._sharedData.invScaleX,
|
|
y1 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_bodyB(otherBody);
|
|
jointDef.set_localAnchorB(
|
|
otherBody.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x2 * this._sharedData.invScaleX,
|
|
y2 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_groundAnchorA(
|
|
this.b2Vec2(
|
|
groundX1 * this._sharedData.invScaleX,
|
|
groundY1 * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
jointDef.set_groundAnchorB(
|
|
this.b2Vec2(
|
|
groundX2 * this._sharedData.invScaleX,
|
|
groundY2 * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
jointDef.set_lengthA(
|
|
lengthA > 0
|
|
? lengthA * this._sharedData.invScaleX
|
|
: this.b2Vec2(
|
|
(groundX1 - x1) * this._sharedData.invScaleX,
|
|
(groundY1 - y1) * this._sharedData.invScaleY
|
|
).Length()
|
|
);
|
|
jointDef.set_lengthB(
|
|
lengthB > 0
|
|
? lengthB * this._sharedData.invScaleX
|
|
: this.b2Vec2(
|
|
(groundX2 - x2) * this._sharedData.invScaleX,
|
|
(groundY2 - y2) * this._sharedData.invScaleY
|
|
).Length()
|
|
);
|
|
jointDef.set_ratio(ratio > 0 ? ratio : 1);
|
|
jointDef.set_collideConnected(collideConnected);
|
|
// Create the joint and get the id
|
|
var jointId = this._sharedData.addJoint(
|
|
Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2PulleyJoint
|
|
)
|
|
);
|
|
// Store the id in the variable
|
|
variable.setNumber(jointId);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPulleyJointFirstGroundAnchorX = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_pulleyJoint) return 0;
|
|
// Get the joint ground anchor
|
|
return joint.GetGroundAnchorA().get_x() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPulleyJointFirstGroundAnchorY = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_pulleyJoint) return 0;
|
|
// Get the joint ground anchor
|
|
return joint.GetGroundAnchorA().get_y() * this._sharedData.scaleY;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPulleyJointSecondGroundAnchorX = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_pulleyJoint) return 0;
|
|
// Get the joint ground anchor
|
|
return joint.GetGroundAnchorB().get_x() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPulleyJointSecondGroundAnchorY = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_pulleyJoint) return 0;
|
|
// Get the joint ground anchor
|
|
return joint.GetGroundAnchorB().get_y() * this._sharedData.scaleY;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPulleyJointFirstLength = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_pulleyJoint) return 0;
|
|
// Get the joint length
|
|
return joint.GetCurrentLengthA() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPulleyJointSecondLength = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_pulleyJoint) return 0;
|
|
// Get the joint length
|
|
return joint.GetCurrentLengthB() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getPulleyJointRatio = function(jointId) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_pulleyJoint) return 0;
|
|
// Get the joint ratio
|
|
return joint.GetRatio();
|
|
};
|
|
|
|
// Gear joint
|
|
gdjs.Physics2RuntimeBehavior.prototype.addGearJoint = function(
|
|
jointId1,
|
|
jointId2,
|
|
ratio,
|
|
collideConnected,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Get the first joint
|
|
var joint1 = this._sharedData.getJoint(jointId1);
|
|
// Joint not found or has wrong type
|
|
if (
|
|
joint1 === null ||
|
|
(joint1.GetType() !== Box2D.e_revoluteJoint &&
|
|
joint1.GetType() !== Box2D.e_prismaticJoint)
|
|
)
|
|
return;
|
|
// Get the second joint
|
|
var joint2 = this._sharedData.getJoint(jointId2);
|
|
if (
|
|
joint2 === null ||
|
|
(joint2.GetType() !== Box2D.e_revoluteJoint &&
|
|
joint2.GetType() !== Box2D.e_prismaticJoint)
|
|
)
|
|
return;
|
|
// The joints are the same
|
|
if (joint1 === joint2) return;
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2GearJointDef();
|
|
// Set gear joint bodies is not necessary at first, as the gear get the bodies from the two child joints
|
|
// But we must pass two different bodies to bypass a test inherited from b2Joint
|
|
jointDef.set_bodyA(this._sharedData.staticBody);
|
|
jointDef.set_bodyB(this._body);
|
|
jointDef.set_joint1(joint1);
|
|
jointDef.set_joint2(joint2);
|
|
jointDef.set_ratio(ratio);
|
|
jointDef.set_collideConnected(collideConnected);
|
|
// Create the joint and get the id
|
|
var jointId = this._sharedData.addJoint(
|
|
Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2GearJoint
|
|
)
|
|
);
|
|
// Store the id in the variable
|
|
variable.setNumber(jointId);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getGearJointFirstJoint = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_gearJoint) return 0;
|
|
// Get the joint first joint
|
|
return this._sharedData.getJointId(joint.GetJoint1());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getGearJointSecondJoint = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_gearJoint) return 0;
|
|
// Get the joint second joint
|
|
return this._sharedData.getJointId(joint.GetJoint2());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getGearJointRatio = function(jointId) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_gearJoint) return 0;
|
|
// Get the joint ratio
|
|
return joint.GetRatio();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setGearJointRatio = function(
|
|
jointId,
|
|
ratio
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_gearJoint) return;
|
|
// Set the joint ratio
|
|
joint.SetRatio(ratio);
|
|
// Awake the bodies, the gear joint picks the dynamic bodies as first and second body (second bodies from the child joints)
|
|
joint.GetBodyA().SetAwake(true);
|
|
joint.GetBodyB().SetAwake(true);
|
|
};
|
|
|
|
// Mouse joint
|
|
gdjs.Physics2RuntimeBehavior.prototype.addMouseJoint = function(
|
|
targetX,
|
|
targetY,
|
|
maxForce,
|
|
frequency,
|
|
dampingRatio,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2MouseJointDef();
|
|
jointDef.set_bodyA(this._sharedData.staticBody);
|
|
jointDef.set_bodyB(this._body);
|
|
jointDef.set_target(
|
|
this.b2Vec2(
|
|
targetX * this._sharedData.invScaleX,
|
|
targetY * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
jointDef.set_maxForce(maxForce >= 0 ? maxForce : 0);
|
|
jointDef.set_frequencyHz(frequency > 0 ? frequency : 1);
|
|
jointDef.set_dampingRatio(dampingRatio >= 0 ? dampingRatio : 0);
|
|
// Create the joint and get the id
|
|
var jointId = this._sharedData.addJoint(
|
|
Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2MouseJoint
|
|
)
|
|
);
|
|
// Store the id in the variable
|
|
variable.setNumber(jointId);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMouseJointTargetX = function(
|
|
jointId
|
|
) {
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_mouseJoint) return 0;
|
|
// Get the joint target X
|
|
return joint.GetTarget().get_x() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMouseJointTargetY = function(
|
|
jointId
|
|
) {
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_mouseJoint) return 0;
|
|
// Get the joint target Y
|
|
return joint.GetTarget().get_y() * this._sharedData.scaleY;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setMouseJointTarget = function(
|
|
jointId,
|
|
targetX,
|
|
targetY
|
|
) {
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_mouseJoint) return;
|
|
// Set the joint target
|
|
joint.SetTarget(
|
|
this.b2Vec2(
|
|
targetX * this._sharedData.invScaleX,
|
|
targetY * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
// Awake the body
|
|
joint.GetBodyB().SetAwake(true);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMouseJointMaxForce = function(
|
|
jointId
|
|
) {
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_mouseJoint) return 0;
|
|
// Get the joint max force
|
|
return joint.GetMaxForce();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setMouseJointMaxForce = function(
|
|
jointId,
|
|
maxForce
|
|
) {
|
|
// Invalid value
|
|
if (maxForce < 0) return;
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_mouseJoint) return;
|
|
// Set the joint max force
|
|
joint.SetMaxForce(maxForce);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMouseJointFrequency = function(
|
|
jointId
|
|
) {
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_mouseJoint) return 0;
|
|
// Get the joint frequency
|
|
return joint.GetFrequency();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setMouseJointFrequency = function(
|
|
jointId,
|
|
frequency
|
|
) {
|
|
// Invalid value
|
|
if (frequency <= 0) return;
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_mouseJoint) return;
|
|
// Set the joint frequency
|
|
joint.SetFrequency(frequency);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMouseJointDampingRatio = function(
|
|
jointId
|
|
) {
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_mouseJoint) return 0;
|
|
// Get the joint damping ratio
|
|
return joint.GetDampingRatio();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setMouseJointDampingRatio = function(
|
|
jointId,
|
|
dampingRatio
|
|
) {
|
|
// Invalid value
|
|
if (dampingRatio < 0) return;
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_mouseJoint) return;
|
|
// Set the joint damping ratio
|
|
joint.SetDampingRatio(dampingRatio);
|
|
};
|
|
|
|
// Wheel joint
|
|
gdjs.Physics2RuntimeBehavior.prototype.addWheelJoint = function(
|
|
x1,
|
|
y1,
|
|
other,
|
|
x2,
|
|
y2,
|
|
axisAngle,
|
|
frequency,
|
|
dampingRatio,
|
|
enableMotor,
|
|
motorSpeed,
|
|
maxMotorTorque,
|
|
collideConnected,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// If there is no second object or it doesn't share the behavior, return
|
|
if (other == null || !other.hasBehavior(this.name)) return;
|
|
// Get the second body
|
|
var otherBody = other.getBehavior(this.name).getBody();
|
|
// If the first and second objects/bodies are the same, return
|
|
if (this._body === otherBody) return;
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2WheelJointDef();
|
|
jointDef.set_bodyA(this._body);
|
|
jointDef.set_localAnchorA(
|
|
this._body.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x1 * this._sharedData.invScaleX,
|
|
y1 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_bodyB(otherBody);
|
|
jointDef.set_localAnchorB(
|
|
otherBody.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x2 * this._sharedData.invScaleX,
|
|
y2 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
axisAngle = gdjs.toRad(axisAngle) - this._body.GetAngle();
|
|
jointDef.set_localAxisA(
|
|
this.b2Vec2(Math.cos(axisAngle), Math.sin(axisAngle))
|
|
);
|
|
jointDef.set_frequencyHz(frequency > 0 ? frequency : 1);
|
|
jointDef.set_dampingRatio(dampingRatio >= 0 ? dampingRatio : 0);
|
|
jointDef.set_enableMotor(enableMotor);
|
|
jointDef.set_motorSpeed(gdjs.toRad(motorSpeed));
|
|
jointDef.set_maxMotorTorque(maxMotorTorque);
|
|
jointDef.set_collideConnected(collideConnected);
|
|
// Create the joint and get the id
|
|
var jointId = this._sharedData.addJoint(
|
|
Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2WheelJoint
|
|
)
|
|
);
|
|
// Store the id in the variable
|
|
variable.setNumber(jointId);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getWheelJointAxisAngle = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return 0;
|
|
// Get the joint axis angle
|
|
return gdjs.toDegrees(
|
|
Math.atan2(joint.GetLocalAxisA().get_y(), joint.GetLocalAxisA().get_x()) +
|
|
joint.GetBodyA().GetAngle()
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getWheelJointTranslation = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return 0;
|
|
// Get the joint current translation
|
|
return joint.GetJointTranslation() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getWheelJointSpeed = function(jointId) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return 0;
|
|
// Get the joint speed
|
|
return gdjs.toDegrees(joint.GetJointSpeed());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.isWheelJointMotorEnabled = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return false;
|
|
// Get the joint motor state
|
|
return joint.IsMotorEnabled();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.enableWheelJointMotor = function(
|
|
jointId,
|
|
enable
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return;
|
|
// Set the joint motor state
|
|
joint.EnableMotor(enable);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getWheelJointMotorSpeed = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return 0;
|
|
// Get the joint motor speed
|
|
return gdjs.toDegrees(joint.GetMotorSpeed());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setWheelJointMotorSpeed = function(
|
|
jointId,
|
|
speed
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return;
|
|
// Set the joint motor speed
|
|
joint.SetMotorSpeed(gdjs.toRad(speed));
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getWheelJointMaxMotorTorque = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return 0;
|
|
// Get the joint max motor torque
|
|
return joint.GetMaxMotorTorque();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setWheelJointMaxMotorTorque = function(
|
|
jointId,
|
|
maxTorque
|
|
) {
|
|
// Invalid value
|
|
if (maxTorque < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return;
|
|
// Set the joint max motor torque
|
|
joint.SetMaxMotorTorque(maxTorque);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getWheelJointMotorTorque = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return 0;
|
|
// Get the joint motor torque
|
|
return joint.GetMotorTorque(1 / this._sharedData.timeStep);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getWheelJointFrequency = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return 0;
|
|
// Get the joint frequency
|
|
return joint.GetSpringFrequencyHz();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setWheelJointFrequency = function(
|
|
jointId,
|
|
frequency
|
|
) {
|
|
// Invalid value
|
|
if (frequency < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return;
|
|
// Set the joint frequency
|
|
joint.SetSpringFrequencyHz(frequency);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getWheelJointDampingRatio = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return 0;
|
|
// Get the joint damping ratio
|
|
return joint.GetSpringDampingRatio();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setWheelJointDampingRatio = function(
|
|
jointId,
|
|
dampingRatio
|
|
) {
|
|
// Invalid value
|
|
if (dampingRatio < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_wheelJoint) return;
|
|
// Set the joint damping ratio
|
|
joint.SetSpringDampingRatio(dampingRatio);
|
|
};
|
|
|
|
// Weld joint
|
|
gdjs.Physics2RuntimeBehavior.prototype.addWeldJoint = function(
|
|
x1,
|
|
y1,
|
|
other,
|
|
x2,
|
|
y2,
|
|
referenceAngle,
|
|
frequency,
|
|
dampingRatio,
|
|
collideConnected,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// If there is no second object or it doesn't share the behavior, return
|
|
if (other == null || !other.hasBehavior(this.name)) return;
|
|
// Get the second body
|
|
var otherBody = other.getBehavior(this.name).getBody();
|
|
// If the first and second objects/bodies are the same, return
|
|
if (this._body === otherBody) return;
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2WeldJointDef();
|
|
jointDef.set_bodyA(this._body);
|
|
jointDef.set_localAnchorA(
|
|
this._body.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x1 * this._sharedData.invScaleX,
|
|
y1 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_bodyB(otherBody);
|
|
jointDef.set_localAnchorB(
|
|
otherBody.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x2 * this._sharedData.invScaleX,
|
|
y2 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_referenceAngle(gdjs.toRad(referenceAngle));
|
|
jointDef.set_frequencyHz(frequency > 0 ? frequency : 1);
|
|
jointDef.set_dampingRatio(dampingRatio >= 0 ? dampingRatio : 0);
|
|
jointDef.set_collideConnected(collideConnected);
|
|
// Create the joint
|
|
var joint = Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2WeldJoint
|
|
);
|
|
// b2WeldJoint.GetReferenceAngle() is not binded, store it manually
|
|
joint.referenceAngle = jointDef.get_referenceAngle();
|
|
// Store the id in the variable
|
|
variable.setNumber(this._sharedData.addJoint(joint));
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getWeldJointReferenceAngle = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_weldJoint) return 0;
|
|
// b2WeldJoint.GetReferenceAngle() is not binded
|
|
// return gdjs.toDegrees(joint.GetReferenceAngle());
|
|
return gdjs.toDegrees(joint.referenceAngle);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getWeldJointFrequency = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_weldJoint) return 0;
|
|
// Get the joint frequency
|
|
return joint.GetFrequency();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setWeldJointFrequency = function(
|
|
jointId,
|
|
frequency
|
|
) {
|
|
// Invalid value
|
|
if (frequency < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_weldJoint) return;
|
|
// Set the joint frequency
|
|
joint.SetFrequency(frequency);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getWeldJointDampingRatio = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_weldJoint) return 0;
|
|
// Get the joint damping ratio
|
|
return joint.GetDampingRatio();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setWeldJointDampingRatio = function(
|
|
jointId,
|
|
dampingRatio
|
|
) {
|
|
// Invalid value
|
|
if (dampingRatio < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_weldJoint) return;
|
|
// Set the joint damping ratio
|
|
joint.SetDampingRatio(dampingRatio);
|
|
};
|
|
|
|
// Rope joint
|
|
gdjs.Physics2RuntimeBehavior.prototype.addRopeJoint = function(
|
|
x1,
|
|
y1,
|
|
other,
|
|
x2,
|
|
y2,
|
|
maxLength,
|
|
collideConnected,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// If there is no second object or it doesn't share the behavior, return
|
|
if (other == null || !other.hasBehavior(this.name)) return;
|
|
// Get the second body
|
|
var otherBody = other.getBehavior(this.name).getBody();
|
|
// If the first and second objects/bodies are the same, return
|
|
if (this._body === otherBody) return;
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2RopeJointDef();
|
|
jointDef.set_bodyA(this._body);
|
|
jointDef.set_localAnchorA(
|
|
this._body.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x1 * this._sharedData.invScaleX,
|
|
y1 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_bodyB(otherBody);
|
|
jointDef.set_localAnchorB(
|
|
otherBody.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x2 * this._sharedData.invScaleX,
|
|
y2 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_maxLength(
|
|
maxLength > 0
|
|
? maxLength * this._sharedData.invScaleX
|
|
: this.b2Vec2(
|
|
(x2 - x1) * this._sharedData.invScaleX,
|
|
(y2 - y1) * this._sharedData.invScaleY
|
|
).Length()
|
|
);
|
|
jointDef.set_collideConnected(collideConnected);
|
|
// Create the joint and get the id
|
|
var jointId = this._sharedData.addJoint(
|
|
Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2RopeJoint
|
|
)
|
|
);
|
|
// Store the id in the variable
|
|
variable.setNumber(jointId);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getRopeJointMaxLength = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_ropeJoint) return 0;
|
|
// Get the joint maximum length
|
|
return joint.GetMaxLength() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setRopeJointMaxLength = function(
|
|
jointId,
|
|
maxLength
|
|
) {
|
|
// Invalid value
|
|
if (maxLength < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_ropeJoint) return;
|
|
// Set the joint maximum length
|
|
joint.SetMaxLength(maxLength * this._sharedData.invScaleX);
|
|
// Awake the bodies
|
|
joint.GetBodyA().SetAwake(true);
|
|
joint.GetBodyB().SetAwake(true);
|
|
};
|
|
|
|
// Friction joint
|
|
gdjs.Physics2RuntimeBehavior.prototype.addFrictionJoint = function(
|
|
x1,
|
|
y1,
|
|
other,
|
|
x2,
|
|
y2,
|
|
maxForce,
|
|
maxTorque,
|
|
collideConnected,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// If there is no second object or it doesn't share the behavior, return
|
|
if (other == null || !other.hasBehavior(this.name)) return;
|
|
// Get the second body
|
|
var otherBody = other.getBehavior(this.name).getBody();
|
|
// If the first and second objects/bodies are the same, return
|
|
if (this._body === otherBody) return;
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2FrictionJointDef();
|
|
jointDef.set_bodyA(this._body);
|
|
jointDef.set_localAnchorA(
|
|
this._body.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x1 * this._sharedData.invScaleX,
|
|
y1 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_bodyB(otherBody);
|
|
jointDef.set_localAnchorB(
|
|
otherBody.GetLocalPoint(
|
|
this.b2Vec2(
|
|
x2 * this._sharedData.invScaleX,
|
|
y2 * this._sharedData.invScaleY
|
|
)
|
|
)
|
|
);
|
|
jointDef.set_maxForce(maxForce >= 0 ? maxForce : 0);
|
|
jointDef.set_maxTorque(maxTorque >= 0 ? maxTorque : 0);
|
|
jointDef.set_collideConnected(collideConnected);
|
|
// Create the joint and get the id
|
|
var jointId = this._sharedData.addJoint(
|
|
Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2FrictionJoint
|
|
)
|
|
);
|
|
// Store the id in the variable
|
|
variable.setNumber(jointId);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getFrictionJointMaxForce = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_frictionJoint) return 0;
|
|
// Get the joint maximum force
|
|
return joint.GetMaxForce();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setFrictionJointMaxForce = function(
|
|
jointId,
|
|
maxForce
|
|
) {
|
|
// Invalid value
|
|
if (maxForce < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_frictionJoint) return;
|
|
// Set the joint maximum force
|
|
joint.SetMaxForce(maxForce);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getFrictionJointMaxTorque = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_frictionJoint) return 0;
|
|
// Get the joint maximum torque
|
|
return joint.GetMaxTorque();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setFrictionJointMaxTorque = function(
|
|
jointId,
|
|
maxTorque
|
|
) {
|
|
// Invalid value
|
|
if (maxTorque < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_frictionJoint) return;
|
|
// Set the joint maximum torque
|
|
joint.SetMaxTorque(maxTorque);
|
|
};
|
|
|
|
// Motor joint
|
|
gdjs.Physics2RuntimeBehavior.prototype.addMotorJoint = function(
|
|
other,
|
|
offsetX,
|
|
offsetY,
|
|
offsetAngle,
|
|
maxForce,
|
|
maxTorque,
|
|
correctionFactor,
|
|
collideConnected,
|
|
variable
|
|
) {
|
|
// If there is no body, set a new one
|
|
if (this._body === null) this.createBody();
|
|
// If there is no second object or it doesn't share the behavior, return
|
|
if (other == null || !other.hasBehavior(this.name)) return;
|
|
// Get the second body
|
|
var otherBody = other.getBehavior(this.name).getBody();
|
|
// If the first and second objects/bodies are the same, return
|
|
if (this._body === otherBody) return;
|
|
// Set joint settings
|
|
var jointDef = new Box2D.b2MotorJointDef();
|
|
jointDef.set_bodyA(this._body);
|
|
jointDef.set_bodyB(otherBody);
|
|
jointDef.set_linearOffset(
|
|
this.b2Vec2(
|
|
offsetX * this._sharedData.invScaleX,
|
|
offsetY * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
jointDef.set_angularOffset(gdjs.toRad(offsetAngle));
|
|
jointDef.set_maxForce(maxForce >= 0 ? maxForce : 0);
|
|
jointDef.set_maxTorque(maxTorque >= 0 ? maxTorque : 0);
|
|
jointDef.set_correctionFactor(
|
|
correctionFactor < 0 ? 0 : correctionFactor > 1 ? 1 : correctionFactor
|
|
);
|
|
jointDef.set_collideConnected(collideConnected);
|
|
// Create the joint and get the id
|
|
var jointId = this._sharedData.addJoint(
|
|
Box2D.castObject(
|
|
this._sharedData.world.CreateJoint(jointDef),
|
|
Box2D.b2MotorJoint
|
|
)
|
|
);
|
|
// Store the id in the variable
|
|
variable.setNumber(jointId);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMotorJointOffsetX = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_motorJoint) return 0;
|
|
// Get the joint offset
|
|
return joint.GetLinearOffset().get_x() * this._sharedData.scaleX;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMotorJointOffsetY = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_motorJoint) return 0;
|
|
// Get the joint offset
|
|
return joint.GetLinearOffset().get_y() * this._sharedData.scaleY;
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setMotorJointOffset = function(
|
|
jointId,
|
|
offsetX,
|
|
offsetY
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_motorJoint) return;
|
|
// Set the joint offset
|
|
joint.SetLinearOffset(
|
|
this.b2Vec2(
|
|
offsetX * this._sharedData.invScaleX,
|
|
offsetY * this._sharedData.invScaleY
|
|
)
|
|
);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMotorJointAngularOffset = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_motorJoint) return 0;
|
|
// Get the joint angular offset
|
|
return gdjs.toDegrees(joint.GetAngularOffset());
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setMotorJointAngularOffset = function(
|
|
jointId,
|
|
offsetAngle
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_motorJoint) return;
|
|
// Set the joint angular offset
|
|
joint.SetAngularOffset(gdjs.toRad(offsetAngle));
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMotorJointMaxForce = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_motorJoint) return 0;
|
|
// Get the joint maximum force
|
|
return joint.GetMaxForce();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setMotorJointMaxForce = function(
|
|
jointId,
|
|
maxForce
|
|
) {
|
|
// Invalid value
|
|
if (maxForce < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_motorJoint) return;
|
|
// Set the joint maximum force
|
|
joint.SetMaxForce(maxForce);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMotorJointMaxTorque = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_motorJoint) return 0;
|
|
// Get the joint maximum torque
|
|
return joint.GetMaxTorque();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setMotorJointMaxTorque = function(
|
|
jointId,
|
|
maxTorque
|
|
) {
|
|
// Invalid value
|
|
if (maxTorque < 0) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_motorJoint) return;
|
|
// Set the joint maximum torque
|
|
joint.SetMaxTorque(maxTorque);
|
|
// Awake the bodies
|
|
joint.GetBodyA().SetAwake(true);
|
|
joint.GetBodyB().SetAwake(true);
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.getMotorJointCorrectionFactor = function(
|
|
jointId
|
|
) {
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_motorJoint) return 0;
|
|
// Get the joint correction factor
|
|
return joint.GetCorrectionFactor();
|
|
};
|
|
|
|
gdjs.Physics2RuntimeBehavior.prototype.setMotorJointCorrectionFactor = function(
|
|
jointId,
|
|
correctionFactor
|
|
) {
|
|
// Invalid value
|
|
if (correctionFactor < 0 || correctionFactor > 1) return;
|
|
// Get the joint
|
|
var joint = this._sharedData.getJoint(jointId);
|
|
// Joint not found or has wrong type
|
|
if (joint === null || joint.GetType() !== Box2D.e_motorJoint) return;
|
|
// Set the joint correction factor
|
|
joint.SetCorrectionFactor(correctionFactor);
|
|
// Awake the bodies
|
|
joint.GetBodyA().SetAwake(true);
|
|
joint.GetBodyB().SetAwake(true);
|
|
};
|
|
|
|
// Collision
|
|
gdjs.Physics2RuntimeBehavior.collisionTest = function(
|
|
object1,
|
|
object2,
|
|
behaviorName
|
|
) {
|
|
// Check if the objects exist and share the behavior
|
|
if (object1 === null || !object1.hasBehavior(behaviorName)) return false;
|
|
if (object2 === null || !object2.hasBehavior(behaviorName)) return false;
|
|
// Test if the second object is in the list of contacts of the first one
|
|
var behavior1 = object1.getBehavior(behaviorName);
|
|
for (var i = 0, len = behavior1.currentContacts.length; i < len; ++i) {
|
|
if (behavior1.currentContacts[i].owner === object2) {
|
|
return true;
|
|
}
|
|
}
|
|
// No contact found
|
|
return false;
|
|
};
|