@osobh/reactar
Version:
AR Library for React Native and Expo
165 lines • 7.18 kB
JavaScript
;
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