UNPKG

@osobh/reactar

Version:

AR Library for React Native and Expo

165 lines 7.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RagdollPhysics = void 0; const three_1 = require("three"); class RagdollPhysics { constructor(physicsManager) { this.bones = new Map(); this.isInitialized = false; this.physicsManager = physicsManager; } /** * Creates a ragdoll from a configuration of bones */ createRagdoll(config) { if (!this.physicsManager) { throw new Error('PhysicsManager must be initialized first'); } // Create rigid bodies for each bone config.forEach(bone => { this.createBone(bone); }); // Create constraints between bones config.forEach(bone => { if (bone.parentBone) { this.createJointConstraint(bone, config.find(b => b.name === bone.parentBone)); } }); this.isInitialized = true; } /** * Creates a single bone rigid body */ createBone(config) { const transform = new Ammo.btTransform(); transform.setIdentity(); transform.setOrigin(new Ammo.btVector3(config.position.x, config.position.y, config.position.z)); transform.setRotation(new Ammo.btQuaternion(config.rotation.x, config.rotation.y, config.rotation.z, config.rotation.w)); const motionState = new Ammo.btDefaultMotionState(transform); const shape = new Ammo.btBoxShape(new Ammo.btVector3(config.dimensions.x * 0.5, config.dimensions.y * 0.5, config.dimensions.z * 0.5)); const localInertia = new Ammo.btVector3(0, 0, 0); shape.calculateLocalInertia(config.mass, localInertia); const rbInfo = new Ammo.btRigidBodyConstructionInfo(config.mass, motionState, shape, localInertia); const body = new Ammo.btRigidBody(rbInfo); // Set additional properties body.setDamping(0.05, 0.85); body.setFriction(0.8); body.setRestitution(0.1); this.bones.set(config.name, { id: config.name, body }); // Add collision group and mask for better performance const collisionGroup = 2; // Ragdoll group const collisionMask = -1; // Collide with everything this.physicsManager['physicsWorld'].addRigidBody(body, collisionGroup, collisionMask); } /** * Creates a constraint between two bones */ createJointConstraint(childBone, parentBone) { const childRagdollBone = this.bones.get(childBone.name); const parentRagdollBone = this.bones.get(parentBone.name); if (!childRagdollBone || !parentRagdollBone) { throw new Error(`Bones not found: ${childBone.name} or ${parentBone.name}`); } let constraint; const parentTransform = new Ammo.btTransform(); const childTransform = new Ammo.btTransform(); parentTransform.setIdentity(); childTransform.setIdentity(); // Add offset handling for joint positions const parentPivot = new Ammo.btVector3(childBone.position.x - parentBone.position.x, childBone.position.y - parentBone.position.y, childBone.position.z - parentBone.position.z); parentTransform.setOrigin(parentPivot); switch (childBone.jointType) { case 'hinge': { const hinge = new Ammo.btHingeConstraint(parentRagdollBone.body, childRagdollBone.body, parentTransform, childTransform, true); if (childBone.jointLimits) { const { minAngle, maxAngle } = childBone.jointLimits; if (minAngle && maxAngle) { hinge.setLimit(minAngle.y, maxAngle.y); } } constraint = hinge; break; } case 'cone': { const cone = new Ammo.btConeTwistConstraint(parentRagdollBone.body, childRagdollBone.body, parentTransform, childTransform); if (childBone.jointLimits) { const { swingSpan1, swingSpan2, twistSpan } = childBone.jointLimits; cone.setLimit(swingSpan1 || 0.5, swingSpan2 || 0.5, twistSpan || 0.5); } constraint = cone; break; } case 'point': { const point = new Ammo.btPoint2PointConstraint(parentRagdollBone.body, childRagdollBone.body, new Ammo.btVector3(0, 0, 0), new Ammo.btVector3(0, 0, 0)); constraint = point; break; } default: throw new Error(`Unsupported joint type: ${childBone.jointType}`); } this.physicsManager['physicsWorld'].addConstraint(constraint, true); childRagdollBone.constraint = constraint; } /** * Applies an impulse force to a specific bone */ applyImpulse(boneName, impulse, worldPoint) { const bone = this.bones.get(boneName); if (!bone) { throw new Error(`Bone ${boneName} not found`); } const btImpulse = new Ammo.btVector3(impulse.x, impulse.y, impulse.z); if (worldPoint) { const btWorldPoint = new Ammo.btVector3(worldPoint.x, worldPoint.y, worldPoint.z); bone.body.applyImpulse(btImpulse, btWorldPoint); } else { bone.body.applyCentralImpulse(btImpulse); } } /** * Gets the current position and rotation of a bone */ getBoneTransform(boneName) { const bone = this.bones.get(boneName); if (!bone) { throw new Error(`Bone ${boneName} not found`); } const transform = new Ammo.btTransform(); bone.body.getMotionState().getWorldTransform(transform); const position = new three_1.Vector3(transform.getOrigin().x(), transform.getOrigin().y(), transform.getOrigin().z()); const rotation = new three_1.Quaternion(transform.getRotation().x(), transform.getRotation().y(), transform.getRotation().z(), transform.getRotation().w()); return { position, rotation }; } /** * Cleans up physics resources for the ragdoll */ setKinematic(boneName, isKinematic) { const bone = this.bones.get(boneName); if (!bone) { throw new Error(`Bone ${boneName} not found`); } if (isKinematic) { bone.body.setCollisionFlags(bone.body.getCollisionFlags() | 2); bone.body.setActivationState(4); // DISABLE_DEACTIVATION } else { bone.body.setCollisionFlags(bone.body.getCollisionFlags() & ~2); bone.body.setActivationState(1); // ACTIVE_TAG } } cleanup() { this.bones.forEach(bone => { if (bone.constraint) { this.physicsManager['physicsWorld'].removeConstraint(bone.constraint); Ammo.destroy(bone.constraint); } this.physicsManager['physicsWorld'].removeRigidBody(bone.body); Ammo.destroy(bone.body); }); this.bones.clear(); this.isInitialized = false; } } exports.RagdollPhysics = RagdollPhysics; //# sourceMappingURL=RagdollPhysics.js.map