181 lines · 5.9 KB · JavaScript
RawDownload
//  gravity.js////  Created by Philip Rosedale on March 29, 2016//  Copyright 2016 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////  This entity script causes the object to move with gravitational force and be attracted to other spheres nearby.//  The force is scaled by GRAVITY_STRENGTH, and only entities of type "Sphere" within GRAVITY_RANGE will affect it.//  The person who has most recently grabbed this object will simulate it.// function Timer() {    var time;    var count = 0;    var totalTime = 0;    this.reset = function() {        count = 0;        totalTime = 0;    }    this.start = function() {        time = new Date().getTime();    }    this.record = function() {        var elapsed =  new Date().getTime() - time;        totalTime += elapsed;        count++;        return elapsed;    }    this.count = function() {        return count;    }    this.average = function() {        return (count == 0) ? 0 : totalTime / count;    }    this.elapsed = function() {        return new Date().getTime() - time;    }} (function () {    var entityID,        wantDebug = true,        CHECK_INTERVAL = 10.00,        SEARCH_INTERVAL = 1000,        GRAVITY_RANGE = 20.0,        GRAVITY_STRENGTH = 1.0,        MIN_VELOCITY = 0.01,        timeoutID = null,        timeSinceLastSearch = 0,        timer = new Timer(),        simulate = false,        spheres = [];     var printDebug = function(message) {        if (wantDebug) {            print(message);        }    }     var greatestDimension = function(dimensions) {        return Math.max(Math.max(dimensions.x, dimensions.y), dimensions.z);    }     var mass2 = function(dimensions) {        return dimensions.x * dimensions.y * dimensions.z;    }     var findSpheres = function(position) {        var entities = Entities.findEntities(position, GRAVITY_RANGE);        spheres = [];        for (var i = 0; i < entities.length; i++) {            if (entityID == spheres[i]) {                // this entity doesn't experience its own gravity.                continue;            }            var props = Entities.getEntityProperties(entities[i]);            if (props && (props.shapeType == "sphere" || props.type == "Sphere")) {                spheres.push(entities[i]);            }        }        // print("FOUND " + spheres.length + " SPHERES");    }     var applyGravity = function() {        if (!simulate) {            return;        }         var properties = Entities.getEntityProperties(entityID);        if (!properties || !properties.position) {            return;        }         // update the list of nearby spheres        var deltaTime = timer.elapsed() / 1000.0;        if (deltaTime == 0.0) {            return;        }        timeSinceLastSearch += CHECK_INTERVAL;        if (timeSinceLastSearch >= SEARCH_INTERVAL) {            findSpheres(properties.position);            timeSinceLastSearch = 0;        }         var deltaVelocity = { x: 0, y: 0, z: 0 };        var otherCount = 0;        var mass = mass2(properties.dimensions);         for (var i = 0; i < spheres.length; i++) {            otherProperties = Entities.getEntityProperties(spheres[i]);            if (!otherProperties || !otherProperties.position) {                continue; // sphere was deleted            }            otherCount++;            var radius = Vec3.distance(properties.position, otherProperties.position);            var otherMass = mass2(otherProperties.dimensions);            var r = (greatestDimension(properties.dimensions) + greatestDimension(otherProperties.dimensions)) / 2;            if (radius > r) {                var n0 = Vec3.normalize(Vec3.subtract(otherProperties.position, properties.position));                var n1 = Vec3.multiply(deltaTime * GRAVITY_STRENGTH * otherMass / (radius * radius), n0);                deltaVelocity = Vec3.sum(deltaVelocity, n1);            }        }        Entities.editEntity(entityID, { velocity: Vec3.sum(properties.velocity, deltaVelocity) });        if (Vec3.length(properties.velocity) < MIN_VELOCITY) {            print("Gravity simulation stopped due to velocity");            simulate = false;        } else {            timer.start();            timeoutID = Script.setTimeout(applyGravity, CHECK_INTERVAL);        }    }    this.applyGravity = applyGravity;     var releaseGrab = function() {        printDebug("Gravity simulation started.");        var properties = Entities.getEntityProperties(entityID);        findSpheres(properties.position);        timer.start();        timeoutID = Script.setTimeout(applyGravity, CHECK_INTERVAL);        simulate = true;    }    this.releaseGrab = releaseGrab;     var preload = function (givenEntityID) {        printDebug("load gravity...");        entityID = givenEntityID;    };    this.preload = preload;     var unload = function () {        printDebug("Unload gravity...");        if (timeoutID !== undefined) {            Script.clearTimeout(timeoutID);        }        if (simulate) {            Entities.editEntity(entityID, { velocity: { x: 0, y: 0, z: 0 } });        }    };    this.unload = unload;     var handleMessages = function(channel, message, sender) {        if (channel === 'Hifi-Object-Manipulation') {            try {                var parsedMessage = JSON.parse(message);                if (parsedMessage.action === 'grab' && parsedMessage.grabbedEntity == entityID) {                    print("Gravity simulation stopped due to grab");                    simulate = false;                }            } catch (e) {                print('error parsing Hifi-Object-Manipulation message: ' + message);            }        }    }    this.handleMessages = handleMessages;     Messages.messageReceived.connect(this.handleMessages);    Messages.subscribe('Hifi-Object-Manipulation');});