127 lines · 5.6 KB · JavaScript
RawDownload
////  magneticBlock.js////  Created by Matti Lahtinen 4/3/2017//  Copyright 2017 High Fidelity, Inc.//////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html////  Makes the entity the script is bound to connect to nearby, similarly sized entities, like a magnet. (function() {    var SNAPSOUND_SOURCE = SoundCache.getSound(Script.resolvePath("../../system/assets/sounds/entitySnap.wav?xrs"));    var RANGE_MULTIPLER = 1.5;    var MAX_SCALE = 2;    var MIN_SCALE = 0.5;     // Helper for detecting nearby objects near entityProperties, with the scale calculated by the dimensions of the object.    function findEntitiesInRange(entityProperties) {        var dimensions = entityProperties.dimensions;        // Average of the dimensions instead of full value.        return Entities.findEntities(entityProperties.position,            ((dimensions.x + dimensions.y + dimensions.z) / 3) * RANGE_MULTIPLER);    }     function getNearestValidEntityProperties(releasedProperties) {        var entities = findEntitiesInRange(releasedProperties);        var nearestEntity = null;        var nearest = Number.MAX_VALUE - 1;        var releaseSize = Vec3.length(releasedProperties.dimensions);        entities.forEach(function(entityId) {            if (entityId !== releasedProperties.id) {                var entity = Entities.getEntityProperties(entityId, ['position', 'rotation', 'dimensions']);                var distance = Vec3.distance(releasedProperties.position, entity.position);                var scale = releaseSize / Vec3.length(entity.dimensions);                 if (distance < nearest && (scale >= MIN_SCALE && scale <= MAX_SCALE)) {                    nearestEntity = entity;                    nearest = distance;                }            }        });        return nearestEntity;    }    // Create the 'class'    function MagneticBlock() {}    // Bind pre-emptive events    MagneticBlock.prototype = {        /*          When script is bound to an entity, preload is the first callback called with the entityID.          It will behave as the constructor        */        preload: function(id) {            // Apply the new properties to entity of id            Entities.editEntity(id, { grab: { grabbable: true } });            Script.scriptEnding.connect(function() {                Script.removeEventHandler(id, "releaseGrab", this.releaseGrab);            });        },        releaseGrab: function(entityId) {            // Release grab is called with entityId,            var released = Entities.getEntityProperties(entityId, ["position", "rotation", "dimensions"]);            var target = getNearestValidEntityProperties(released);            if (target !== null) {                // We found nearest, now lets do the snap calculations                // Plays the snap sound between the two objects.                Audio.playSound(SNAPSOUND_SOURCE, {                    volume: 1,                    position: Vec3.mix(target.position, released.position, 0.5)                });                // Check Nearest Axis                var difference = Vec3.subtract(released.position, target.position);                var relativeDifference = Vec3.multiplyQbyV(Quat.inverse(target.rotation), difference);                 var abs = {                    x: Math.abs(relativeDifference.x),                    y: Math.abs(relativeDifference.y),                    z: Math.abs(relativeDifference.z)                };                // Check what value is greater. and lock down to that axis.                var newRelative = {                    x: 0,                    y: 0,                    z: 0                };                if (abs.x >= abs.y && abs.x >= abs.z) {                    newRelative.x = target.dimensions.x / 2 + released.dimensions.x / 2;                    if (relativeDifference.x < 0) {                        newRelative.x = -newRelative.x;                    }                } else if (abs.y >= abs.x && abs.y >= abs.z) {                    newRelative.y = target.dimensions.y / 2 + released.dimensions.y / 2;                    if (relativeDifference.y < 0) {                        newRelative.y = -newRelative.y;                    }                } else if (abs.z >= abs.x && abs.z >= abs.y) {                    newRelative.z = target.dimensions.z / 2 + released.dimensions.z / 2;                    if (relativeDifference.z < 0) {                        newRelative.z = -newRelative.z;                    }                }                // Can be expanded upon to work in nearest 90 degree rotation as well, but was not in spec.                var newPosition = Vec3.multiplyQbyV(target.rotation, newRelative);                Entities.editEntity(entityId, {                    // Script relies on the registrationPoint being at the very center of the object. Thus override.                    registrationPoint: {                        x: 0.5,                        y: 0.5,                        z: 0.5                    },                    rotation: target.rotation,                    position: Vec3.sum(target.position, newPosition)                });                // Script relies on the registrationPoint being at the very center of the object. Thus override.                Entities.editEntity(target.id, {                    registrationPoint: {                        x: 0.5,                        y: 0.5,                        z: 0.5                    }                });            }        }    };    return new MagneticBlock();});