mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 07:47:30 +02:00
Merge pull request #10175 from PhilipRosedale/springHold
New Tutorial and entity scripts
This commit is contained in:
commit
f1bd371fbe
7 changed files with 448 additions and 419 deletions
|
@ -1,181 +0,0 @@
|
||||||
// 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');
|
|
||||||
});
|
|
|
@ -1,72 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="64"
|
|
||||||
height="64"
|
|
||||||
viewBox="0 0 64.000001 64.000001"
|
|
||||||
id="svg2"
|
|
||||||
version="1.1"
|
|
||||||
inkscape:version="0.91 r13725"
|
|
||||||
sodipodi:docname="gravity.svg">
|
|
||||||
<defs
|
|
||||||
id="defs4" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="1.4"
|
|
||||||
inkscape:cx="192.07838"
|
|
||||||
inkscape:cy="33.619203"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
units="px"
|
|
||||||
inkscape:window-width="2782"
|
|
||||||
inkscape:window-height="1764"
|
|
||||||
inkscape:window-x="98"
|
|
||||||
inkscape:window-y="36"
|
|
||||||
inkscape:window-maximized="1" />
|
|
||||||
<metadata
|
|
||||||
id="metadata7">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(0,-988.36216)">
|
|
||||||
<ellipse
|
|
||||||
style="fill:#a09898;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
id="path4690"
|
|
||||||
cx="12.142858"
|
|
||||||
cy="1039.1478"
|
|
||||||
rx="8.5714283"
|
|
||||||
ry="8.2142859" />
|
|
||||||
<ellipse
|
|
||||||
style="fill:#3131d9;fill-opacity:1;stroke:#000000;stroke-width:3;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
|
||||||
id="path4692"
|
|
||||||
cx="39.285717"
|
|
||||||
cy="1014.1478"
|
|
||||||
rx="21.358366"
|
|
||||||
ry="21.001223" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.1 KiB |
|
@ -1,166 +0,0 @@
|
||||||
// makePlanets.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
|
|
||||||
//
|
|
||||||
// Make an earth and moon, where you can grab and throw moon into orbit. Entity
|
|
||||||
// script attached to moon gives it gravitation behavior and will also make it attracted to
|
|
||||||
// other spheres placed nearby.
|
|
||||||
//
|
|
||||||
|
|
||||||
var SCALE = 3.0;
|
|
||||||
var EARTH_SIZE = 3.959 / SCALE;
|
|
||||||
var MOON_SIZE = 1.079 / SCALE;
|
|
||||||
|
|
||||||
var BUTTON_SIZE = 32;
|
|
||||||
var PADDING = 3;
|
|
||||||
|
|
||||||
var earth = null;
|
|
||||||
var moon = null;
|
|
||||||
|
|
||||||
var SCRIPT_URL = Script.resolvePath("gravity.js");
|
|
||||||
|
|
||||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
|
||||||
Script.include(["/~/system/libraries/toolBars.js"]);
|
|
||||||
var toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL, "highfidelity.makePlanets.js");
|
|
||||||
|
|
||||||
var makePlanetsIconURL = Script.resolvePath("gravity.svg");
|
|
||||||
var button = toolBar.addOverlay("image", {
|
|
||||||
width: BUTTON_SIZE,
|
|
||||||
height: BUTTON_SIZE,
|
|
||||||
imageURL: makePlanetsIconURL,
|
|
||||||
color: {
|
|
||||||
red: 255,
|
|
||||||
green: 255,
|
|
||||||
blue: 255
|
|
||||||
},
|
|
||||||
alpha: 1
|
|
||||||
});
|
|
||||||
|
|
||||||
var deleteButton = toolBar.addOverlay("image", {
|
|
||||||
width: BUTTON_SIZE,
|
|
||||||
height: BUTTON_SIZE,
|
|
||||||
imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png",
|
|
||||||
color: {
|
|
||||||
red: 255,
|
|
||||||
green: 255,
|
|
||||||
blue: 255
|
|
||||||
},
|
|
||||||
alpha: 1
|
|
||||||
});
|
|
||||||
|
|
||||||
function inFrontOfMe(distance) {
|
|
||||||
return Vec3.sum(Camera.getPosition(), Vec3.multiply(distance, Quat.getForward(Camera.getOrientation())));
|
|
||||||
}
|
|
||||||
|
|
||||||
function onButtonClick() {
|
|
||||||
earth = Entities.addEntity({
|
|
||||||
type: "Model",
|
|
||||||
name: "Earth",
|
|
||||||
modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/seth/production/NBody/earth.fbx",
|
|
||||||
position: inFrontOfMe(2 * EARTH_SIZE),
|
|
||||||
dimensions: { x: EARTH_SIZE, y: EARTH_SIZE, z: EARTH_SIZE },
|
|
||||||
shapeType: "sphere",
|
|
||||||
lifetime: 86400, // 1 day
|
|
||||||
angularDamping: 0,
|
|
||||||
angularVelocity: { x: 0, y: 0.1, z: 0 },
|
|
||||||
});
|
|
||||||
moon = Entities.addEntity({
|
|
||||||
type: "Model",
|
|
||||||
name: "Moon",
|
|
||||||
modelURL: "https://s3-us-west-1.amazonaws.com/hifi-content/seth/production/NBody/moon.fbx",
|
|
||||||
position: inFrontOfMe(EARTH_SIZE - MOON_SIZE),
|
|
||||||
dimensions: { x: MOON_SIZE, y: MOON_SIZE, z: MOON_SIZE },
|
|
||||||
dynamic: true,
|
|
||||||
damping: 0, // 0.01,
|
|
||||||
angularDamping: 0, // 0.01,
|
|
||||||
script: SCRIPT_URL,
|
|
||||||
shapeType: "sphere"
|
|
||||||
});
|
|
||||||
Entities.addEntity({
|
|
||||||
"accelerationSpread": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"alpha": 1,
|
|
||||||
"alphaFinish": 0,
|
|
||||||
"alphaStart": 1,
|
|
||||||
"azimuthFinish": 0,
|
|
||||||
"azimuthStart": 0,
|
|
||||||
"color": {
|
|
||||||
"blue": 255,
|
|
||||||
"green": 255,
|
|
||||||
"red": 255
|
|
||||||
},
|
|
||||||
"colorFinish": {
|
|
||||||
"blue": 255,
|
|
||||||
"green": 255,
|
|
||||||
"red": 255
|
|
||||||
},
|
|
||||||
"colorStart": {
|
|
||||||
"blue": 255,
|
|
||||||
"green": 255,
|
|
||||||
"red": 255
|
|
||||||
},
|
|
||||||
"dimensions": {
|
|
||||||
"x": 0.10890001058578491,
|
|
||||||
"y": 0.10890001058578491,
|
|
||||||
"z": 0.10890001058578491
|
|
||||||
},
|
|
||||||
"emitAcceleration": {
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"emitOrientation": {
|
|
||||||
"w": 0.99999994039535522,
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"emitRate": 300,
|
|
||||||
"emitSpeed": 0,
|
|
||||||
"emitterShouldTrail": 1,
|
|
||||||
"maxParticles": 10000,
|
|
||||||
"name": "moon trail",
|
|
||||||
"parentID": moon,
|
|
||||||
"particleRadius": 0.005,
|
|
||||||
"radiusFinish": 0.005,
|
|
||||||
"radiusSpread": 0.005,
|
|
||||||
"radiusStart": 0.005,
|
|
||||||
"speedSpread": 0,
|
|
||||||
"lifespan": 20,
|
|
||||||
"textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
|
||||||
"type": "ParticleEffect",
|
|
||||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDeleteButton() {
|
|
||||||
Entities.deleteEntity(earth);
|
|
||||||
Entities.deleteEntity(moon);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mousePressEvent(event) {
|
|
||||||
var clickedText = false;
|
|
||||||
var clickedOverlay = Overlays.getOverlayAtPoint({
|
|
||||||
x: event.x,
|
|
||||||
y: event.y
|
|
||||||
});
|
|
||||||
if (clickedOverlay == button) {
|
|
||||||
onButtonClick();
|
|
||||||
} else if (clickedOverlay == deleteButton) {
|
|
||||||
onDeleteButton();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function scriptEnding() {
|
|
||||||
toolBar.cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.mousePressEvent.connect(mousePressEvent);
|
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
|
59
scripts/tutorials/createSwords.js
Normal file
59
scripts/tutorials/createSwords.js
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// createSwords.js
|
||||||
|
//
|
||||||
|
// Created by Philip Rosedale on April 9, 2017
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// Makes two grabbable 'swords' in front of the user, that can be held and used
|
||||||
|
// to hit the other. Demonstration of an action that would allow two people to hold
|
||||||
|
// entities that are also colliding.
|
||||||
|
//
|
||||||
|
|
||||||
|
var COLOR = { red: 255, green: 0, blue: 0 };
|
||||||
|
var SIZE = { x: 0.10, y: 1.5, z: 0.10 };
|
||||||
|
|
||||||
|
var SCRIPT_URL = Script.resolvePath("entity_scripts/springHold.js");
|
||||||
|
|
||||||
|
function inFrontOfMe(distance) {
|
||||||
|
return Vec3.sum(Camera.getPosition(), Vec3.multiply(distance, Quat.getForward(Camera.getOrientation())));
|
||||||
|
}
|
||||||
|
|
||||||
|
var sword1 = Entities.addEntity({
|
||||||
|
type: "Box",
|
||||||
|
name: "Sword1",
|
||||||
|
position: inFrontOfMe(2 * SIZE.y),
|
||||||
|
dimensions: SIZE,
|
||||||
|
color: COLOR,
|
||||||
|
angularDamping: 0,
|
||||||
|
damping: 0,
|
||||||
|
script: SCRIPT_URL,
|
||||||
|
userData:JSON.stringify({
|
||||||
|
grabbableKey:{
|
||||||
|
grabbable:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
var sword2 = Entities.addEntity({
|
||||||
|
type: "Box",
|
||||||
|
name: "Sword2",
|
||||||
|
position: inFrontOfMe(3 * SIZE.y),
|
||||||
|
dimensions: SIZE,
|
||||||
|
color: COLOR,
|
||||||
|
angularDamping: 0,
|
||||||
|
damping: 0,
|
||||||
|
script: SCRIPT_URL,
|
||||||
|
userData:JSON.stringify({
|
||||||
|
grabbableKey:{
|
||||||
|
grabbable:true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function scriptEnding() {
|
||||||
|
Entities.deleteEntity(sword1);
|
||||||
|
Entities.deleteEntity(sword2);
|
||||||
|
});
|
||||||
|
|
116
scripts/tutorials/entity_scripts/springHold.js
Normal file
116
scripts/tutorials/entity_scripts/springHold.js
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
//
|
||||||
|
// springHold.js
|
||||||
|
//
|
||||||
|
// Created by Philip Rosedale on March 18, 2017
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Attach this entity script to a model or basic shape and grab it. The object will
|
||||||
|
// follow your hand like a spring, allowing you, for example, to swordfight with others.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var TIMESCALE = 0.03;
|
||||||
|
var ACTION_TTL = 10;
|
||||||
|
var _this;
|
||||||
|
|
||||||
|
function SpringHold() {
|
||||||
|
_this = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSpringAction(timescale) {
|
||||||
|
|
||||||
|
var targetProps = Entities.getEntityProperties(_this.entityID);
|
||||||
|
var props = {
|
||||||
|
targetPosition: targetProps.position,
|
||||||
|
targetRotation: targetProps.rotation,
|
||||||
|
linearTimeScale: timescale,
|
||||||
|
angularTimeScale: timescale,
|
||||||
|
ttl: ACTION_TTL
|
||||||
|
};
|
||||||
|
Entities.updateAction(_this.copy, _this.actionID, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSpringAction(timescale) {
|
||||||
|
|
||||||
|
var targetProps = Entities.getEntityProperties(_this.entityID);
|
||||||
|
var props = {
|
||||||
|
targetPosition: targetProps.position,
|
||||||
|
targetRotation: targetProps.rotation,
|
||||||
|
linearTimeScale: timescale,
|
||||||
|
angularTimeScale: timescale,
|
||||||
|
ttl: ACTION_TTL
|
||||||
|
};
|
||||||
|
_this.actionID = Entities.addAction("spring", _this.copy, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCopy() {
|
||||||
|
var originalProps = Entities.getEntityProperties(_this.entityID);
|
||||||
|
var props = {
|
||||||
|
type: originalProps.type,
|
||||||
|
color: originalProps.color,
|
||||||
|
modelURL: originalProps.modelURL,
|
||||||
|
dimensions: originalProps.dimensions,
|
||||||
|
dynamic: true,
|
||||||
|
damping: 0.0,
|
||||||
|
angularDamping: 0.0,
|
||||||
|
collidesWith: 'dynamic,static,kinematic',
|
||||||
|
rotation: originalProps.rotation,
|
||||||
|
position: originalProps.position,
|
||||||
|
shapeType: originalProps.shapeType,
|
||||||
|
visible: true,
|
||||||
|
userData:JSON.stringify({
|
||||||
|
grabbableKey:{
|
||||||
|
grabbable:false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
_this.copy = Entities.addEntity(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteCopy() {
|
||||||
|
Entities.deleteEntity(_this.copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeOriginalInvisible() {
|
||||||
|
Entities.editEntity(_this.entityID, {
|
||||||
|
visible: false,
|
||||||
|
collisionless: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeOriginalVisible() {
|
||||||
|
Entities.editEntity(_this.entityID, {
|
||||||
|
visible: true,
|
||||||
|
collisionless: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteSpringAction() {
|
||||||
|
Entities.deleteAction(_this.copy, _this.actionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpringHold.prototype = {
|
||||||
|
preload: function(entityID) {
|
||||||
|
_this.entityID = entityID;
|
||||||
|
},
|
||||||
|
startNearGrab: function(entityID, data) {
|
||||||
|
createCopy();
|
||||||
|
createSpringAction(TIMESCALE);
|
||||||
|
makeOriginalInvisible();
|
||||||
|
},
|
||||||
|
continueNearGrab: function() {
|
||||||
|
updateSpringAction(TIMESCALE);
|
||||||
|
},
|
||||||
|
releaseGrab: function() {
|
||||||
|
deleteSpringAction();
|
||||||
|
deleteCopy();
|
||||||
|
makeOriginalVisible();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return new SpringHold();
|
||||||
|
});
|
206
scripts/tutorials/entity_scripts/touch.js
Normal file
206
scripts/tutorials/entity_scripts/touch.js
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
// touch.js
|
||||||
|
//
|
||||||
|
// Sample file using spring action, haptic vibration, and color change to demonstrate two spheres
|
||||||
|
// That can give a sense of touch to the holders.
|
||||||
|
// Create two standard spheres, make them grabbable, and attach this entity script. Grab them and touch them together.
|
||||||
|
//
|
||||||
|
// Created by Philip Rosedale on March 18, 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
|
||||||
|
//
|
||||||
|
|
||||||
|
var TIMESCALE = 0.03;
|
||||||
|
var ACTION_TTL = 10;
|
||||||
|
var _this;
|
||||||
|
|
||||||
|
var RIGHT_HAND = 1;
|
||||||
|
var LEFT_HAND = 0;
|
||||||
|
var HAPTIC_PULSE_FIRST_STRENGTH = 0.5;
|
||||||
|
var HAPTIC_PULSE_MIN_STRENGTH = 0.20;
|
||||||
|
var HAPTIC_PULSE_MAX_STRENGTH = 0.5;
|
||||||
|
var HAPTIC_PULSE_FIRST_DURATION = 1.0;
|
||||||
|
var HAPTIC_PULSE_DURATION = 16.0;
|
||||||
|
var HAPTIC_PULSE_DISTANCE = 0.0;
|
||||||
|
var MAX_PENETRATION = 0.02;
|
||||||
|
var HAPTIC_MIN_VELOCITY = 0.002;
|
||||||
|
var HAPTIC_MAX_VELOCITY = 0.5;
|
||||||
|
var PENETRATION_PULLBACK_FACTOR = 0.65;
|
||||||
|
var FRAME_TIME = 0.016;
|
||||||
|
|
||||||
|
var isColliding = false;
|
||||||
|
|
||||||
|
var hand = LEFT_HAND;
|
||||||
|
var lastHapticPulseLocation = { x:0, y:0, z:0 };
|
||||||
|
|
||||||
|
|
||||||
|
var GRAY = { red: 128, green: 128, blue: 128 };
|
||||||
|
var RED = { red: 255, green: 0, blue: 0 };
|
||||||
|
|
||||||
|
var targetColor = { x: GRAY.red, y: GRAY.green, z: GRAY.blue };
|
||||||
|
|
||||||
|
var lastPosition = { x: 0, y: 0, z: 0 };
|
||||||
|
var velocity = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
|
var lastOtherPosition = { x: 0, y: 0, z: 0 };
|
||||||
|
var otherVelocity = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
|
|
||||||
|
function TouchExample() {
|
||||||
|
_this = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSpringAction(timescale) {
|
||||||
|
var targetProps = Entities.getEntityProperties(_this.entityID);
|
||||||
|
//
|
||||||
|
// Look for nearby entities to touch
|
||||||
|
//
|
||||||
|
var copyProps = Entities.getEntityProperties(_this.copy);
|
||||||
|
var nearbyEntities = Entities.findEntities(copyProps.position, copyProps.dimensions.x * 2);
|
||||||
|
var wasColliding = isColliding;
|
||||||
|
var targetAdjust = { x: 0, y: 0, z: 0 };
|
||||||
|
|
||||||
|
isColliding = false;
|
||||||
|
for (var i = 0; i < nearbyEntities.length; i++) {
|
||||||
|
if (_this.copy != nearbyEntities[i] && _this.entityID != nearbyEntities[i]) {
|
||||||
|
var otherProps = Entities.getEntityProperties(nearbyEntities[i]);
|
||||||
|
var penetration = Vec3.distance(copyProps.position, otherProps.position) - (copyProps.dimensions.x / 2 + otherProps.dimensions.x / 2);
|
||||||
|
if (otherProps.type === 'Sphere' && penetration < 0 && penetration > -copyProps.dimensions.x * 3) {
|
||||||
|
isColliding = true;
|
||||||
|
targetAdjust = Vec3.sum(targetAdjust, Vec3.multiply(Vec3.normalize(Vec3.subtract(targetProps.position, otherProps.position)), -penetration * PENETRATION_PULLBACK_FACTOR));
|
||||||
|
if (!wasColliding && false) {
|
||||||
|
targetColor = { x: RED.red, y: RED.green, z: RED.blue };
|
||||||
|
} else {
|
||||||
|
targetColor = { x: 200 + Math.min(-penetration / MAX_PENETRATION, 1.0) * 55, y: GRAY.green, z: GRAY.blue };
|
||||||
|
}
|
||||||
|
if (Vec3.distance(targetProps.position, lastHapticPulseLocation) > HAPTIC_PULSE_DISTANCE || !wasColliding) {
|
||||||
|
if (!wasColliding) {
|
||||||
|
velocity = { x: 0, y: 0, z: 0};
|
||||||
|
otherVelocity = { x: 0, y: 0, z: 0 };
|
||||||
|
Controller.triggerHapticPulse(HAPTIC_PULSE_FIRST_STRENGTH, HAPTIC_PULSE_FIRST_DURATION, hand);
|
||||||
|
} else {
|
||||||
|
velocity = Vec3.distance(targetProps.position, lastPosition) / FRAME_TIME;
|
||||||
|
otherVelocity = Vec3.distance(otherProps.position, lastOtherPosition) / FRAME_TIME;
|
||||||
|
var velocityStrength = Math.min(velocity + otherVelocity / HAPTIC_MAX_VELOCITY, 1.0);
|
||||||
|
var strength = HAPTIC_PULSE_MIN_STRENGTH + Math.min(-penetration / MAX_PENETRATION, 1.0) * (HAPTIC_PULSE_MAX_STRENGTH - HAPTIC_PULSE_MIN_STRENGTH);
|
||||||
|
Controller.triggerHapticPulse(velocityStrength * strength, HAPTIC_PULSE_DURATION, hand);
|
||||||
|
}
|
||||||
|
lastPosition = targetProps.position;
|
||||||
|
lastOtherPosition = otherProps.position;
|
||||||
|
lastHapticPulseLocation = targetProps.position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((wasColliding != isColliding) && !isColliding) {
|
||||||
|
targetColor = { x: GRAY.red, y: GRAY.green, z: GRAY.blue };
|
||||||
|
}
|
||||||
|
// Interpolate color toward target color
|
||||||
|
var currentColor = { x: copyProps.color.red, y: copyProps.color.green, z: copyProps.color.blue };
|
||||||
|
var newColor = Vec3.sum(currentColor, Vec3.multiply(Vec3.subtract(targetColor, currentColor), 0.1));
|
||||||
|
Entities.editEntity(_this.copy, { color: { red: newColor.x, green: newColor.y, blue: newColor.z } });
|
||||||
|
|
||||||
|
var props = {
|
||||||
|
targetPosition: Vec3.sum(targetProps.position, targetAdjust),
|
||||||
|
targetRotation: targetProps.rotation,
|
||||||
|
linearTimeScale: timescale,
|
||||||
|
angularTimeScale: timescale,
|
||||||
|
ttl: ACTION_TTL
|
||||||
|
};
|
||||||
|
var success = Entities.updateAction(_this.copy, _this.actionID, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSpringAction(timescale) {
|
||||||
|
|
||||||
|
var targetProps = Entities.getEntityProperties(_this.entityID);
|
||||||
|
var props = {
|
||||||
|
targetPosition: targetProps.position,
|
||||||
|
targetRotation: targetProps.rotation,
|
||||||
|
linearTimeScale: timescale,
|
||||||
|
angularTimeScale: timescale,
|
||||||
|
ttl: ACTION_TTL
|
||||||
|
};
|
||||||
|
_this.actionID = Entities.addAction("spring", _this.copy, props);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCopy() {
|
||||||
|
var originalProps = Entities.getEntityProperties(_this.entityID);
|
||||||
|
var props = {
|
||||||
|
type: originalProps.type,
|
||||||
|
modelURL: originalProps.modelURL,
|
||||||
|
dimensions: originalProps.dimensions,
|
||||||
|
color: GRAY,
|
||||||
|
dynamic: true,
|
||||||
|
damping: 0.0,
|
||||||
|
angularDamping: 0.0,
|
||||||
|
collidesWith: 'static',
|
||||||
|
rotation: originalProps.rotation,
|
||||||
|
position: originalProps.position,
|
||||||
|
shapeType: originalProps.shapeType,
|
||||||
|
visible: true,
|
||||||
|
userData:JSON.stringify({
|
||||||
|
grabbableKey:{
|
||||||
|
grabbable:false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
_this.copy = Entities.addEntity(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteCopy() {
|
||||||
|
print("Delete copy");
|
||||||
|
Entities.deleteEntity(_this.copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeOriginalInvisible() {
|
||||||
|
Entities.editEntity(_this.entityID, {
|
||||||
|
visible: false,
|
||||||
|
collisionless: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeOriginalVisible() {
|
||||||
|
Entities.editEntity(_this.entityID, {
|
||||||
|
visible: true,
|
||||||
|
collisionless: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteSpringAction() {
|
||||||
|
Entities.deleteAction(_this.copy, _this.actionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setHand(position) {
|
||||||
|
if (Vec3.distance(MyAvatar.getLeftPalmPosition(), position) < Vec3.distance(MyAvatar.getRightPalmPosition(), position)) {
|
||||||
|
hand = LEFT_HAND;
|
||||||
|
} else {
|
||||||
|
hand = RIGHT_HAND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TouchExample.prototype = {
|
||||||
|
preload: function(entityID) {
|
||||||
|
_this.entityID = entityID;
|
||||||
|
},
|
||||||
|
startNearGrab: function(entityID, data) {
|
||||||
|
createCopy();
|
||||||
|
createSpringAction(TIMESCALE);
|
||||||
|
makeOriginalInvisible();
|
||||||
|
setHand(Entities.getEntityProperties(_this.entityID).position);
|
||||||
|
},
|
||||||
|
continueNearGrab: function() {
|
||||||
|
updateSpringAction(TIMESCALE);
|
||||||
|
},
|
||||||
|
releaseGrab: function() {
|
||||||
|
deleteSpringAction();
|
||||||
|
deleteCopy();
|
||||||
|
makeOriginalVisible();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return new TouchExample();
|
||||||
|
});
|
67
scripts/tutorials/nBody.js
Normal file
67
scripts/tutorials/nBody.js
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
//
|
||||||
|
// nBody.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Philip Rosedale on March 18, 2017
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Create some spheres that obey gravity, which is great to teach physics.
|
||||||
|
// You can control how many to create by changing the value of 'n' below.
|
||||||
|
// Grab them and watch the others move around.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var bodies = [];
|
||||||
|
var n = 3;
|
||||||
|
var radius = 0.1;
|
||||||
|
var G = 0.25;
|
||||||
|
var EARTH = "https://s3-us-west-1.amazonaws.com/hifi-content/seth/production/NBody/earth.fbx";
|
||||||
|
var MOON = "https://s3-us-west-1.amazonaws.com/hifi-content/seth/production/NBody/moon.fbx";
|
||||||
|
|
||||||
|
var COLOR1 = { red: 51, green: 51, blue: 255 };
|
||||||
|
var COLOR2 = { red: 51, green: 51, blue: 255 };
|
||||||
|
var COLOR3 = { red: 51, green: 51, blue: 255 };
|
||||||
|
|
||||||
|
var inFront = Vec3.sum(Camera.getPosition(), Vec3.multiply(radius * 20, Quat.getFront(Camera.getOrientation())));
|
||||||
|
|
||||||
|
for (var i = 0; i < n; i++) {
|
||||||
|
bodies.push(Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
modelURL: (i == 0) ? EARTH : MOON,
|
||||||
|
shapeType: "sphere",
|
||||||
|
dimensions: { x: radius * 2, y: radius * 2, z: radius * 2},
|
||||||
|
position: Vec3.sum(inFront, { x: 0, y: i * 2 * radius, z: 0 }),
|
||||||
|
gravity: { x: 0, y: 0, z: 0 },
|
||||||
|
damping: 0.0,
|
||||||
|
angularDamping: 0.0,
|
||||||
|
dynamic: true
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.update.connect(function(dt) {
|
||||||
|
var props = [];
|
||||||
|
for (var i = 0; i < n; i++) {
|
||||||
|
props.push(Entities.getEntityProperties(bodies[i]));
|
||||||
|
}
|
||||||
|
for (var i = 0; i < n; i++) {
|
||||||
|
if (props[i].dynamic) {
|
||||||
|
var dv = { x: 0, y: 0, z: 0};
|
||||||
|
for (var j = 0; j < n; j++) {
|
||||||
|
if (i != j) {
|
||||||
|
dv = Vec3.sum(dv, Vec3.multiply(G * dt / Vec3.distance(props[i].position, props[j].position),
|
||||||
|
Vec3.normalize(Vec3.subtract(props[j].position, props[i].position))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Entities.editEntity(bodies[i], { velocity: Vec3.sum(props[i].velocity, dv)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function scriptEnding() {
|
||||||
|
for (var i = 0; i < n; i++) {
|
||||||
|
Entities.deleteEntity(bodies[i]);
|
||||||
|
}
|
||||||
|
});
|
Loading…
Reference in a new issue