UNPKG

cyclone-physics

Version:

Pure Javascript physics engine based on http://procyclone.com/

192 lines (181 loc) 7.8 kB
elation.require(['physics.common', 'physics.cyclone', 'physics.processors.cpu', 'janusweb.external.physx.physx-cyclone-processor'], function() { // `elation.physics.worker` is the code that runs in a worker when using multithreaded physics // It interfaces with an `elation.physics.processor.worker` processor in the main thread, and keeps // the worker's scene in sync with the main thread's scene. elation.extend("physics.worker", function(parent) { this.fps = 120; this.objects = {}; this.addqueue = []; this.colliderupdates = new Set(); this.handleMessage = function(msg) { if (msg.type == 'system_init') { this.system = new elation.physics.system({autostart: false, processortype: msg.processortype}); this.system.start(msg.args); if (this.addqueue.length > 0) { this.addqueue.forEach(obj => { this.system.add(obj); }); } this.lastframe = performance.now(); /* setInterval(() => { this.advance(); }, 1000 / this.fps); */ this.advance(); } else if (msg.type == 'object_add') { let obj = msg.object; if (!this.objects[obj.id]) { this.addObjectToSystem(obj); console.log('worker added new object', obj.id, obj, this.objects); } } else if (msg.type == 'object_remove') { let object = this.objects[msg.objectid], parent = this.objects[msg.parentid]; //console.log('worker object removed', parent, object, object.parent, msg); if (object && parent) { parent.remove(object); } } else if (msg.type == 'object_changes') { let framedata = {}; for (let i = 0; i < msg.changes.length; i++) { let obj = msg.changes[i]; if (!this.objects[obj.id]) { this.addObjectToSystem(obj); } else { let body = this.objects[obj.id]; //console.log('copy it', obj, body); body.position.copy(obj.position); body.orientation.copy(obj.orientation); body.velocity.copy(obj.velocity); body.angular.copy(obj.angular); body.acceleration.copy(obj.acceleration); body.scale.copy(obj.scale); body.mass = obj.mass; body.restitution = obj.restitution; body.dynamicfriction = obj.dynamicfriction; body.staticfriction = obj.staticfriction; //body.force_accumulator.copy(obj.forces); body.linearDamping = obj.linearDamping; body.angulardamping = obj.angulardamping; body.gravity = obj.gravity; if (body.parent.id != obj.parentid) { //console.log('object parent changed in worker', body.parent.id, obj.parentid, body, obj, this.objects[obj.parentid]); if (this.objects[obj.parentid]) { //body.parent.remove(body); this.objects[obj.parentid].add(body); } } body.updateAcceleration(framedata); } } } else if (msg.type == 'collider_change') { let object = this.objects[msg.objectid]; console.log('worker says a collider changed', msg.objectid, object, msg.collider.type, msg.collider.length, msg.collider.offset, msg.collider.meshdata, msg.collider, this.objects); if (object) { object.setCollider(msg.collider.type, msg.collider); this.colliderupdates.add(object); console.log('add collider update to set', this.colliderupdates); } else { console.log('couldnt find object', msg.objectid, this.objects); } } else if (msg.type == 'force_update') { let object = this.objects[msg.objectid]; if (object && object.forces[msg.forcenum]) { //console.log('update force', object, object.forces[msg.forcenum], msg.force.force); object.forces[msg.forcenum].update(msg.force); object.updateAcceleration({}); /* if (object.forces[msg.forcenum].force && object.forces[msg.forcenum].force.length() > 0) { console.log(object.forces[msg.forcenum].force.toArray()); } */ } } //console.log('[physicsworker] got a message', msg); } onmessage = (ev) => this.handleMessage(ev.data); this.advance = function() { let now = performance.now(), dt = (now - this.lastframe) / 1000; this.lastframe = now; this.system.step(dt); this.sync(); setTimeout(() => this.advance(), 1000 / this.fps); } this.sync = function() { //console.log('sync it back'); postMessage({type: 'object_updates', updates: this.summarizeUpdates()}); } this.summarizeUpdates = function(objects, updates) { if (!objects) objects = this.objects; if (!updates) updates = {}; for (let k in objects) { if (!objects[k].state.sleeping || this.colliderupdates.has(objects[k])) { updates[k] = { position: objects[k].position.toJSON(), orientation: objects[k].orientation.toJSON(), velocity: objects[k].velocity.toJSON(), angular: objects[k].angular.toJSON(), }; //console.log('sync', updates[k].position, updates[k].velocity, objects[k].acceleration); } } this.colliderupdates.clear(); return updates; } this.addObjectToSystem = function(obj) { this.objects[obj.id] = new elation.physics.rigidbody({ id: obj.id, position: new elation.physics.vector3().copy(obj.position), orientation: new elation.physics.quaternion().copy(obj.orientation), velocity: new elation.physics.vector3().copy(obj.velocity), acceleration: new elation.physics.vector3().copy(obj.acceleration), angular: new elation.physics.vector3().copy(obj.angular), scale: new elation.physics.vector3().copy(obj.scale), mass: obj.mass, restitution: obj.restitution, dynamicfriction: obj.dynamicfriction, staticfriction: obj.staticfriction, //forces: object.force_accumulator, linearDamping: obj.linearDamping, angularDamping: obj.angularDamping, gravity: obj.gravity, }); //console.log('new rigidbody', obj.id, obj.collider, obj, this.objects[obj.id], this.objects, msg.changes); if (obj.forces) { //console.log('cool forces bro', obj.forces, this.objects[obj.id]); obj.forces.forEach(f => { this.objects[obj.id].addForce(f.type, f); }); } if (obj.parentid) { if (this.objects[obj.parentid]) { this.objects[obj.parentid].add(this.objects[obj.id]); } else { console.log('Couldn\'t find parent for object', obj.id, obj.parentid, this.objects[obj.id]); } } else { if (this.system) { this.system.add(this.objects[obj.id]); } else { // System not created yet, add to queue this.addqueue.push(this.objects[obj.id]); } } if (obj.collider) { let collider = new elation.physics.colliders[obj.collider.type](this.objects[obj.id], obj.collider); this.objects[obj.id].collider = collider; this.objects[obj.id].collider.getInertialMoment(); this.objects[obj.id].collider.trigger = obj.collider.trigger; let root = (collider.type == 'mesh' ? collider.getRoot() : collider.body); elation.events.add(root, 'physics_collide', (ev) => { let contact = ev.data, body1 = contact.bodies[0], body2 = contact.bodies[1]; postMessage({type: 'contact_begin', thing1: body1.id, thing2: body2.id, point: contact.point, normal: contact.normal, penetration: contact.penetration}); }); } } }); });