UNPKG

@babylonjs/core

Version:

Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.

620 lines 28.9 kB
import { PhysicsPrestepType } from "./IPhysicsEnginePlugin.js"; import { Vector3, Quaternion, TmpVectors } from "../../Maths/math.vector.js"; /** * PhysicsBody is useful for creating a physics body that can be used in a physics engine. It allows * the user to set the mass and velocity of the body, which can then be used to calculate the * motion of the body in the physics engine. */ export class PhysicsBody { /** * Disable pre-step that consists in updating Physics Body from Transform Node Translation/Orientation. * True by default for maximum performance. */ get disablePreStep() { return this._prestepType == PhysicsPrestepType.DISABLED; } set disablePreStep(value) { this._prestepType = value ? PhysicsPrestepType.DISABLED : PhysicsPrestepType.TELEPORT; } /** * Constructs a new physics body for the given node. * @param transformNode - The Transform Node to construct the physics body for. For better performance, it is advised that this node does not have a parent. * @param motionType - The motion type of the physics body. The options are: * - PhysicsMotionType.STATIC - Static bodies are not moving and unaffected by forces or collisions. They are good for level boundaries or terrain. * - PhysicsMotionType.DYNAMIC - Dynamic bodies are fully simulated. They can move and collide with other objects. * - PhysicsMotionType.ANIMATED - They behave like dynamic bodies, but they won't be affected by other bodies, but still push other bodies out of the way. * @param startsAsleep - Whether the physics body should start in a sleeping state (not a guarantee). Defaults to false. * @param scene - The scene containing the physics engine. * * This code is useful for creating a physics body for a given Transform Node in a scene. * It checks the version of the physics engine and the physics plugin, and initializes the body accordingly. * It also sets the node's rotation quaternion if it is not already set. Finally, it adds the body to the physics engine. */ constructor(transformNode, motionType, startsAsleep, scene) { /** * V2 Physics plugin private data for single Transform */ this._pluginData = undefined; /** * V2 Physics plugin private data for instances */ this._pluginDataInstances = []; /** * If the collision callback is enabled */ this._collisionCBEnabled = false; /** * If the collision ended callback is enabled */ this._collisionEndedCBEnabled = false; /** * Disable sync from physics to transformNode. This value is set to true at body creation or at motionType setting when the body is not dynamic. */ this.disableSync = false; this._isDisposed = false; this._shape = null; this._prestepType = PhysicsPrestepType.DISABLED; if (!scene) { return; } const physicsEngine = scene.getPhysicsEngine(); if (!physicsEngine) { throw new Error("No Physics Engine available."); } this._physicsEngine = physicsEngine; if (physicsEngine.getPluginVersion() != 2) { throw new Error("Plugin version is incorrect. Expected version 2."); } const physicsPlugin = physicsEngine.getPhysicsPlugin(); if (!physicsPlugin) { throw new Error("No Physics Plugin available."); } this._physicsPlugin = physicsPlugin; if (!transformNode.rotationQuaternion) { transformNode.rotationQuaternion = Quaternion.FromEulerAngles(transformNode.rotation.x, transformNode.rotation.y, transformNode.rotation.z); } this.startAsleep = startsAsleep; this._motionType = motionType; // only dynamic and animated body needs sync from physics to transformNode this.disableSync = motionType == 0 /* PhysicsMotionType.STATIC */; // instances? const m = transformNode; if (m.hasThinInstances) { this._physicsPlugin.initBodyInstances(this, motionType, m); } else { // single instance if (transformNode.parent) { // Force computation of world matrix so that the parent transforms are correctly reflected in absolutePosition/absoluteRotationQuaternion. transformNode.computeWorldMatrix(true); } this._physicsPlugin.initBody(this, motionType, transformNode.absolutePosition, transformNode.absoluteRotationQuaternion); } this.transformNode = transformNode; transformNode.physicsBody = this; physicsEngine.addBody(this); this._nodeDisposeObserver = transformNode.onDisposeObservable.add(() => { this.dispose(); }); } /** * Returns the string "PhysicsBody". * @returns "PhysicsBody" */ getClassName() { return "PhysicsBody"; } /** * Clone the PhysicsBody to a new body and assign it to the transformNode parameter * @param transformNode transformNode that will be used for the cloned PhysicsBody * @returns the newly cloned PhysicsBody */ clone(transformNode) { const clonedBody = new PhysicsBody(transformNode, this.getMotionType(), this.startAsleep, this.transformNode.getScene()); clonedBody.shape = this.shape; clonedBody.setMassProperties(this.getMassProperties()); clonedBody.setLinearDamping(this.getLinearDamping()); clonedBody.setAngularDamping(this.getAngularDamping()); return clonedBody; } /** * If a physics body is connected to an instanced node, update the number physic instances to match the number of node instances. */ updateBodyInstances() { const m = this.transformNode; if (m.hasThinInstances) { this._physicsPlugin.updateBodyInstances(this, m); } } /** * This returns the number of internal instances of the physics body */ get numInstances() { return this._pluginDataInstances.length; } /** * Get the motion type of the physics body. Can be STATIC, DYNAMIC, or ANIMATED. */ get motionType() { return this._motionType; } /** * Sets the shape of the physics body. * @param shape - The shape of the physics body. * * This method is useful for setting the shape of the physics body, which is necessary for the physics engine to accurately simulate the body's behavior. * The shape is used to calculate the body's mass, inertia, and other properties. */ set shape(shape) { this._shape = shape; if (shape) { this._physicsPlugin.setShape(this, shape); } } /** * Retrieves the physics shape associated with this object. * * @returns The physics shape associated with this object, or `undefined` if no * shape is associated. * * This method is useful for retrieving the physics shape associated with this object, * which can be used to apply physical forces to the object or to detect collisions. */ get shape() { return this._shape; } /** * Returns the bounding box of the physics body. * @returns The bounding box of the physics body. */ getBoundingBox() { return this._physicsPlugin.getBodyBoundingBox(this); } /** * Sets the event mask for the physics engine. * * @param eventMask - A bitmask that determines which events will be sent to the physics engine. * @param instanceIndex - If this body is instanced, the index of the instance to set the event mask for. * * This method is useful for setting the event mask for the physics engine, which determines which events * will be sent to the physics engine. This allows the user to control which events the physics engine will respond to. */ setEventMask(eventMask, instanceIndex) { this._physicsPlugin.setEventMask(this, eventMask, instanceIndex); } /** * Gets the event mask of the physics engine. * @param instanceIndex - If this body is instanced, the index of the instance to get the event mask for. * @returns The event mask of the physics engine. * * This method is useful for getting the event mask of the physics engine, * which is used to determine which events the engine will respond to. * This is important for ensuring that the engine is responding to the correct events and not * wasting resources on unnecessary events. */ getEventMask(instanceIndex) { return this._physicsPlugin.getEventMask(this, instanceIndex); } /** * Sets the motion type of the physics body. Can be STATIC, DYNAMIC, or ANIMATED. * @param motionType - The motion type to set. * @param instanceIndex - If this body is instanced, the index of the instance to set the motion type for. */ setMotionType(motionType, instanceIndex) { this.disableSync = motionType == 0 /* PhysicsMotionType.STATIC */; this._physicsPlugin.setMotionType(this, motionType, instanceIndex); } /** * Gets the motion type of the physics body. Can be STATIC, DYNAMIC, or ANIMATED. * @param instanceIndex - If this body is instanced, the index of the instance to get the motion type for. * @returns The motion type of the physics body. */ getMotionType(instanceIndex) { return this._physicsPlugin.getMotionType(this, instanceIndex); } /** * Set the prestep type of the body * @param prestepType prestep type provided by PhysicsPrestepType */ setPrestepType(prestepType) { this._prestepType = prestepType; } /** * Get the current prestep type of the body * @returns the type of prestep associated with the body and its instance index */ getPrestepType() { return this._prestepType; } /** * Computes the mass properties of the physics object, based on the set of physics shapes this body uses. * This method is useful for computing the initial mass properties of a physics object, such as its mass, * inertia, and center of mass; these values are important for accurately simulating the physics of the * object in the physics engine, and computing values based on the shape will provide you with reasonable * initial values, which you can then customize. * @param instanceIndex - The index of the instance to compute the mass properties for. * @returns The mass properties of the object. */ computeMassProperties(instanceIndex) { return this._physicsPlugin.computeMassProperties(this, instanceIndex); } /** * Sets the mass properties of the physics object. * * @param massProps - The mass properties to set. * @param instanceIndex - The index of the instance to set the mass properties for. If not defined, the mass properties will be set for all instances. * * This method is useful for setting the mass properties of a physics object, such as its mass, * inertia, and center of mass. This is important for accurately simulating the physics of the object in the physics engine. */ setMassProperties(massProps, instanceIndex) { this._physicsPlugin.setMassProperties(this, massProps, instanceIndex); } /** * Retrieves the mass properties of the object. * @param instanceIndex - If this body is instanced, the index of the instance to get the mass properties for. * @returns The mass properties of the object. * * This method is useful for physics simulations, as it allows the user to * retrieve the mass properties of the object, such as its mass, center of mass, * and moment of inertia. This information is necessary for accurate physics * simulations. */ getMassProperties(instanceIndex) { return this._physicsPlugin.getMassProperties(this, instanceIndex); } /** * Sets the linear damping of the physics body. * * @param damping - The linear damping value. * @param instanceIndex - If this body is instanced, the index of the instance to set the linear damping for. * * This method is useful for controlling the linear damping of the physics body, * which is the rate at which the body's velocity decreases over time. This is useful for simulating * the effects of air resistance or other forms of friction. */ setLinearDamping(damping, instanceIndex) { this._physicsPlugin.setLinearDamping(this, damping, instanceIndex); } /** * Gets the linear damping of the physics body. * @param instanceIndex - If this body is instanced, the index of the instance to get the linear damping for. * @returns The linear damping of the physics body. * * This method is useful for retrieving the linear damping of the physics body, which is the amount of * resistance the body has to linear motion. This is useful for simulating realistic physics behavior * in a game. */ getLinearDamping(instanceIndex) { return this._physicsPlugin.getLinearDamping(this, instanceIndex); } /** * Sets the angular damping of the physics body. * @param damping The angular damping of the body. * @param instanceIndex - If this body is instanced, the index of the instance to set the angular damping for. * * This method is useful for controlling the angular velocity of a physics body. * By setting the damping, the body's angular velocity will be reduced over time, simulating the effect of friction. * This can be used to create realistic physical behavior in a physics engine. */ setAngularDamping(damping, instanceIndex) { this._physicsPlugin.setAngularDamping(this, damping, instanceIndex); } /** * Gets the angular damping of the physics body. * @param instanceIndex - If this body is instanced, the index of the instance to get the angular damping for. * * @returns The angular damping of the physics body. * * This method is useful for getting the angular damping of the physics body, * which is the rate of reduction of the angular velocity over time. * This is important for simulating realistic physics behavior in a game. */ getAngularDamping(instanceIndex) { return this._physicsPlugin.getAngularDamping(this, instanceIndex); } /** * Sets the linear velocity of the physics object. * @param linVel - The linear velocity to set. * @param instanceIndex - If this body is instanced, the index of the instance to set the linear velocity for. * * This method is useful for setting the linear velocity of a physics object, * which is necessary for simulating realistic physics in a game engine. * By setting the linear velocity, the physics object will move in the direction and speed specified by the vector. * This allows for realistic physics simulations, such as simulating the motion of a ball rolling down a hill. */ setLinearVelocity(linVel, instanceIndex) { this._physicsPlugin.setLinearVelocity(this, linVel, instanceIndex); } /** * Gets the linear velocity of the physics body and stores it in the given vector3. * @param linVel - The vector3 to store the linear velocity in. * @param instanceIndex - If this body is instanced, the index of the instance to get the linear velocity for. * * This method is useful for getting the linear velocity of a physics body in a physics engine. * This can be used to determine the speed and direction of the body, which can be used to calculate the motion of the body. */ getLinearVelocityToRef(linVel, instanceIndex) { this._physicsPlugin.getLinearVelocityToRef(this, linVel, instanceIndex); } /** * Gets the linear velocity of the physics body as a new vector3. * @param instanceIndex - If this body is instanced, the index of the instance to get the linear velocity for. * @returns The linear velocity of the physics body. * * This method is useful for getting the linear velocity of a physics body in a physics engine. * This can be used to determine the speed and direction of the body, which can be used to calculate the motion of the body. */ getLinearVelocity(instanceIndex) { const ref = new Vector3(); this.getLinearVelocityToRef(ref, instanceIndex); return ref; } /** * Sets the angular velocity of the physics object. * @param angVel - The angular velocity to set. * @param instanceIndex - If this body is instanced, the index of the instance to set the angular velocity for. * * This method is useful for setting the angular velocity of a physics object, which is necessary for * simulating realistic physics behavior. The angular velocity is used to determine the rate of rotation of the object, * which is important for simulating realistic motion. */ setAngularVelocity(angVel, instanceIndex) { this._physicsPlugin.setAngularVelocity(this, angVel, instanceIndex); } /** * Gets the angular velocity of the physics body and stores it in the given vector3. * @param angVel - The vector3 to store the angular velocity in. * @param instanceIndex - If this body is instanced, the index of the instance to get the angular velocity for. * * This method is useful for getting the angular velocity of a physics body, which can be used to determine the body's * rotational speed. This information can be used to create realistic physics simulations. */ getAngularVelocityToRef(angVel, instanceIndex) { this._physicsPlugin.getAngularVelocityToRef(this, angVel, instanceIndex); } /** * Gets the angular velocity of the physics body as a new vector3. * @param instanceIndex - If this body is instanced, the index of the instance to get the angular velocity for. * @returns The angular velocity of the physics body. * * This method is useful for getting the angular velocity of a physics body, which can be used to determine the body's * rotational speed. This information can be used to create realistic physics simulations. */ getAngularVelocity(instanceIndex) { const ref = new Vector3(); this.getAngularVelocityToRef(ref, instanceIndex); return ref; } /** * Applies an impulse to the physics object. * * @param impulse The impulse vector. * @param location The location of the impulse. * @param instanceIndex For a instanced body, the instance to where the impulse should be applied. If not specified, the impulse is applied to all instances. * * This method is useful for applying an impulse to a physics object, which can be used to simulate physical forces such as gravity, * collisions, and explosions. This can be used to create realistic physics simulations in a game or other application. */ applyImpulse(impulse, location, instanceIndex) { this._physicsPlugin.applyImpulse(this, impulse, location, instanceIndex); } /** * Add torque to a physics body * @param angularImpulse The angular impulse vector. * @param instanceIndex For a instanced body, the instance to where the impulse should be applied. If not specified, the impulse is applied to all instances. */ applyAngularImpulse(angularImpulse, instanceIndex) { this._physicsPlugin.applyAngularImpulse(this, angularImpulse, instanceIndex); } /** * Applies a force to the physics object. * * @param force The force vector. * @param location The location of the force. * @param instanceIndex For a instanced body, the instance to where the force should be applied. If not specified, the force is applied to all instances. * * This method is useful for applying a force to a physics object, which can be used to simulate physical forces such as gravity, * collisions, and explosions. This can be used to create realistic physics simulations in a game or other application. */ applyForce(force, location, instanceIndex) { this._physicsPlugin.applyForce(this, force, location, instanceIndex); } /** * Retrieves the geometry of the body from the physics plugin. * * @returns The geometry of the body. * * This method is useful for retrieving the geometry of the body from the physics plugin, which can be used for various physics calculations. */ getGeometry() { return this._physicsPlugin.getBodyGeometry(this); } /** * Returns an observable that will be notified for when a collision starts or continues for this PhysicsBody * @returns Observable */ getCollisionObservable() { return this._physicsPlugin.getCollisionObservable(this); } /** * Returns an observable that will be notified when the body has finished colliding with another body * @returns */ getCollisionEndedObservable() { return this._physicsPlugin.getCollisionEndedObservable(this); } /** * Enable or disable collision callback for this PhysicsBody. * @param enabled true if PhysicsBody's collision will rise a collision event and notifies the observable */ setCollisionCallbackEnabled(enabled) { this._collisionCBEnabled = enabled; this._physicsPlugin.setCollisionCallbackEnabled(this, enabled); } /** * Enable or disable collision ended callback for this PhysicsBody. * @param enabled true if PhysicsBody's collision ended will rise a collision event and notifies the observable */ setCollisionEndedCallbackEnabled(enabled) { this._collisionEndedCBEnabled = enabled; this._physicsPlugin.setCollisionEndedCallbackEnabled(this, enabled); } /** * Get the center of the object in world space. * @param instanceIndex - If this body is instanced, the index of the instance to get the center for. * @returns geometric center of the associated mesh */ getObjectCenterWorld(instanceIndex) { const ref = new Vector3(); return this.getObjectCenterWorldToRef(ref, instanceIndex); } /** * Get the center of the object in world space. * @param ref - The vector3 to store the result in. * @param instanceIndex - If this body is instanced, the index of the instance to get the center for. * @returns geometric center of the associated mesh */ getObjectCenterWorldToRef(ref, instanceIndex) { if (this._pluginDataInstances?.length > 0) { const index = instanceIndex || 0; const matrixData = this.transformNode._thinInstanceDataStorage.matrixData; if (matrixData) { ref.set(matrixData[index * 16 + 12], matrixData[index * 16 + 13], matrixData[index * 16 + 14]); } } else { ref.copyFrom(this.transformNode.position); } return ref; } /** * Adds a constraint to the physics engine. * * @param childBody - The body to which the constraint will be applied. * @param constraint - The constraint to be applied. * @param instanceIndex - If this body is instanced, the index of the instance to which the constraint will be applied. If not specified, no constraint will be applied. * @param childInstanceIndex - If the child body is instanced, the index of the instance to which the constraint will be applied. If not specified, no constraint will be applied. * */ addConstraint(childBody, constraint, instanceIndex, childInstanceIndex) { this._physicsPlugin.addConstraint(this, childBody, constraint, instanceIndex, childInstanceIndex); } /** * Sync with a bone * @param bone The bone that the impostor will be synced to. * @param boneMesh The mesh that the bone is influencing. * @param jointPivot The pivot of the joint / bone in local space. * @param distToJoint Optional distance from the impostor to the joint. * @param adjustRotation Optional quaternion for adjusting the local rotation of the bone. * @param boneAxis Optional vector3 axis the bone is aligned with */ syncWithBone(bone, boneMesh, jointPivot, distToJoint, adjustRotation, boneAxis) { const mesh = this.transformNode; if (mesh.rotationQuaternion) { if (adjustRotation) { const tempQuat = TmpVectors.Quaternion[0]; bone.getRotationQuaternionToRef(1 /* Space.WORLD */, boneMesh, tempQuat); tempQuat.multiplyToRef(adjustRotation, mesh.rotationQuaternion); } else { bone.getRotationQuaternionToRef(1 /* Space.WORLD */, boneMesh, mesh.rotationQuaternion); } } const pos = TmpVectors.Vector3[0]; const boneDir = TmpVectors.Vector3[1]; if (!boneAxis) { boneAxis = TmpVectors.Vector3[2]; boneAxis.x = 0; boneAxis.y = 1; boneAxis.z = 0; } bone.getDirectionToRef(boneAxis, boneMesh, boneDir); bone.getAbsolutePositionToRef(boneMesh, pos); if ((distToJoint === undefined || distToJoint === null) && jointPivot) { distToJoint = jointPivot.length(); } if (distToJoint !== undefined && distToJoint !== null) { pos.x += boneDir.x * distToJoint; pos.y += boneDir.y * distToJoint; pos.z += boneDir.z * distToJoint; } mesh.setAbsolutePosition(pos); } /** * Executes a callback on the body or all of the instances of a body * @param callback the callback to execute */ iterateOverAllInstances(callback) { if (this._pluginDataInstances?.length > 0) { for (let i = 0; i < this._pluginDataInstances.length; i++) { callback(this, i); } } else { callback(this, undefined); } } /** * Sets the gravity factor of the physics body * @param factor the gravity factor to set * @param instanceIndex the instance of the body to set, if undefined all instances will be set */ setGravityFactor(factor, instanceIndex) { this._physicsPlugin.setGravityFactor(this, factor, instanceIndex); } /** * Gets the gravity factor of the physics body * @param instanceIndex the instance of the body to get, if undefined the value of first instance will be returned * @returns the gravity factor */ getGravityFactor(instanceIndex) { return this._physicsPlugin.getGravityFactor(this, instanceIndex); } /** * Set the target transformation (position and rotation) of the body, such that the body will set its velocity to reach that target * @param position The target position * @param rotation The target rotation * @param instanceIndex The index of the instance in an instanced body */ setTargetTransform(position, rotation, instanceIndex) { this._physicsPlugin.setTargetTransform(this, position, rotation, instanceIndex); } /** * Returns if the body has been disposed. * @returns true if disposed, false otherwise. */ get isDisposed() { return this._isDisposed; } /** * Disposes the body from the physics engine. * * This method is useful for cleaning up the physics engine when a body is no longer needed. Disposing the body will free up resources and prevent memory leaks. */ dispose() { if (this._isDisposed) { return; } // Disable collisions CB so it doesn't fire when the body is disposed if (this._collisionCBEnabled) { this.setCollisionCallbackEnabled(false); } if (this._collisionEndedCBEnabled) { this.setCollisionEndedCallbackEnabled(false); } if (this._nodeDisposeObserver) { this.transformNode.onDisposeObservable.remove(this._nodeDisposeObserver); this._nodeDisposeObserver = null; } this._physicsEngine.removeBody(this); this._physicsPlugin.removeBody(this); this._physicsPlugin.disposeBody(this); this.transformNode.physicsBody = null; this._pluginData = null; this._pluginDataInstances.length = 0; this._isDisposed = true; this.shape = null; } } //# sourceMappingURL=physicsBody.js.map