mirror of
https://github.com/overte-org/overte.git
synced 2025-04-26 20:36:15 +02:00
181 lines
5.9 KiB
JavaScript
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');
|
|
});
|