UNPKG

@rpgjs/physic

Version:

A deterministic 2D top-down physics library for RPG, sandbox and MMO games

153 lines (152 loc) 4.24 kB
class SpringConstraint { /** * Creates a new spring constraint * * @param entityA - First entity * @param entityB - Second entity * @param restLength - Rest length of the spring * @param springConstant - Spring constant (stiffness) * @param damping - Damping coefficient */ constructor(entityA, entityB, restLength, springConstant, damping) { this.entityA = entityA; this.entityB = entityB; this.restLength = restLength; this.springConstant = springConstant; this.damping = damping; } /** * @inheritdoc */ update(_deltaTime) { const direction = this.entityB.position.sub(this.entityA.position); const distance = direction.length(); if (distance < 1e-3) { return; } const displacement = distance - this.restLength; const springForce = this.springConstant * displacement; direction.normalizeInPlace(); const force = direction.mul(springForce); this.entityA.applyForce(force.mul(-1)); this.entityB.applyForce(force); if (this.damping > 0) { const relativeVelocity = this.entityB.velocity.sub(this.entityA.velocity); const dampingForce = direction.mul(-this.damping * relativeVelocity.dot(direction)); this.entityA.applyForce(dampingForce.mul(-1)); this.entityB.applyForce(dampingForce); } } /** * Gets the current length of the spring * * @returns Current length */ getCurrentLength() { return this.entityA.position.distanceTo(this.entityB.position); } } class DistanceConstraint { /** * Creates a new distance constraint * * @param entityA - First entity * @param entityB - Second entity * @param targetDistance - Target distance to maintain * @param stiffness - Constraint stiffness (0-1, higher = stiffer) */ constructor(entityA, entityB, targetDistance, stiffness = 0.9) { this.entityA = entityA; this.entityB = entityB; this.targetDistance = targetDistance; this.stiffness = stiffness; } /** * @inheritdoc */ update(_deltaTime) { const direction = this.entityB.position.sub(this.entityA.position); const distance = direction.length(); if (distance < 1e-3) { return; } const error = distance - this.targetDistance; if (Math.abs(error) < 1e-3) { return; } direction.normalizeInPlace(); const totalInvMass = this.entityA.invMass + this.entityB.invMass; if (totalInvMass === 0) { return; } const correction = error * this.stiffness / totalInvMass; const correctionA = direction.mul(-correction * this.entityA.invMass); const correctionB = direction.mul(correction * this.entityB.invMass); if (!this.entityA.isStatic()) { this.entityA.position.addInPlace(correctionA); } if (!this.entityB.isStatic()) { this.entityB.position.addInPlace(correctionB); } } /** * Gets the current distance * * @returns Current distance */ getCurrentDistance() { return this.entityA.position.distanceTo(this.entityB.position); } } class AnchorConstraint { /** * Creates a new anchor constraint * * @param entity - Entity to anchor * @param anchorPoint - Anchor point in world space * @param stiffness - Constraint stiffness (0-1) */ constructor(entity, anchorPoint, stiffness = 0.9) { this.entity = entity; this.anchorPoint = anchorPoint.clone(); this.stiffness = stiffness; } /** * @inheritdoc */ update(_deltaTime) { if (this.entity.isStatic()) { return; } const direction = this.anchorPoint.sub(this.entity.position); const distance = direction.length(); if (distance < 1e-3) { return; } direction.normalizeInPlace(); const correction = direction.mul(distance * this.stiffness); this.entity.position.addInPlace(correction); } /** * Sets the anchor point * * @param point - New anchor point */ setAnchorPoint(point) { this.anchorPoint.copyFrom(point); } /** * Gets the anchor point * * @returns Anchor point */ getAnchorPoint() { return this.anchorPoint.clone(); } } export { AnchorConstraint, DistanceConstraint, SpringConstraint }; //# sourceMappingURL=index10.js.map