overte-JulianGro/scripts/tutorials/NBody/gravity.js
2016-05-09 14:43:24 -07:00

181 lines
5.9 KiB
JavaScript

// 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');
});