UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

418 lines (417 loc) 9.83 kB
import { Quat } from "../../../core/math/quat.js"; import { Vec3 } from "../../../core/math/vec3.js"; import { Component } from "../component.js"; import { BODYTYPE_STATIC, BODYGROUP_DYNAMIC, BODYGROUP_KINEMATIC, BODYGROUP_STATIC, BODYMASK_ALL, BODYMASK_NOT_STATIC, BODYTYPE_DYNAMIC, BODYTYPE_KINEMATIC } from "./constants.js"; const _quat1 = new Quat(); const _quat2 = new Quat(); const _vec3 = new Vec3(); const _position = new Vec3(); const _rotation = new Quat(); const _vecA = new Vec3(); const _vecB = new Vec3(); class RigidBodyComponent extends Component { static EVENT_CONTACT = "contact"; static EVENT_COLLISIONSTART = "collisionstart"; static EVENT_COLLISIONEND = "collisionend"; static EVENT_TRIGGERENTER = "triggerenter"; static EVENT_TRIGGERLEAVE = "triggerleave"; static order = -1; _angularDamping = 0; _angularFactor = new Vec3(1, 1, 1); _angularVelocity = new Vec3(); _body = null; _friction = 0.5; _group = BODYGROUP_STATIC; _linearDamping = 0; _linearFactor = new Vec3(1, 1, 1); _linearVelocity = new Vec3(); _mask = BODYMASK_NOT_STATIC; _mass = 1; _restitution = 0; _rollingFriction = 0; _simulationEnabled = false; _type = BODYTYPE_STATIC; set angularDamping(damping) { if (this._angularDamping !== damping) { this._angularDamping = damping; if (this._body) { this._body.setDamping(this._linearDamping, damping); } } } get angularDamping() { return this._angularDamping; } set angularFactor(factor) { if (!this._angularFactor.equals(factor)) { this._angularFactor.copy(factor); if (this._body && this._type === BODYTYPE_DYNAMIC) { this._body.setAngularFactor(factor); } } } get angularFactor() { return this._angularFactor; } set angularVelocity(velocity) { if (this._body && this._type === BODYTYPE_DYNAMIC) { this._body.activate(); this._body.setAngularVelocity(velocity); this._angularVelocity.copy(velocity); } } get angularVelocity() { if (this._body && this._type === BODYTYPE_DYNAMIC) { this._body.getAngularVelocity(this._angularVelocity); } return this._angularVelocity; } set body(body) { if (this._body !== body) { this._body = body; if (body && this._simulationEnabled) { body.activate(); } } } get body() { return this._body ? this._body.nativeBody : null; } set friction(friction) { if (this._friction !== friction) { this._friction = friction; if (this._body) { this._body.setFriction(friction); } } } get friction() { return this._friction; } set group(group) { if (this._group !== group) { this._group = group; if (this.enabled && this.entity.enabled) { this.disableSimulation(); this.enableSimulation(); } } } get group() { return this._group; } set linearDamping(damping) { if (this._linearDamping !== damping) { this._linearDamping = damping; if (this._body) { this._body.setDamping(damping, this._angularDamping); } } } get linearDamping() { return this._linearDamping; } set linearFactor(factor) { if (!this._linearFactor.equals(factor)) { this._linearFactor.copy(factor); if (this._body && this._type === BODYTYPE_DYNAMIC) { this._body.setLinearFactor(factor); } } } get linearFactor() { return this._linearFactor; } set linearVelocity(velocity) { if (this._body && this._type === BODYTYPE_DYNAMIC) { this._body.activate(); this._body.setLinearVelocity(velocity); this._linearVelocity.copy(velocity); } } get linearVelocity() { if (this._body && this._type === BODYTYPE_DYNAMIC) { this._body.getLinearVelocity(this._linearVelocity); } return this._linearVelocity; } set mask(mask) { if (this._mask !== mask) { this._mask = mask; if (this.enabled && this.entity.enabled) { this.disableSimulation(); this.enableSimulation(); } } } get mask() { return this._mask; } set mass(mass) { if (this._mass !== mass) { this._mass = mass; if (this._body && this._type === BODYTYPE_DYNAMIC) { const enabled = this.enabled && this.entity.enabled; if (enabled) { this.disableSimulation(); } this._body.setMass(mass); if (enabled) { this.enableSimulation(); } } } } get mass() { return this._mass; } set restitution(restitution) { if (this._restitution !== restitution) { this._restitution = restitution; if (this._body) { this._body.setRestitution(restitution); } } } get restitution() { return this._restitution; } set rollingFriction(friction) { if (this._rollingFriction !== friction) { this._rollingFriction = friction; if (this._body) { this._body.setRollingFriction(friction); } } } get rollingFriction() { return this._rollingFriction; } set type(type) { if (this._type !== type) { this._type = type; this.disableSimulation(); switch (type) { case BODYTYPE_DYNAMIC: this._group = BODYGROUP_DYNAMIC; this._mask = BODYMASK_ALL; break; case BODYTYPE_KINEMATIC: this._group = BODYGROUP_KINEMATIC; this._mask = BODYMASK_ALL; break; case BODYTYPE_STATIC: default: this._group = BODYGROUP_STATIC; this._mask = BODYMASK_NOT_STATIC; break; } this.createBody(); } } get type() { return this._type; } createBody() { const entity = this.entity; let shape; if (entity.collision) { shape = entity.collision.shape; if (entity.trigger) { entity.trigger.destroy(); delete entity.trigger; } } const world = this.system.physicsWorld; if (shape && world) { if (this._body) { world.removeBody(this._body); world.destroyBody(this._body); this._body = null; } const mass = this._type === BODYTYPE_DYNAMIC ? this._mass : 0; this._getEntityTransform(_position, _rotation); const body = world.createBody({ type: this._type, mass, shape, position: _position, rotation: _rotation, entity }); body.setRestitution(this._restitution); body.setFriction(this._friction); body.setRollingFriction(this._rollingFriction); body.setDamping(this._linearDamping, this._angularDamping); if (this._type === BODYTYPE_DYNAMIC) { body.setLinearFactor(this._linearFactor); body.setAngularFactor(this._angularFactor); } this.body = body; if (this.enabled && entity.enabled) { this.enableSimulation(); } } } isActive() { return this._body ? this._body.isActive() : false; } activate() { if (this._body) { this._body.activate(); } } enableSimulation() { this.system.enableSimulation(this); } disableSimulation() { this.system.disableSimulation(this); } applyForce(x, y, z, px, py, pz) { const body = this._body; if (body) { body.activate(); if (x instanceof Vec3) { _vecA.copy(x); } else { _vecA.set(x, y, z); } if (y instanceof Vec3) { _vecB.copy(y); } else if (px !== void 0) { _vecB.set(px, py, pz); } else { _vecB.set(0, 0, 0); } body.applyForce(_vecA, _vecB); } } applyTorque(x, y, z) { const body = this._body; if (body) { body.activate(); if (x instanceof Vec3) { _vecA.copy(x); } else { _vecA.set(x, y, z); } body.applyTorque(_vecA); } } applyImpulse(x, y, z, px, py, pz) { const body = this._body; if (body) { body.activate(); if (x instanceof Vec3) { _vecA.copy(x); } else { _vecA.set(x, y, z); } if (y instanceof Vec3) { _vecB.copy(y); } else if (px !== void 0) { _vecB.set(px, py, pz); } else { _vecB.set(0, 0, 0); } body.applyImpulse(_vecA, _vecB); } } applyTorqueImpulse(x, y, z) { const body = this._body; if (body) { body.activate(); if (x instanceof Vec3) { _vecA.copy(x); } else { _vecA.set(x, y, z); } body.applyTorqueImpulse(_vecA); } } isStatic() { return this._type === BODYTYPE_STATIC; } isStaticOrKinematic() { return this._type === BODYTYPE_STATIC || this._type === BODYTYPE_KINEMATIC; } isKinematic() { return this._type === BODYTYPE_KINEMATIC; } _getEntityTransform(position, rotation) { const entity = this.entity; const component = entity.collision; if (component) { position.copy(component.getShapePosition()); rotation.copy(component.getShapeRotation()); } else { position.copy(entity.getPosition()); rotation.copy(entity.getRotation()); } } syncEntityToBody() { const body = this._body; if (body) { this._getEntityTransform(_position, _rotation); body.setTransform(_position, _rotation); } } _updateDynamic() { const body = this._body; if (body.isActive()) { const entity = this.entity; body.getTransform(_position, _rotation); const component = entity.collision; if (component && component._hasOffset) { const lo = component.linearOffset; const ao = component.angularOffset; const invertedAo = _quat2.copy(ao).invert(); const entityRot = _quat1.copy(_rotation).mul(invertedAo); entityRot.transformVector(lo, _vec3); entity.setPositionAndRotation(_position.sub(_vec3), entityRot); } else { entity.setPositionAndRotation(_position, _rotation); } } } _updateKinematic() { this._getEntityTransform(_position, _rotation); this._body.setKinematicTarget(_position, _rotation); } teleport(x, y, z, rx, ry, rz) { if (x instanceof Vec3) { this.entity.setPosition(x); } else { this.entity.setPosition(x, y, z); } if (y instanceof Quat) { this.entity.setRotation(y); } else if (y instanceof Vec3) { this.entity.setEulerAngles(y); } else if (rx !== void 0) { this.entity.setEulerAngles(rx, ry, rz); } this.syncEntityToBody(); } onEnable() { if (!this._body) { this.createBody(); } this.enableSimulation(); } onDisable() { this.disableSimulation(); } } export { RigidBodyComponent };