From eb48aa10185e8b5323ea2b3e2365fd1b6259e43d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Sun, 19 Jul 2015 12:10:37 -0700 Subject: [PATCH 1/8] Update edit.js to swing up on activate --- examples/libraries/entityCameraTool.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index d27d95c161..a3b817e300 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -141,7 +141,7 @@ CameraManager = function() { // Pick a point INITIAL_ZOOM_DISTANCE in front of the camera to use as a focal point that.zoomDistance = INITIAL_ZOOM_DISTANCE; - that.targetZoomDistance = that.zoomDistance; + that.targetZoomDistance = that.zoomDistance + 3.0; var focalPoint = Vec3.sum(Camera.getPosition(), Vec3.multiply(that.zoomDistance, Quat.getFront(Camera.getOrientation()))); @@ -150,6 +150,7 @@ CameraManager = function() { var xzDist = Math.sqrt(dPos.x * dPos.x + dPos.z * dPos.z); that.targetPitch = -Math.atan2(dPos.y, xzDist) * 180 / Math.PI; + that.targetPitch += (90 - that.targetPitch) / 3.0; // Swing camera "up" to look down at the focal point that.targetYaw = Math.atan2(dPos.x, dPos.z) * 180 / Math.PI; that.pitch = that.targetPitch; that.yaw = that.targetYaw; From 2aa453b6102f0fb092283a5644498fcf7c355aeb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Jul 2015 12:05:45 -0700 Subject: [PATCH 2/8] fix build errors for shared-tests --- tests/shared/src/AngularConstraintTests.cpp | 1 + tests/shared/src/AngularConstraintTests.h | 7 ++----- tests/shared/src/MovingPercentileTests.cpp | 1 + tests/shared/src/MovingPercentileTests.h | 1 - tests/shared/src/TransformTests.cpp | 4 +++- tests/shared/src/TransformTests.h | 2 -- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/shared/src/AngularConstraintTests.cpp b/tests/shared/src/AngularConstraintTests.cpp index 95c5db18c2..4dcf3d7296 100644 --- a/tests/shared/src/AngularConstraintTests.cpp +++ b/tests/shared/src/AngularConstraintTests.cpp @@ -16,6 +16,7 @@ #include #include "AngularConstraintTests.h" +#include "../QTestExtensions.h" // Computes the error value between two quaternions (using glm::dot) float getErrorDifference(const glm::quat& a, const glm::quat& b) { diff --git a/tests/shared/src/AngularConstraintTests.h b/tests/shared/src/AngularConstraintTests.h index df2fe8e9c3..705639b571 100644 --- a/tests/shared/src/AngularConstraintTests.h +++ b/tests/shared/src/AngularConstraintTests.h @@ -12,6 +12,7 @@ #ifndef hifi_AngularConstraintTests_h #define hifi_AngularConstraintTests_h +#include #include class AngularConstraintTests : public QObject { @@ -21,10 +22,6 @@ private slots: void testConeRollerConstraint(); }; -// Use QCOMPARE_WITH_ABS_ERROR and define it for glm::quat -#include -float getErrorDifference (const glm::quat& a, const glm::quat& b); -QTextStream & operator << (QTextStream& stream, const glm::quat& q); -#include "../QTestExtensions.h" +float getErrorDifference(const glm::quat& a, const glm::quat& b); #endif // hifi_AngularConstraintTests_h diff --git a/tests/shared/src/MovingPercentileTests.cpp b/tests/shared/src/MovingPercentileTests.cpp index b9593fca83..fbbc3c7b9e 100644 --- a/tests/shared/src/MovingPercentileTests.cpp +++ b/tests/shared/src/MovingPercentileTests.cpp @@ -16,6 +16,7 @@ #include #include +#include <../QTestExtensions.h> QTEST_MAIN(MovingPercentileTests) diff --git a/tests/shared/src/MovingPercentileTests.h b/tests/shared/src/MovingPercentileTests.h index 4a1d4b33d2..ffc8ddb0f6 100644 --- a/tests/shared/src/MovingPercentileTests.h +++ b/tests/shared/src/MovingPercentileTests.h @@ -13,7 +13,6 @@ #define hifi_MovingPercentileTests_h #include -#include <../QTestExtensions.h> class MovingPercentileTests : public QObject { Q_OBJECT diff --git a/tests/shared/src/TransformTests.cpp b/tests/shared/src/TransformTests.cpp index 93b0583aa6..be22914b9d 100644 --- a/tests/shared/src/TransformTests.cpp +++ b/tests/shared/src/TransformTests.cpp @@ -8,10 +8,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "TransformTests.h" + #include -#include "TransformTests.h" #include "SharedLogging.h" +#include <../QTestExtensions.h> using namespace glm; diff --git a/tests/shared/src/TransformTests.h b/tests/shared/src/TransformTests.h index ab5c8cf144..a4d9b2a6c0 100644 --- a/tests/shared/src/TransformTests.h +++ b/tests/shared/src/TransformTests.h @@ -40,8 +40,6 @@ inline QTextStream& operator<< (QTextStream& stream, const glm::mat4& matrix) { return stream; } -#include <../QTestExtensions.h> - class TransformTests : public QObject { Q_OBJECT private slots: From d03a7d1b701d0459468ac7d4afe908d973957707 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Jul 2015 12:24:17 -0700 Subject: [PATCH 3/8] fix physics-tests build errors --- tests/physics/src/BulletUtilTests.cpp | 7 +- tests/physics/src/BulletUtilTests.h | 3 - tests/physics/src/CollisionInfoTests.cpp | 70 ------------------- tests/physics/src/CollisionInfoTests.h | 29 -------- tests/physics/src/MeshMassPropertiesTests.cpp | 8 ++- tests/physics/src/MeshMassPropertiesTests.h | 6 -- tests/physics/src/ShapeColliderTests.cpp | 14 ++-- tests/physics/src/ShapeColliderTests.h | 7 -- 8 files changed, 18 insertions(+), 126 deletions(-) delete mode 100644 tests/physics/src/CollisionInfoTests.cpp delete mode 100644 tests/physics/src/CollisionInfoTests.h diff --git a/tests/physics/src/BulletUtilTests.cpp b/tests/physics/src/BulletUtilTests.cpp index bbd88f88b7..181d22327e 100644 --- a/tests/physics/src/BulletUtilTests.cpp +++ b/tests/physics/src/BulletUtilTests.cpp @@ -9,13 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "BulletUtilTests.h" + #include -//#include "PhysicsTestUtil.h" #include #include -#include "BulletUtilTests.h" +// Add additional qtest functionality (the include order is important!) +#include "GlmTestUtils.h" +#include "../QTestExtensions.h" // Constants const glm::vec3 origin(0.0f); diff --git a/tests/physics/src/BulletUtilTests.h b/tests/physics/src/BulletUtilTests.h index fd4fe13d09..e8fee1e473 100644 --- a/tests/physics/src/BulletUtilTests.h +++ b/tests/physics/src/BulletUtilTests.h @@ -13,9 +13,6 @@ #define hifi_BulletUtilTests_h #include -// Add additional qtest functionality (the include order is important!) -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" class BulletUtilTests : public QObject { Q_OBJECT diff --git a/tests/physics/src/CollisionInfoTests.cpp b/tests/physics/src/CollisionInfoTests.cpp deleted file mode 100644 index 70e2e14bb0..0000000000 --- a/tests/physics/src/CollisionInfoTests.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// -// CollisionInfoTests.cpp -// tests/physics/src -// -// Created by Andrew Meadows on 2/21/2014. -// Copyright 2014 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 -// - -#include - -#include -#include - -#include -#include -#include - -#include "CollisionInfoTests.h" - - - -QTEST_MAIN(CollisionInfoTests) -/* -static glm::vec3 xAxis(1.0f, 0.0f, 0.0f); -static glm::vec3 xZxis(0.0f, 1.0f, 0.0f); -static glm::vec3 xYxis(0.0f, 0.0f, 1.0f); - -void CollisionInfoTests::rotateThenTranslate() { - CollisionInfo collision; - collision._penetration = xAxis; - collision._contactPoint = xYxis; - collision._addedVelocity = xAxis + xYxis + xZxis; - - glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); - float distance = 3.0f; - glm::vec3 translation = distance * xYxis; - - collision.rotateThenTranslate(rotation, translation); - QCOMPARE(collision._penetration, xYxis); - - glm::vec3 expectedContactPoint = -xAxis + translation; - QCOMPARE(collision._contactPoint, expectedContactPoint); - - glm::vec3 expectedAddedVelocity = xYxis - xAxis + xZxis; - QCOMPARE(collision._addedVelocity, expectedAddedVelocity); -} - -void CollisionInfoTests::translateThenRotate() { - CollisionInfo collision; - collision._penetration = xAxis; - collision._contactPoint = xYxis; - collision._addedVelocity = xAxis + xYxis + xZxis; - - glm::quat rotation = glm::angleAxis( -PI_OVER_TWO, zAxis); - float distance = 3.0f; - glm::vec3 translation = distance * xYxis; - - collision.translateThenRotate(translation, rotation); - QCOMPARE(collision._penetration, -xYxis); - - glm::vec3 expectedContactPoint = (1.0f + distance) * xAxis; - QCOMPARE(collision._contactPoint, expectedContactPoint); - - glm::vec3 expectedAddedVelocity = - xYxis + xAxis + xYxis; - QCOMPARE(collision._addedVelocity, expectedAddedVelocity); -}*/ - diff --git a/tests/physics/src/CollisionInfoTests.h b/tests/physics/src/CollisionInfoTests.h deleted file mode 100644 index d26d39be4b..0000000000 --- a/tests/physics/src/CollisionInfoTests.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// CollisionInfoTests.h -// tests/physics/src -// -// Created by Andrew Meadows on 2/21/2014. -// Copyright 2014 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 -// - -#ifndef hifi_CollisionInfoTests_h -#define hifi_CollisionInfoTests_h - -#include - -// Add additional qtest functionality (the include order is important!) -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" - -class CollisionInfoTests : public QObject { - Q_OBJECT - -private slots: -// void rotateThenTranslate(); -// void translateThenRotate(); -}; - -#endif // hifi_CollisionInfoTests_h diff --git a/tests/physics/src/MeshMassPropertiesTests.cpp b/tests/physics/src/MeshMassPropertiesTests.cpp index 794eee0fcf..e88bcae1b7 100644 --- a/tests/physics/src/MeshMassPropertiesTests.cpp +++ b/tests/physics/src/MeshMassPropertiesTests.cpp @@ -9,11 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "MeshMassPropertiesTests.h" + #include -#include #include -#include "MeshMassPropertiesTests.h" +// Add additional qtest functionality (the include order is important!) +#include "BulletTestUtils.h" +#include "GlmTestUtils.h" +#include "../QTestExtensions.h" const btScalar acceptableRelativeError(1.0e-5f); const btScalar acceptableAbsoluteError(1.0e-4f); diff --git a/tests/physics/src/MeshMassPropertiesTests.h b/tests/physics/src/MeshMassPropertiesTests.h index 35471bdbad..b8af9d9db6 100644 --- a/tests/physics/src/MeshMassPropertiesTests.h +++ b/tests/physics/src/MeshMassPropertiesTests.h @@ -13,12 +13,6 @@ #define hifi_MeshMassPropertiesTests_h #include -#include - -// Add additional qtest functionality (the include order is important!) -#include "BulletTestUtils.h" -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" // Relative error macro (see errorTest in BulletTestUtils.h) #define QCOMPARE_WITH_RELATIVE_ERROR(actual, expected, relativeError) \ diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index cb42f534cb..cb51e18fbd 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -9,12 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "ShapeColliderTests.h" + //#include #include #include #include #include +#include #include #include @@ -25,7 +28,10 @@ #include #include -#include "ShapeColliderTests.h" +// Add additional qtest functionality (the include order is important!) +#include "BulletTestUtils.h" +#include "GlmTestUtils.h" +#include "../QTestExtensions.h" const glm::vec3 origin(0.0f); @@ -1553,8 +1559,6 @@ void ShapeColliderTests::rayHitsCapsule() { intersection._rayDirection = - xAxis; QCOMPARE(capsule.findRayIntersection(intersection), true); float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine -// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - // for edge cases we allow a LOT of error QCOMPARE_WITH_ABS_ERROR(intersection._hitDistance, expectedDistance, startDistance * EDGE_CASE_SLOP_FACTOR * EPSILON); } @@ -1564,8 +1568,6 @@ void ShapeColliderTests::rayHitsCapsule() { intersection._rayDirection = - xAxis; QCOMPARE(capsule.findRayIntersection(intersection), true); float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine -// float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - // for edge cases we allow a LOT of error QCOMPARE_WITH_ABS_ERROR(intersection._hitDistance, expectedDistance, startDistance * EPSILON * EDGE_CASE_SLOP_FACTOR); } @@ -1575,8 +1577,6 @@ void ShapeColliderTests::rayHitsCapsule() { intersection._rayDirection = - xAxis; QCOMPARE(capsule.findRayIntersection(intersection), true); float expectedDistance = startDistance - radius * sqrtf(2.0f * delta); // using small angle approximation of cosine - float relativeError = fabsf(intersection._hitDistance - expectedDistance) / startDistance; - // for edge cases we allow a LOT of error QCOMPARE_WITH_ABS_ERROR(intersection._hitDistance, expectedDistance, startDistance * EPSILON * EDGE_CASE_SLOP_FACTOR); } // TODO: test at steep angles near cylinder/cap junction diff --git a/tests/physics/src/ShapeColliderTests.h b/tests/physics/src/ShapeColliderTests.h index 48d9cbd742..73e2b972a9 100644 --- a/tests/physics/src/ShapeColliderTests.h +++ b/tests/physics/src/ShapeColliderTests.h @@ -13,13 +13,6 @@ #define hifi_ShapeColliderTests_h #include -#include - -// Add additional qtest functionality (the include order is important!) -#include "BulletTestUtils.h" -#include "GlmTestUtils.h" -#include "../QTestExtensions.h" - class ShapeColliderTests : public QObject { Q_OBJECT From ccb3d433afb69e6ce391c7d302092143515a96f1 Mon Sep 17 00:00:00 2001 From: bwent Date: Fri, 24 Jul 2015 09:43:49 -0700 Subject: [PATCH 4/8] Example script solarsystem.js with orbiting satellite game --- examples/example/games/satellite.js | 279 +++++++++++++ examples/example/games/solarsystem.js | 554 ++++++++++++++++++++++++++ examples/utilities/tools/vector.js | 197 +++++++++ 3 files changed, 1030 insertions(+) create mode 100644 examples/example/games/satellite.js create mode 100644 examples/example/games/solarsystem.js create mode 100644 examples/utilities/tools/vector.js diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js new file mode 100644 index 0000000000..d2e4dd2a99 --- /dev/null +++ b/examples/example/games/satellite.js @@ -0,0 +1,279 @@ +// +// satellite.js +// games +// +// Created by Bridget Went 7/1/2015. +// Copyright 2015 High Fidelity, Inc. +// +// A game to bring a satellite model into orbit around an animated earth model . +// - Double click to create a new satellite +// - Click on the satellite, drag a vector arrow to specify initial velocity +// - Release mouse to launch the active satellite +// - Orbital movement is calculated using equations of gravitational physics +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include('../../utilities/tools/vector.js'); + +var URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/"; + +SatelliteGame = function() { + var MAX_RANGE = 50.0; + var Y_AXIS = { + x: 0, + y: 1, + z: 0 + } + var LIFETIME = 6000; + + var v0; + var T = 4.0; + var M = 16000.0; + var m = M * 0.000000333; + var ERROR_THRESH = 20.0; + + // Create the spinning earth model + var EARTH_SIZE = 20.0; + var CLOUDS_OFFSET = 0.5; + var SPIN = 0.1; + var ZONE_DIM = 10.0; + var LIGHT_INTENSITY = 1.2; + + Earth = function(position, size) { + this.earth = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "earth.fbx", + position: position, + dimensions: { + x: size, + y: size, + z: size + }, + rotation: Quat.angleAxis(180, {x: 1, y: 0, z: 0}), + angularVelocity: { x: 0.00, y: 0.5 * SPIN, z: 0.00 }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: 6000, + collisionsWillMove: false, + visible: true + }); + + this.clouds = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "clouds.fbx?", + position: position, + dimensions: { + x: size + CLOUDS_OFFSET, + y: size + CLOUDS_OFFSET, + z: size + CLOUDS_OFFSET + }, + angularVelocity: { x: 0.00, y: SPIN, z: 0.00 }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + visible: true + }); + + this.zone = Entities.addEntity({ + type: "Zone", + position: position, + dimensions: { + x: ZONE_DIM, + y: ZONE_DIM, + z: ZONE_DIM + }, + keyLightDirection: Vec3.normalize(Vec3.subtract(position, Camera.getPosition())), + keyLightIntensity: LIGHT_INTENSITY + }); + + this.cleanup = function() { + Entities.deleteEntity(this.clouds); + Entities.deleteEntity(this.earth); + Entities.deleteEntity(this.zone); + } + } + + // Create earth model + var center = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); + var distance = Vec3.length(Vec3.subtract(center, Camera.getPosition())); + var earth = new Earth(center, EARTH_SIZE); + + var satellites = []; + var SATELLITE_SIZE = 2.0; + var launched = false; + var activeSatellite; + + Satellite = function(position, planetCenter) { + // The Satellite class + + this.launched = false; + this.startPosition = position; + this.readyToLaunch = false; + this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); + + this.satellite = Entities.addEntity({ + type: "Model", + modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", + position: this.startPosition, + dimensions: { + x: SATELLITE_SIZE, + y: SATELLITE_SIZE, + z: SATELLITE_SIZE + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + }); + + this.getProperties = function() { + return Entities.getEntityProperties(this.satellite); + } + + this.launch = function() { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(planetCenter, prop.position); + var radius = Vec3.length(between); + this.G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); + + var v0 = Vec3.normalize(Vec3.cross(between, Y_AXIS)); + v0 = Vec3.multiply(Math.sqrt((this.G * M) / radius), v0); + v0 = Vec3.multiply(this.arrow.magnitude, v0); + v0 = Vec3.multiply(Vec3.length(v0), this.arrow.direction); + + Entities.editEntity(this.satellite, { velocity: v0 }); + this.launched = true; + }; + + + this.update = function(deltaTime) { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(prop.position, planetCenter); + var radius = Vec3.length(between); + var a = -(this.G * M) * Math.pow(radius, (-2.0)); + var speed = a * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); + + var newVelocity = Vec3.sum(prop.velocity, vel); + var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); + + Entities.editEntity(this.satellite, { + velocity: newVelocity, + position: newPos + }); + }; + } + + function mouseDoublePressEvent(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + var point = Vec3.sum(Camera.getPosition(), addVector); + + // Create a new satellite + activeSatellite = new Satellite(point, center); + satellites.push(activeSatellite); + } + + function mousePressEvent(event) { + if (!activeSatellite) { + return; + } + // Reset label + if (activeSatellite.arrow) { + activeSatellite.arrow.deleteLabel(); + } + var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.5, Quat.getFront(Camera.getOrientation()))); + var pickRay = Camera.computePickRay(event.x, event.y) + var rayPickResult = Entities.findRayIntersection(pickRay, true); + if (rayPickResult.entityID === activeSatellite.satellite) { + // Create a draggable vector arrow at satellite position + activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); + activeSatellite.arrow.onMousePressEvent(event); + activeSatellite.arrow.isDragging = true; + } + } + + function mouseMoveEvent(event) { + if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseMoveEvent(event); + } + + function mouseReleaseEvent(event) { + if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseReleaseEvent(event); + activeSatellite.launch(); + activeSatellite.arrow.cleanup(); + } + + var counter = 0.0; + var TIME = 500; + + function update(deltaTime) { + if(!activeSatellite) { + return; + } + // Update all satellites + for (var i = 0; i < satellites.length; i++) { + if (!satellites[i].launched) { + return; + } + satellites[i].update(deltaTime); + } + + counter++; + if (counter % TIME == 0) { + var prop = activeSatellite.getProperties(); + var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); + if (Math.abs(error) <= ERROR_THRESH) { + activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); + } else { + activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); + } + } + } + + this.endGame = function() { + print("ending game"); + for(var i = 0; i < satellites.length; i++) { + Entities.deleteEntitiy(satellites[i].satellite); + satellites[i].arrow.cleanup(); + } + earth.cleanup(); + } + + + function calcEnergyError(pos, vel) { + //Calculate total energy error for active satellite's orbital motion + var radius = activeSatellite.radius; + var G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); + var v0 = Math.sqrt((G * M) / radius); + + var totalEnergy = 0.5 * M * Math.pow(v0, 2.0) - ((G * M * m) / radius); + var measuredEnergy = 0.5 * M * Math.pow(vel, 2.0) - ((G * M * m) / Vec3.length(Vec3.subtract(pos, center))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; + } + + Controller.mousePressEvent.connect(mousePressEvent); + Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); + Controller.mouseMoveEvent.connect(mouseMoveEvent); + Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + Script.update.connect(update); + Script.scriptEnding.connect(this.endGame); + +} + + + diff --git a/examples/example/games/solarsystem.js b/examples/example/games/solarsystem.js new file mode 100644 index 0000000000..b651e551f0 --- /dev/null +++ b/examples/example/games/solarsystem.js @@ -0,0 +1,554 @@ +// +// solarsystem.js +// games +// +// Created by Bridget Went, 5/28/15. +// Copyright 2015 High Fidelity, Inc. +// +// The start to a project to build a virtual physics classroom to simulate the solar system, gravity, and orbital physics. +// A sun with oribiting planets is created in front of the user. UI elements allow for adjusting the period, gravity, trails, and energy recalculations. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include('../../utilities/tools/cookies.js'); +Script.include('satellite.js'); + +var BASE_URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/planets/"; + +var NUM_PLANETS = 8; + +var trailsEnabled = true; +var energyConserved = true; +var planetView = false; +var earthView = false; +var satelliteGame; + +var PANEL_X = 850; +var PANEL_Y = 600; +var BUTTON_SIZE = 20; +var PADDING = 20; + +var DAMPING = 0.0; +var LIFETIME = 6000; +var ERROR_THRESH = 2.0; +var TIME_STEP = 70.0; + +var MAX_POINTS_PER_LINE = 5; +var LINE_DIM = 10; +var LINE_WIDTH = 3.0; +var line; +var planetLines = []; +var trails = []; + +var BOUNDS = 200; + + +// Alert user to move if they are too close to domain bounds +if (MyAvatar.position.x < BOUNDS || MyAvatar.position.x > TREE_SCALE - BOUNDS + || MyAvatar.position.y < BOUNDS || MyAvatar.position.y > TREE_SCALE - BOUNDS + || MyAvatar.position.z < BOUNDS || MyAvatar.position.z > TREE_SCALE - BOUNDS) { + Window.alert("Please move at least 200m away from domain bounds."); + return; +} + +// Save intiial avatar and camera position +var startingPosition = MyAvatar.position; +var startFrame = Window.location.href; + +// Place the sun +var MAX_RANGE = 80.0; +var SUN_SIZE = 8.0; +var center = Vec3.sum(startingPosition, Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); + +var theSun = Entities.addEntity({ + type: "Model", + modelURL: BASE_URL + "sun.fbx", + position: center, + dimensions: { + x: SUN_SIZE, + y: SUN_SIZE, + z: SUN_SIZE + }, + angularDamping: DAMPING, + damping: DAMPING, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false +}); + +var planets = []; +var planet_properties = []; + +// Reference values +var radius = 7.0; +var T_ref = 1.0; +var size = 1.0; +var M = 250.0; +var m = M * 0.000000333; +var G = (Math.pow(radius, 3.0) / Math.pow((T_ref / (2.0 * Math.PI)), 2.0)) / M; +var G_ref = G; + +// Adjust size and distance as number of planets increases +var DELTA_RADIUS = 1.8; +var DELTA_SIZE = 0.2; + +function initPlanets() { + for (var i = 0; i < NUM_PLANETS; ++i) { + var v0 = Math.sqrt((G * M) / radius); + var T = (2.0 * Math.PI) * Math.sqrt(Math.pow(radius, 3.0) / (G * M)); + + if (i == 0) { + var color = {red: 255, green: 255, blue: 255}; + } else if (i == 1) { + var color = {red: 255, green: 160, blue: 110}; + } else if (i == 2) { + var color = {red: 10, green: 150, blue: 160}; + } else if (i == 3) { + var color = {red: 180, green: 70, blue: 10}; + } else if (i == 4) { + var color = {red: 250, green: 140, blue: 0}; + } else if (i == 5) { + var color = {red: 235, green: 215, blue: 0}; + } else if (i == 6) { + var color = {red:135, green: 205, blue: 240}; + } else if (i == 7) { + var color = {red:30, green: 140, blue: 255}; + } + + var prop = { + radius: radius, + position: Vec3.sum(center, {x: radius, y: 0.0, z: 0.0}), + lineColor: color, + period: T, + dimensions: size, + velocity: Vec3.multiply(v0, Vec3.normalize({x: 0, y: -0.2, z: 0.9})) + }; + planet_properties.push(prop); + + planets.push(Entities.addEntity({ + type: "Model", + modelURL: BASE_URL + (i + 1) + ".fbx", + position: prop.position, + dimensions: { + x: prop.dimensions, + y: prop.dimensions, + z: prop.dimensions + }, + velocity: prop.velocity, + angularDamping: DAMPING, + damping: DAMPING, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: true, + })); + + radius *= DELTA_RADIUS; + size += DELTA_SIZE; + } +} + +// Initialize planets +initPlanets(); + + +var labels = []; +var labelLines = []; +var labelsShowing = false; +var LABEL_X = 8.0; +var LABEL_Y = 3.0; +var LABEL_Z = 1.0; +var LABEL_DIST = 8.0; +var TEXT_HEIGHT = 1.0; +var sunLabel; + +function showLabels() { + labelsShowing = true; + for (var i = 0; i < NUM_PLANETS; i++) { + var properties = planet_properties[i]; + var text; + if (i == 0) { + text = "Mercury"; + } else if (i == 1) { + text = "Venus"; + } else if (i == 2) { + text = "Earth"; + } else if (i == 3) { + text = "Mars"; + } else if (i == 4) { + text = "Jupiter"; + } else if (i == 5) { + text = "Saturn"; + } else if (i == 6) { + text = "Uranus"; + } else if (i == 7) { + text = "Neptune"; + } + + text = text + " Speed: " + Vec3.length(properties.velocity).toFixed(2); + + var labelPos = Vec3.sum(planet_properties[i].position, {x: 0.0, y: LABEL_DIST, z: LABEL_DIST}); + var linePos = planet_properties[i].position; + labelLines.push(Entities.addEntity( { + type: "Line", + position: linePos, + dimensions: {x: 20, y: 20, z: 20}, + lineWidth: 3.0, + color: {red: 255, green: 255, blue: 255}, + linePoints: [{x: 0, y: 0, z: 0}, computeLocalPoint(linePos, labelPos)] + })); + + labels.push(Entities.addEntity( { + type: "Text", + text: text, + lineHeight: TEXT_HEIGHT, + dimensions: {x: LABEL_X, y: LABEL_Y, z: LABEL_Z}, + position: labelPos, + backgroundColor: {red: 10, green: 10, blue: 10}, + textColor: {red: 255, green: 255, blue: 255}, + faceCamera: true + })); + } +} + +function hideLabels() { + labelsShowing = false; + Entities.deleteEntity(sunLabel); + + for (var i = 0; i < NUM_PLANETS; ++i) { + Entities.deleteEntity(labelLines[i]); + Entities.deleteEntity(labels[i]); + } + labels = []; + labelLines = []; +} + +var time = 0.0; +var elapsed; +var counter = 0; +var dt = 1.0 / TIME_STEP; + +function update(deltaTime) { + if (paused) { + return; + } + deltaTime = dt; + time++; + + for (var i = 0; i < NUM_PLANETS; ++i) { + var properties = planet_properties[i]; + var between = Vec3.subtract(properties.position, center); + var speed = getAcceleration(properties.radius) * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); + + // Update velocity and position + properties.velocity = Vec3.sum(properties.velocity, vel); + properties.position = Vec3.sum(properties.position, Vec3.multiply(properties.velocity, deltaTime)); + Entities.editEntity(planets[i], { + velocity: properties.velocity, + position: properties.position + }); + + + // Create new or update current trail + if (trailsEnabled) { + var lineStack = planetLines[i]; + var point = properties.position; + var prop = Entities.getEntityProperties(lineStack[lineStack.length - 1]); + var linePos = prop.position; + + trails[i].push(computeLocalPoint(linePos, point)); + + Entities.editEntity(lineStack[lineStack.length - 1], { + linePoints: trails[i] + }); + if (trails[i].length === MAX_POINTS_PER_LINE) { + trails[i] = newLine(lineStack, point, properties.period, properties.lineColor); + } + } + + // Measure total energy every 10 updates, recalibrate velocity if necessary + if (energyConserved) { + if (counter % 10 === 0) { + var error = calcEnergyError(planets[i], properties.radius, properties.v0, properties.velocity, properties.position); + if (Math.abs(error) >= ERROR_THRESH) { + var speed = adjustVelocity(planets[i], properties.position); + properties.velocity = Vec3.multiply(speed, Vec3.normalize(properties.velocity)); + } + } + } + } + + counter++; + if (time % TIME_STEP == 0) { + elapsed++; + } +} + +function computeLocalPoint(linePos, worldPoint) { + var localPoint = Vec3.subtract(worldPoint, linePos); + return localPoint; +} + +function getAcceleration(radius) { + var acc = -(G * M) * Math.pow(radius, (-2.0)); + return acc; +} + +// Create a new trail +function resetTrails(planetIndex) { + elapsed = 0.0; + var properties = planet_properties[planetIndex]; + + var trail = []; + var lineStack = []; + + //add the first line to both the line entity stack and the trail + trails.push(newLine(lineStack, properties.position, properties.period, properties.lineColor)); + planetLines.push(lineStack); +} + +// Create a new line +function newLine(lineStack, point, period, color) { + if (elapsed < period) { + var line = Entities.addEntity({ + position: point, + type: "Line", + color: color, + dimensions: { + x: LINE_DIM, + y: LINE_DIM, + z: LINE_DIM + }, + lifetime: LIFETIME, + lineWidth: LINE_WIDTH + }); + lineStack.push(line); + } else { + // Begin overwriting first lines after one full revolution (one period) + var firstLine = lineStack.shift(); + Entities.editEntity(firstLine, { + position: point, + linePoints: [{x: 0.0, y: 0.0, z: 0.0}] + }); + lineStack.push(firstLine); + + } + var points = []; + points.push(computeLocalPoint(point, point)); + return points; +} + +// Measure energy error, recalculate velocity to return to initial net energy +var totalEnergy; +var measuredEnergy; +var measuredPE; + +function calcEnergyError(planet, radius, v0, v, pos) { + totalEnergy = 0.5 * M * Math.pow(v0, 2.0) - ((G * M * m) / radius); + measuredEnergy = 0.5 * M * Math.pow(v, 2.0) - ((G * M * m) / Vec3.length(Vec3.subtract(center, pos))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; +} +function adjustVelocity(planet, pos) { + var measuredPE = -(G * M * m) / Vec3.length(Vec3.subtract(center, pos)); + return Math.sqrt(2 * (totalEnergy - measuredPE) / M); +} + + +// Allow user to toggle pausing the model, switch to planet view +var pauseButton = Overlays.addOverlay("text", { + backgroundColor: { red: 200, green: 200, blue: 255 }, + text: "Pause", + x: PANEL_X, + y: PANEL_Y - 30, + width: 70, + height: 20, + alpha: 1.0, + backgroundAlpha: 0.5, + visible: true +}); + +var paused = false; + +function mousePressEvent(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + if(clickedOverlay == pauseButton) { + paused = !paused; + for (var i = 0; i < NUM_PLANETS; ++i) { + Entities.editEntity(planets[i], { velocity: {x: 0.0, y: 0.0, z: 0.0} }); + } + if (paused && !labelsShowing) { + Overlays.editOverlay(pauseButton, { text: "Paused", backgroundColor: {red: 255, green: 50, blue: 50} } ); + showLabels(); + } + if (paused == false && labelsShowing) { + Overlays.editOverlay(pauseButton, { text: "Pause", backgroundColor: {red: 200, green: 200, blue: 255}}); + hideLabels(); + } + planetView = false; + } +} + +function keyPressEvent(event) { + // Jump back to solar system view + if (event.text == "TAB" && planetView) { + if (earthView) { + satelliteGame.endGame(); + earthView = false; + } + MyAvatar.position = startingPosition; + } +} + +function mouseDoublePressEvent(event) { + if(earthView) { + return; + } + var pickRay = Camera.computePickRay(event.x, event.y) + var rayPickResult = Entities.findRayIntersection(pickRay, true); + + for (var i = 0; i < NUM_PLANETS; ++i) { + if (rayPickResult.entityID === labels[i]) { + planetView = true; + if (i == 2) { + MyAvatar.position = Vec3.sum(center, {x: 200, y: 200, z: 200}); + Camera.setPosition(Vec3.sum(center, {x: 200, y: 200, z: 200})); + earthView = true; + satelliteGame = new SatelliteGame(); + + } else { + MyAvatar.position = Vec3.sum({x: 0.0, y: 0.0, z: 3.0}, planet_properties[i].position); + Camera.lookAt(planet_properties[i].position); + } + break; + } + } +} + + + + +// Create UI panel +var panel = new Panel(PANEL_X, PANEL_Y); +var panelItems = []; + +var g_multiplier = 1.0; +panelItems.push(panel.newSlider("Adjust Gravitational Force: ", 0.1, 5.0, + function (value) { + g_multiplier = value; + G = G_ref * g_multiplier; + }, + + function () { + return g_multiplier; + }, + function (value) { + return value.toFixed(1) + "x"; + })); + +var period_multiplier = 1.0; +var last_alpha = period_multiplier; +panelItems.push(panel.newSlider("Adjust Orbital Period: ", 0.1, 3.0, + function (value) { + period_multiplier = value; + changePeriod(period_multiplier); + }, + function () { + return period_multiplier; + }, + function (value) { + return (value).toFixed(2) + "x"; + })); + +panelItems.push(panel.newCheckbox("Leave Trails: ", + function (value) { + trailsEnabled = value; + if (trailsEnabled) { + for (var i = 0; i < NUM_PLANETS; ++i) { + resetTrails(i); + } + //if trails are off and we've already created trails, remove existing trails + } else if (planetLines.length != 0) { + for (var i = 0; i < NUM_PLANETS; ++i) { + for (var j = 0; j < planetLines[i].length; ++j) { + Entities.deleteEntity(planetLines[i][j]); + } + planetLines[i] = []; + } + } + }, + function () { + return trailsEnabled; + }, + function (value) { + return value; + })); + +panelItems.push(panel.newCheckbox("Energy Error Calculations: ", + function (value) { + energyConserved = value; + }, + function () { + return energyConserved; + }, + function (value) { + return value; + })); + +// Update global G constant, period, poke velocity to new value +function changePeriod(alpha) { + var ratio = last_alpha / alpha; + G = Math.pow(ratio, 2.0) * G; + for (var i = 0; i < NUM_PLANETS; ++i) { + var properties = planet_properties[i]; + properties.period = ratio * properties.period; + properties.velocity = Vec3.multiply(ratio, properties.velocity); + + } + last_alpha = alpha; +} + + +// Clean up models, UI panels, lines, and button overlays +function scriptEnding() { + + satelliteGame.endGame(); + + Entities.deleteEntity(theSun); + for (var i = 0; i < NUM_PLANETS; ++i) { + Entities.deleteEntity(planets[i]); + } + Menu.removeMenu("Developer > Scene"); + panel.destroy(); + Overlays.deleteOverlay(pauseButton); + + var e = Entities.findEntities(MyAvatar.position, 16000); + for (i = 0; i < e.length; i++) { + var props = Entities.getEntityProperties(e[i]); + if (props.type === "Line" || props.type === "Text") { + Entities.deleteEntity(e[i]); + } + } +}; + + +Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { + return panel.mouseMoveEvent(event); +}); +Controller.mousePressEvent.connect(function panelMousePressEvent(event) { + return panel.mousePressEvent(event); +}); +Controller.mouseDoublePressEvent.connect(function panelMouseDoublePressEvent(event) { + return panel.mouseDoublePressEvent(event); +}); +Controller.mouseReleaseEvent.connect(function (event) { + return panel.mouseReleaseEvent(event); +}); +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); +Controller.keyPressEvent.connect(keyPressEvent); + +Script.scriptEnding.connect(scriptEnding); +Script.update.connect(update); \ No newline at end of file diff --git a/examples/utilities/tools/vector.js b/examples/utilities/tools/vector.js new file mode 100644 index 0000000000..ab2e8cf200 --- /dev/null +++ b/examples/utilities/tools/vector.js @@ -0,0 +1,197 @@ +// +// vector.js +// examples +// +// Created by Bridget Went on 7/1/15. +// Copyright 2015 High Fidelity, Inc. +// +// A template for creating vector arrows using line entities. A VectorArrow object creates a +// draggable vector arrow where the user clicked at a specified distance from the viewer. +// The relative magnitude and direction of the vector may be displayed. +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// + +var LINE_DIMENSIONS = 100; +var LIFETIME = 6000; +var RAD_TO_DEG = 180.0 / Math.PI; + +var LINE_WIDTH = 4; +var ARROW_WIDTH = 6; +var line, linePosition; +var arrow1, arrow2; + +var SCALE = 0.15; +var ANGLE = 150.0; + + +VectorArrow = function(distance, showStats, statsTitle, statsPosition) { + this.magnitude = 0; + this.direction = {x: 0, y: 0, z: 0}; + + this.showStats = showStats; + this.isDragging = false; + + this.newLine = function(position) { + linePosition = position; + var points = []; + + line = Entities.addEntity({ + position: linePosition, + type: "Line", + color: {red: 255, green: 255, blue: 255}, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + lineWidth: LINE_WIDTH, + lifetime: LIFETIME, + linePoints: [] + }); + + arrow1 = Entities.addEntity({ + position: {x: 0, y: 0, z: 0}, + type: "Line", + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + color: {red: 255, green: 255, blue: 255}, + lineWidth: ARROW_WIDTH, + linePoints: [], + }); + + arrow2 = Entities.addEntity({ + position: {x: 0, y: 0, z: 0}, + type: "Line", + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + color: {red: 255, green: 255, blue: 255}, + lineWidth: ARROW_WIDTH, + linePoints: [], + }); + + } + + + this.onMousePressEvent = function(event) { + + this.newLine(computeWorldPoint(event)); + + if (this.showStats) { + this.label = Entities.addEntity({ + type: "Text", + position: statsPosition, + dimensions: { + x: 4.0, + y: 1.5, + z: 0.1 + }, + lineHeight: 0.3, + faceCamera: true + }); + } + + this.isDragging = true; + + } + + + this.onMouseMoveEvent = function(event) { + + if (!this.isDragging) { + return; + } + + var worldPoint = computeWorldPoint(event); + var localPoint = computeLocalPoint(event, linePosition); + points = [{x: 0, y: 0, z: 0}, localPoint]; + Entities.editEntity(line, { linePoints: points }); + + var nextOffset = Vec3.multiply(SCALE, localPoint); + var normOffset = Vec3.normalize(localPoint); + var axis = Vec3.cross(normOffset, Quat.getFront(Camera.getOrientation()) ); + axis = Vec3.cross(axis, normOffset); + var rotate1 = Quat.angleAxis(ANGLE, axis); + var rotate2 = Quat.angleAxis(-ANGLE, axis); + + // Rotate arrow head to follow direction of the line + Entities.editEntity(arrow1, { + visible: true, + position: worldPoint, + linePoints: [{x: 0, y: 0, z: 0}, nextOffset], + rotation: rotate1 + }); + Entities.editEntity(arrow2, { + visible: true, + position: worldPoint, + linePoints: [{x: 0, y: 0, z: 0}, nextOffset], + rotation: rotate2 + }); + + this.magnitude = Vec3.length(localPoint) / 10.0; + this.direction = Vec3.normalize(Vec3.subtract(worldPoint, linePosition)); + + if (this.showStats) { + this.editLabel(statsTitle + " Magnitude " + this.magnitude.toFixed(2) + ", Direction: " + + this.direction.x.toFixed(2) + ", " + this.direction.y.toFixed(2) + ", " + this.direction.z.toFixed(2)); + } + } + + this.onMouseReleaseEvent = function() { + this.isDragging = false; + } + + this.cleanup = function() { + Entities.deleteEntity(line); + Entities.deleteEntity(arrow1); + Entities.deleteEntity(arrow2); + } + + this.deleteLabel = function() { + Entities.deleteEntity(this.label); + } + + this.editLabel = function(str) { + if(!this.showStats) { + return; + } + Entities.editEntity(this.label, { + text: str + }); + } + + function computeWorldPoint(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + return Vec3.sum(Camera.getPosition(), addVector); + } + + function computeLocalPoint(event, linePosition) { + var localPoint = Vec3.subtract(computeWorldPoint(event), linePosition); + return localPoint; + } + + + +} + + + + + + + + + + + + From e0d6609a99b198f84a7a54445b2f9abb6465f047 Mon Sep 17 00:00:00 2001 From: bwent Date: Fri, 24 Jul 2015 10:18:33 -0700 Subject: [PATCH 5/8] resolve file path issue --- examples/example/games/satellite.js | 13 ++++++------- examples/example/{games => }/solarsystem.js | 12 +++++++++--- 2 files changed, 15 insertions(+), 10 deletions(-) rename examples/example/{games => }/solarsystem.js (96%) diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js index d2e4dd2a99..e82285622b 100644 --- a/examples/example/games/satellite.js +++ b/examples/example/games/satellite.js @@ -15,7 +15,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include('../../utilities/tools/vector.js'); +Script.include('../utilities/tools/vector.js'); var URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/"; @@ -38,8 +38,8 @@ SatelliteGame = function() { var EARTH_SIZE = 20.0; var CLOUDS_OFFSET = 0.5; var SPIN = 0.1; - var ZONE_DIM = 10.0; - var LIGHT_INTENSITY = 1.2; + var ZONE_DIM = 100.0; + var LIGHT_INTENSITY = 1.5; Earth = function(position, size) { this.earth = Entities.addEntity({ @@ -65,7 +65,7 @@ SatelliteGame = function() { this.clouds = Entities.addEntity({ type: "Model", shapeType: 'sphere', - modelURL: URL + "clouds.fbx?", + modelURL: URL + "clouds.fbx?i=2", position: position, dimensions: { x: size + CLOUDS_OFFSET, @@ -190,7 +190,7 @@ SatelliteGame = function() { if (activeSatellite.arrow) { activeSatellite.arrow.deleteLabel(); } - var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.5, Quat.getFront(Camera.getOrientation()))); + var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); var pickRay = Camera.computePickRay(event.x, event.y) var rayPickResult = Entities.findRayIntersection(pickRay, true); if (rayPickResult.entityID === activeSatellite.satellite) { @@ -245,9 +245,8 @@ SatelliteGame = function() { } this.endGame = function() { - print("ending game"); for(var i = 0; i < satellites.length; i++) { - Entities.deleteEntitiy(satellites[i].satellite); + Entities.deleteEntity(satellites[i].satellite); satellites[i].arrow.cleanup(); } earth.cleanup(); diff --git a/examples/example/games/solarsystem.js b/examples/example/solarsystem.js similarity index 96% rename from examples/example/games/solarsystem.js rename to examples/example/solarsystem.js index b651e551f0..09ba2eec8d 100644 --- a/examples/example/games/solarsystem.js +++ b/examples/example/solarsystem.js @@ -6,14 +6,20 @@ // Copyright 2015 High Fidelity, Inc. // // The start to a project to build a virtual physics classroom to simulate the solar system, gravity, and orbital physics. -// A sun with oribiting planets is created in front of the user. UI elements allow for adjusting the period, gravity, trails, and energy recalculations. +// - A sun with oribiting planets is created in front of the user +// - UI elements allow for adjusting the period, gravity, trails, and energy recalculations +// - Click "PAUSE" to pause the animation and show planet labels +// - In this mode, double-click a planet label to zoom in on that planet +// -Double-clicking on earth label initiates satellite orbiter game +// -Press "TAB" to toggle back to solar system view +// // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include('../../utilities/tools/cookies.js'); -Script.include('satellite.js'); +Script.include('../utilities/tools/cookies.js'); +Script.include('games/satellite.js'); var BASE_URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/planets/"; From 5272a1d6e74a23b310b765ef51242a9ea81e0cc7 Mon Sep 17 00:00:00 2001 From: bwent Date: Mon, 27 Jul 2015 14:28:43 -0700 Subject: [PATCH 6/8] refactoring variables and constants, fix update loop to continue over unlaunched satellites --- examples/example/games/satellite.js | 212 +++++++++++++------------ examples/example/solarsystem.js | 229 ++++++++++++++++++++-------- examples/utilities/tools/vector.js | 31 ++-- 3 files changed, 290 insertions(+), 182 deletions(-) diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js index e82285622b..3ddce96aa5 100644 --- a/examples/example/games/satellite.js +++ b/examples/example/games/satellite.js @@ -27,11 +27,6 @@ SatelliteGame = function() { z: 0 } var LIFETIME = 6000; - - var v0; - var T = 4.0; - var M = 16000.0; - var m = M * 0.000000333; var ERROR_THRESH = 20.0; // Create the spinning earth model @@ -43,42 +38,54 @@ SatelliteGame = function() { Earth = function(position, size) { this.earth = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "earth.fbx", - position: position, - dimensions: { - x: size, - y: size, - z: size - }, - rotation: Quat.angleAxis(180, {x: 1, y: 0, z: 0}), - angularVelocity: { x: 0.00, y: 0.5 * SPIN, z: 0.00 }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: 6000, - collisionsWillMove: false, - visible: true + type: "Model", + shapeType: 'sphere', + modelURL: URL + "earth.fbx", + position: position, + dimensions: { + x: size, + y: size, + z: size + }, + rotation: Quat.angleAxis(180, { + x: 1, + y: 0, + z: 0 + }), + angularVelocity: { + x: 0.00, + y: 0.5 * SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: 6000, + collisionsWillMove: false, + visible: true }); this.clouds = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "clouds.fbx?i=2", - position: position, - dimensions: { - x: size + CLOUDS_OFFSET, - y: size + CLOUDS_OFFSET, - z: size + CLOUDS_OFFSET - }, - angularVelocity: { x: 0.00, y: SPIN, z: 0.00 }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, - visible: true + type: "Model", + shapeType: 'sphere', + modelURL: URL + "clouds.fbx?i=2", + position: position, + dimensions: { + x: size + CLOUDS_OFFSET, + y: size + CLOUDS_OFFSET, + z: size + CLOUDS_OFFSET + }, + angularVelocity: { + x: 0.00, + y: SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + visible: true }); this.zone = Entities.addEntity({ @@ -93,11 +100,11 @@ SatelliteGame = function() { keyLightIntensity: LIGHT_INTENSITY }); - this.cleanup = function() { - Entities.deleteEntity(this.clouds); + this.cleanup = function() { + Entities.deleteEntity(this.clouds); Entities.deleteEntity(this.earth); Entities.deleteEntity(this.zone); - } + } } // Create earth model @@ -110,6 +117,10 @@ SatelliteGame = function() { var launched = false; var activeSatellite; + var PERIOD = 4.0; + var LARGE_BODY_MASS = 16000.0; + var SMALL_BODY_MASS = LARGE_BODY_MASS * 0.000000333; + Satellite = function(position, planetCenter) { // The Satellite class @@ -118,20 +129,20 @@ SatelliteGame = function() { this.readyToLaunch = false; this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); - this.satellite = Entities.addEntity({ + this.satellite = Entities.addEntity({ type: "Model", - modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", - position: this.startPosition, - dimensions: { - x: SATELLITE_SIZE, - y: SATELLITE_SIZE, - z: SATELLITE_SIZE - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, + modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", + position: this.startPosition, + dimensions: { + x: SATELLITE_SIZE, + y: SATELLITE_SIZE, + z: SATELLITE_SIZE + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, }); this.getProperties = function() { @@ -142,14 +153,16 @@ SatelliteGame = function() { var prop = Entities.getEntityProperties(this.satellite); var between = Vec3.subtract(planetCenter, prop.position); var radius = Vec3.length(between); - this.G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); + this.gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); - var v0 = Vec3.normalize(Vec3.cross(between, Y_AXIS)); - v0 = Vec3.multiply(Math.sqrt((this.G * M) / radius), v0); - v0 = Vec3.multiply(this.arrow.magnitude, v0); - v0 = Vec3.multiply(Vec3.length(v0), this.arrow.direction); + var initialVelocity = Vec3.normalize(Vec3.cross(between, Y_AXIS)); + initialVelocity = Vec3.multiply(Math.sqrt((this.gravity * LARGE_BODY_MASS) / radius), initialVelocity); + initialVelocity = Vec3.multiply(this.arrow.magnitude, initialVelocity); + initialVelocity = Vec3.multiply(Vec3.length(initialVelocity), this.arrow.direction); - Entities.editEntity(this.satellite, { velocity: v0 }); + Entities.editEntity(this.satellite, { + velocity: initialVelocity + }); this.launched = true; }; @@ -158,12 +171,12 @@ SatelliteGame = function() { var prop = Entities.getEntityProperties(this.satellite); var between = Vec3.subtract(prop.position, planetCenter); var radius = Vec3.length(between); - var a = -(this.G * M) * Math.pow(radius, (-2.0)); - var speed = a * deltaTime; - var vel = Vec3.multiply(speed, Vec3.normalize(between)); + var acceleration = -(this.gravity * LARGE_BODY_MASS) * Math.pow(radius, (-2.0)); + var speed = acceleration * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); - var newVelocity = Vec3.sum(prop.velocity, vel); - var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); + var newVelocity = Vec3.sum(prop.velocity, vel); + var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); Entities.editEntity(this.satellite, { velocity: newVelocity, @@ -173,11 +186,11 @@ SatelliteGame = function() { } function mouseDoublePressEvent(event) { - var pickRay = Camera.computePickRay(event.x, event.y); - var addVector = Vec3.multiply(pickRay.direction, distance); - var point = Vec3.sum(Camera.getPosition(), addVector); + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + var point = Vec3.sum(Camera.getPosition(), addVector); - // Create a new satellite + // Create a new satellite activeSatellite = new Satellite(point, center); satellites.push(activeSatellite); } @@ -188,11 +201,11 @@ SatelliteGame = function() { } // Reset label if (activeSatellite.arrow) { - activeSatellite.arrow.deleteLabel(); - } + activeSatellite.arrow.deleteLabel(); + } var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); var pickRay = Camera.computePickRay(event.x, event.y) - var rayPickResult = Entities.findRayIntersection(pickRay, true); + var rayPickResult = Entities.findRayIntersection(pickRay, true); if (rayPickResult.entityID === activeSatellite.satellite) { // Create a draggable vector arrow at satellite position activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); @@ -202,50 +215,50 @@ SatelliteGame = function() { } function mouseMoveEvent(event) { - if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { return; } activeSatellite.arrow.onMouseMoveEvent(event); } function mouseReleaseEvent(event) { - if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { return; } activeSatellite.arrow.onMouseReleaseEvent(event); - activeSatellite.launch(); - activeSatellite.arrow.cleanup(); + activeSatellite.launch(); + activeSatellite.arrow.cleanup(); } var counter = 0.0; - var TIME = 500; + var CHECK_ENERGY_PERIOD = 500; function update(deltaTime) { - if(!activeSatellite) { + if (!activeSatellite) { return; } // Update all satellites for (var i = 0; i < satellites.length; i++) { if (!satellites[i].launched) { - return; + continue; } - satellites[i].update(deltaTime); + satellites[i].update(deltaTime); } - + counter++; - if (counter % TIME == 0) { + if (counter % CHECK_ENERGY_PERIOD == 0) { var prop = activeSatellite.getProperties(); - var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); - if (Math.abs(error) <= ERROR_THRESH) { - activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); - } else { - activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); - } - } + var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); + if (Math.abs(error) <= ERROR_THRESH) { + activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); + } else { + activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); + } + } } this.endGame = function() { - for(var i = 0; i < satellites.length; i++) { + for (var i = 0; i < satellites.length; i++) { Entities.deleteEntity(satellites[i].satellite); satellites[i].arrow.cleanup(); } @@ -256,13 +269,13 @@ SatelliteGame = function() { function calcEnergyError(pos, vel) { //Calculate total energy error for active satellite's orbital motion var radius = activeSatellite.radius; - var G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T); - var v0 = Math.sqrt((G * M) / radius); - - var totalEnergy = 0.5 * M * Math.pow(v0, 2.0) - ((G * M * m) / radius); - var measuredEnergy = 0.5 * M * Math.pow(vel, 2.0) - ((G * M * m) / Vec3.length(Vec3.subtract(pos, center))); - var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; - return error; + var gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); + var initialVelocityCalculated = Math.sqrt((gravity * LARGE_BODY_MASS) / radius); + + var totalEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(initialVelocityCalculated, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / radius); + var measuredEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(vel, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / Vec3.length(Vec3.subtract(pos, center))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; } Controller.mousePressEvent.connect(mousePressEvent); @@ -272,7 +285,4 @@ SatelliteGame = function() { Script.update.connect(update); Script.scriptEnding.connect(this.endGame); -} - - - +} \ No newline at end of file diff --git a/examples/example/solarsystem.js b/examples/example/solarsystem.js index 09ba2eec8d..8d1f0c81e3 100644 --- a/examples/example/solarsystem.js +++ b/examples/example/solarsystem.js @@ -52,9 +52,7 @@ var BOUNDS = 200; // Alert user to move if they are too close to domain bounds -if (MyAvatar.position.x < BOUNDS || MyAvatar.position.x > TREE_SCALE - BOUNDS - || MyAvatar.position.y < BOUNDS || MyAvatar.position.y > TREE_SCALE - BOUNDS - || MyAvatar.position.z < BOUNDS || MyAvatar.position.z > TREE_SCALE - BOUNDS) { +if (MyAvatar.position.x < BOUNDS || MyAvatar.position.x > TREE_SCALE - BOUNDS || MyAvatar.position.y < BOUNDS || MyAvatar.position.y > TREE_SCALE - BOUNDS || MyAvatar.position.z < BOUNDS || MyAvatar.position.z > TREE_SCALE - BOUNDS) { Window.alert("Please move at least 200m away from domain bounds."); return; } @@ -106,30 +104,70 @@ function initPlanets() { var T = (2.0 * Math.PI) * Math.sqrt(Math.pow(radius, 3.0) / (G * M)); if (i == 0) { - var color = {red: 255, green: 255, blue: 255}; + var color = { + red: 255, + green: 255, + blue: 255 + }; } else if (i == 1) { - var color = {red: 255, green: 160, blue: 110}; + var color = { + red: 255, + green: 160, + blue: 110 + }; } else if (i == 2) { - var color = {red: 10, green: 150, blue: 160}; + var color = { + red: 10, + green: 150, + blue: 160 + }; } else if (i == 3) { - var color = {red: 180, green: 70, blue: 10}; + var color = { + red: 180, + green: 70, + blue: 10 + }; } else if (i == 4) { - var color = {red: 250, green: 140, blue: 0}; + var color = { + red: 250, + green: 140, + blue: 0 + }; } else if (i == 5) { - var color = {red: 235, green: 215, blue: 0}; + var color = { + red: 235, + green: 215, + blue: 0 + }; } else if (i == 6) { - var color = {red:135, green: 205, blue: 240}; + var color = { + red: 135, + green: 205, + blue: 240 + }; } else if (i == 7) { - var color = {red:30, green: 140, blue: 255}; + var color = { + red: 30, + green: 140, + blue: 255 + }; } var prop = { radius: radius, - position: Vec3.sum(center, {x: radius, y: 0.0, z: 0.0}), + position: Vec3.sum(center, { + x: radius, + y: 0.0, + z: 0.0 + }), lineColor: color, period: T, dimensions: size, - velocity: Vec3.multiply(v0, Vec3.normalize({x: 0, y: -0.2, z: 0.9})) + velocity: Vec3.multiply(v0, Vec3.normalize({ + x: 0, + y: -0.2, + z: 0.9 + })) }; planet_properties.push(prop); @@ -194,27 +232,55 @@ function showLabels() { text = text + " Speed: " + Vec3.length(properties.velocity).toFixed(2); - var labelPos = Vec3.sum(planet_properties[i].position, {x: 0.0, y: LABEL_DIST, z: LABEL_DIST}); + var labelPos = Vec3.sum(planet_properties[i].position, { + x: 0.0, + y: LABEL_DIST, + z: LABEL_DIST + }); var linePos = planet_properties[i].position; - labelLines.push(Entities.addEntity( { + labelLines.push(Entities.addEntity({ type: "Line", position: linePos, - dimensions: {x: 20, y: 20, z: 20}, + dimensions: { + x: 20, + y: 20, + z: 20 + }, lineWidth: 3.0, - color: {red: 255, green: 255, blue: 255}, - linePoints: [{x: 0, y: 0, z: 0}, computeLocalPoint(linePos, labelPos)] + color: { + red: 255, + green: 255, + blue: 255 + }, + linePoints: [{ + x: 0, + y: 0, + z: 0 + }, computeLocalPoint(linePos, labelPos)] })); - labels.push(Entities.addEntity( { + labels.push(Entities.addEntity({ type: "Text", text: text, lineHeight: TEXT_HEIGHT, - dimensions: {x: LABEL_X, y: LABEL_Y, z: LABEL_Z}, + dimensions: { + x: LABEL_X, + y: LABEL_Y, + z: LABEL_Z + }, position: labelPos, - backgroundColor: {red: 10, green: 10, blue: 10}, - textColor: {red: 255, green: 255, blue: 255}, + backgroundColor: { + red: 10, + green: 10, + blue: 10 + }, + textColor: { + red: 255, + green: 255, + blue: 255 + }, faceCamera: true - })); + })); } } @@ -255,7 +321,7 @@ function update(deltaTime) { velocity: properties.velocity, position: properties.position }); - + // Create new or update current trail if (trailsEnabled) { @@ -285,11 +351,11 @@ function update(deltaTime) { } } } - + counter++; if (time % TIME_STEP == 0) { elapsed++; - } + } } function computeLocalPoint(linePos, worldPoint) { @@ -306,7 +372,7 @@ function getAcceleration(radius) { function resetTrails(planetIndex) { elapsed = 0.0; var properties = planet_properties[planetIndex]; - + var trail = []; var lineStack = []; @@ -333,10 +399,14 @@ function newLine(lineStack, point, period, color) { lineStack.push(line); } else { // Begin overwriting first lines after one full revolution (one period) - var firstLine = lineStack.shift(); + var firstLine = lineStack.shift(); Entities.editEntity(firstLine, { position: point, - linePoints: [{x: 0.0, y: 0.0, z: 0.0}] + linePoints: [{ + x: 0.0, + y: 0.0, + z: 0.0 + }] }); lineStack.push(firstLine); @@ -357,6 +427,7 @@ function calcEnergyError(planet, radius, v0, v, pos) { var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; return error; } + function adjustVelocity(planet, pos) { var measuredPE = -(G * M * m) / Vec3.length(Vec3.subtract(center, pos)); return Math.sqrt(2 * (totalEnergy - measuredPE) / M); @@ -365,7 +436,11 @@ function adjustVelocity(planet, pos) { // Allow user to toggle pausing the model, switch to planet view var pauseButton = Overlays.addOverlay("text", { - backgroundColor: { red: 200, green: 200, blue: 255 }, + backgroundColor: { + red: 200, + green: 200, + blue: 255 + }, text: "Pause", x: PANEL_X, y: PANEL_Y - 30, @@ -379,22 +454,45 @@ var pauseButton = Overlays.addOverlay("text", { var paused = false; function mousePressEvent(event) { - var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - if(clickedOverlay == pauseButton) { + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); + if (clickedOverlay == pauseButton) { paused = !paused; for (var i = 0; i < NUM_PLANETS; ++i) { - Entities.editEntity(planets[i], { velocity: {x: 0.0, y: 0.0, z: 0.0} }); + Entities.editEntity(planets[i], { + velocity: { + x: 0.0, + y: 0.0, + z: 0.0 + } + }); } if (paused && !labelsShowing) { - Overlays.editOverlay(pauseButton, { text: "Paused", backgroundColor: {red: 255, green: 50, blue: 50} } ); + Overlays.editOverlay(pauseButton, { + text: "Paused", + backgroundColor: { + red: 255, + green: 50, + blue: 50 + } + }); showLabels(); } if (paused == false && labelsShowing) { - Overlays.editOverlay(pauseButton, { text: "Pause", backgroundColor: {red: 200, green: 200, blue: 255}}); + Overlays.editOverlay(pauseButton, { + text: "Pause", + backgroundColor: { + red: 200, + green: 200, + blue: 255 + } + }); hideLabels(); } planetView = false; - } + } } function keyPressEvent(event) { @@ -409,7 +507,7 @@ function keyPressEvent(event) { } function mouseDoublePressEvent(event) { - if(earthView) { + if (earthView) { return; } var pickRay = Camera.computePickRay(event.x, event.y) @@ -419,57 +517,68 @@ function mouseDoublePressEvent(event) { if (rayPickResult.entityID === labels[i]) { planetView = true; if (i == 2) { - MyAvatar.position = Vec3.sum(center, {x: 200, y: 200, z: 200}); - Camera.setPosition(Vec3.sum(center, {x: 200, y: 200, z: 200})); + MyAvatar.position = Vec3.sum(center, { + x: 200, + y: 200, + z: 200 + }); + Camera.setPosition(Vec3.sum(center, { + x: 200, + y: 200, + z: 200 + })); earthView = true; satelliteGame = new SatelliteGame(); - + } else { - MyAvatar.position = Vec3.sum({x: 0.0, y: 0.0, z: 3.0}, planet_properties[i].position); + MyAvatar.position = Vec3.sum({ + x: 0.0, + y: 0.0, + z: 3.0 + }, planet_properties[i].position); Camera.lookAt(planet_properties[i].position); } - break; - } - } + break; + } + } } - // Create UI panel var panel = new Panel(PANEL_X, PANEL_Y); var panelItems = []; var g_multiplier = 1.0; panelItems.push(panel.newSlider("Adjust Gravitational Force: ", 0.1, 5.0, - function (value) { + function(value) { g_multiplier = value; G = G_ref * g_multiplier; }, - function () { + function() { return g_multiplier; }, - function (value) { + function(value) { return value.toFixed(1) + "x"; })); var period_multiplier = 1.0; var last_alpha = period_multiplier; panelItems.push(panel.newSlider("Adjust Orbital Period: ", 0.1, 3.0, - function (value) { + function(value) { period_multiplier = value; changePeriod(period_multiplier); }, - function () { + function() { return period_multiplier; }, - function (value) { + function(value) { return (value).toFixed(2) + "x"; })); panelItems.push(panel.newCheckbox("Leave Trails: ", - function (value) { + function(value) { trailsEnabled = value; if (trailsEnabled) { for (var i = 0; i < NUM_PLANETS; ++i) { @@ -485,21 +594,21 @@ panelItems.push(panel.newCheckbox("Leave Trails: ", } } }, - function () { + function() { return trailsEnabled; }, - function (value) { + function(value) { return value; })); panelItems.push(panel.newCheckbox("Energy Error Calculations: ", - function (value) { + function(value) { energyConserved = value; }, - function () { + function() { return energyConserved; }, - function (value) { + function(value) { return value; })); @@ -519,7 +628,7 @@ function changePeriod(alpha) { // Clean up models, UI panels, lines, and button overlays function scriptEnding() { - + satelliteGame.endGame(); Entities.deleteEntity(theSun); @@ -536,7 +645,7 @@ function scriptEnding() { if (props.type === "Line" || props.type === "Text") { Entities.deleteEntity(e[i]); } - } + } }; @@ -549,7 +658,7 @@ Controller.mousePressEvent.connect(function panelMousePressEvent(event) { Controller.mouseDoublePressEvent.connect(function panelMouseDoublePressEvent(event) { return panel.mouseDoublePressEvent(event); }); -Controller.mouseReleaseEvent.connect(function (event) { +Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); Controller.mousePressEvent.connect(mousePressEvent); diff --git a/examples/utilities/tools/vector.js b/examples/utilities/tools/vector.js index ab2e8cf200..0635b6cbc7 100644 --- a/examples/utilities/tools/vector.js +++ b/examples/utilities/tools/vector.js @@ -82,6 +82,13 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { } + var STATS_DIMENSIONS = { + x: 4.0, + y: 1.5, + z: 0.1 + }; + var TEXT_HEIGHT = 0.3; + this.onMousePressEvent = function(event) { this.newLine(computeWorldPoint(event)); @@ -90,12 +97,8 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { this.label = Entities.addEntity({ type: "Text", position: statsPosition, - dimensions: { - x: 4.0, - y: 1.5, - z: 0.1 - }, - lineHeight: 0.3, + dimensions: STATS_DIMENSIONS, + lineHeight: TEXT_HEIGHT, faceCamera: true }); } @@ -137,7 +140,7 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { rotation: rotate2 }); - this.magnitude = Vec3.length(localPoint) / 10.0; + this.magnitude = Vec3.length(localPoint) * 0.1; this.direction = Vec3.normalize(Vec3.subtract(worldPoint, linePosition)); if (this.showStats) { @@ -180,18 +183,4 @@ VectorArrow = function(distance, showStats, statsTitle, statsPosition) { return localPoint; } - - } - - - - - - - - - - - - From 1107742188a8cd878a65c2983f68d458648d0598 Mon Sep 17 00:00:00 2001 From: bwent Date: Tue, 28 Jul 2015 12:39:04 -0700 Subject: [PATCH 7/8] Clean up formatting for satellite.js --- examples/example/games/satellite.js | 468 ++++++++++++++-------------- 1 file changed, 234 insertions(+), 234 deletions(-) diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js index 3ddce96aa5..f362c0c1e4 100644 --- a/examples/example/games/satellite.js +++ b/examples/example/games/satellite.js @@ -3,13 +3,13 @@ // games // // Created by Bridget Went 7/1/2015. -// Copyright 2015 High Fidelity, Inc. +// Copyright 2015 High Fidelity, Inc. // // A game to bring a satellite model into orbit around an animated earth model . -// - Double click to create a new satellite -// - Click on the satellite, drag a vector arrow to specify initial velocity -// - Release mouse to launch the active satellite -// - Orbital movement is calculated using equations of gravitational physics +// - Double click to create a new satellite +// - Click on the satellite, drag a vector arrow to specify initial velocity +// - Release mouse to launch the active satellite +// - Orbital movement is calculated using equations of gravitational physics // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -20,269 +20,269 @@ Script.include('../utilities/tools/vector.js'); var URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/"; SatelliteGame = function() { - var MAX_RANGE = 50.0; - var Y_AXIS = { - x: 0, - y: 1, - z: 0 - } - var LIFETIME = 6000; - var ERROR_THRESH = 20.0; + var MAX_RANGE = 50.0; + var Y_AXIS = { + x: 0, + y: 1, + z: 0 + } + var LIFETIME = 6000; + var ERROR_THRESH = 20.0; - // Create the spinning earth model - var EARTH_SIZE = 20.0; - var CLOUDS_OFFSET = 0.5; - var SPIN = 0.1; - var ZONE_DIM = 100.0; - var LIGHT_INTENSITY = 1.5; + // Create the spinning earth model + var EARTH_SIZE = 20.0; + var CLOUDS_OFFSET = 0.5; + var SPIN = 0.1; + var ZONE_DIM = 100.0; + var LIGHT_INTENSITY = 1.5; - Earth = function(position, size) { - this.earth = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "earth.fbx", - position: position, - dimensions: { - x: size, - y: size, - z: size - }, - rotation: Quat.angleAxis(180, { - x: 1, - y: 0, - z: 0 - }), - angularVelocity: { - x: 0.00, - y: 0.5 * SPIN, - z: 0.00 - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: 6000, - collisionsWillMove: false, - visible: true - }); + Earth = function(position, size) { + this.earth = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "earth.fbx", + position: position, + dimensions: { + x: size, + y: size, + z: size + }, + rotation: Quat.angleAxis(180, { + x: 1, + y: 0, + z: 0 + }), + angularVelocity: { + x: 0.00, + y: 0.5 * SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: 6000, + collisionsWillMove: false, + visible: true + }); - this.clouds = Entities.addEntity({ - type: "Model", - shapeType: 'sphere', - modelURL: URL + "clouds.fbx?i=2", - position: position, - dimensions: { - x: size + CLOUDS_OFFSET, - y: size + CLOUDS_OFFSET, - z: size + CLOUDS_OFFSET - }, - angularVelocity: { - x: 0.00, - y: SPIN, - z: 0.00 - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, - visible: true - }); + this.clouds = Entities.addEntity({ + type: "Model", + shapeType: 'sphere', + modelURL: URL + "clouds.fbx?i=2", + position: position, + dimensions: { + x: size + CLOUDS_OFFSET, + y: size + CLOUDS_OFFSET, + z: size + CLOUDS_OFFSET + }, + angularVelocity: { + x: 0.00, + y: SPIN, + z: 0.00 + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + visible: true + }); - this.zone = Entities.addEntity({ - type: "Zone", - position: position, - dimensions: { - x: ZONE_DIM, - y: ZONE_DIM, - z: ZONE_DIM - }, - keyLightDirection: Vec3.normalize(Vec3.subtract(position, Camera.getPosition())), - keyLightIntensity: LIGHT_INTENSITY - }); + this.zone = Entities.addEntity({ + type: "Zone", + position: position, + dimensions: { + x: ZONE_DIM, + y: ZONE_DIM, + z: ZONE_DIM + }, + keyLightDirection: Vec3.normalize(Vec3.subtract(position, Camera.getPosition())), + keyLightIntensity: LIGHT_INTENSITY + }); - this.cleanup = function() { - Entities.deleteEntity(this.clouds); - Entities.deleteEntity(this.earth); - Entities.deleteEntity(this.zone); - } - } + this.cleanup = function() { + Entities.deleteEntity(this.clouds); + Entities.deleteEntity(this.earth); + Entities.deleteEntity(this.zone); + } + } - // Create earth model - var center = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); - var distance = Vec3.length(Vec3.subtract(center, Camera.getPosition())); - var earth = new Earth(center, EARTH_SIZE); + // Create earth model + var center = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation()))); + var distance = Vec3.length(Vec3.subtract(center, Camera.getPosition())); + var earth = new Earth(center, EARTH_SIZE); - var satellites = []; - var SATELLITE_SIZE = 2.0; - var launched = false; - var activeSatellite; + var satellites = []; + var SATELLITE_SIZE = 2.0; + var launched = false; + var activeSatellite; var PERIOD = 4.0; var LARGE_BODY_MASS = 16000.0; var SMALL_BODY_MASS = LARGE_BODY_MASS * 0.000000333; - Satellite = function(position, planetCenter) { - // The Satellite class + Satellite = function(position, planetCenter) { + // The Satellite class - this.launched = false; - this.startPosition = position; - this.readyToLaunch = false; - this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); + this.launched = false; + this.startPosition = position; + this.readyToLaunch = false; + this.radius = Vec3.length(Vec3.subtract(position, planetCenter)); - this.satellite = Entities.addEntity({ - type: "Model", - modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", - position: this.startPosition, - dimensions: { - x: SATELLITE_SIZE, - y: SATELLITE_SIZE, - z: SATELLITE_SIZE - }, - angularDamping: 0.0, - damping: 0.0, - ignoreCollisions: false, - lifetime: LIFETIME, - collisionsWillMove: false, - }); + this.satellite = Entities.addEntity({ + type: "Model", + modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx", + position: this.startPosition, + dimensions: { + x: SATELLITE_SIZE, + y: SATELLITE_SIZE, + z: SATELLITE_SIZE + }, + angularDamping: 0.0, + damping: 0.0, + ignoreCollisions: false, + lifetime: LIFETIME, + collisionsWillMove: false, + }); - this.getProperties = function() { - return Entities.getEntityProperties(this.satellite); - } + this.getProperties = function() { + return Entities.getEntityProperties(this.satellite); + } - this.launch = function() { - var prop = Entities.getEntityProperties(this.satellite); - var between = Vec3.subtract(planetCenter, prop.position); - var radius = Vec3.length(between); - this.gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); + this.launch = function() { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(planetCenter, prop.position); + var radius = Vec3.length(between); + this.gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); - var initialVelocity = Vec3.normalize(Vec3.cross(between, Y_AXIS)); - initialVelocity = Vec3.multiply(Math.sqrt((this.gravity * LARGE_BODY_MASS) / radius), initialVelocity); - initialVelocity = Vec3.multiply(this.arrow.magnitude, initialVelocity); - initialVelocity = Vec3.multiply(Vec3.length(initialVelocity), this.arrow.direction); + var initialVelocity = Vec3.normalize(Vec3.cross(between, Y_AXIS)); + initialVelocity = Vec3.multiply(Math.sqrt((this.gravity * LARGE_BODY_MASS) / radius), initialVelocity); + initialVelocity = Vec3.multiply(this.arrow.magnitude, initialVelocity); + initialVelocity = Vec3.multiply(Vec3.length(initialVelocity), this.arrow.direction); - Entities.editEntity(this.satellite, { - velocity: initialVelocity - }); - this.launched = true; - }; + Entities.editEntity(this.satellite, { + velocity: initialVelocity + }); + this.launched = true; + }; - this.update = function(deltaTime) { - var prop = Entities.getEntityProperties(this.satellite); - var between = Vec3.subtract(prop.position, planetCenter); - var radius = Vec3.length(between); - var acceleration = -(this.gravity * LARGE_BODY_MASS) * Math.pow(radius, (-2.0)); - var speed = acceleration * deltaTime; - var vel = Vec3.multiply(speed, Vec3.normalize(between)); + this.update = function(deltaTime) { + var prop = Entities.getEntityProperties(this.satellite); + var between = Vec3.subtract(prop.position, planetCenter); + var radius = Vec3.length(between); + var acceleration = -(this.gravity * LARGE_BODY_MASS) * Math.pow(radius, (-2.0)); + var speed = acceleration * deltaTime; + var vel = Vec3.multiply(speed, Vec3.normalize(between)); - var newVelocity = Vec3.sum(prop.velocity, vel); - var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); + var newVelocity = Vec3.sum(prop.velocity, vel); + var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime)); - Entities.editEntity(this.satellite, { - velocity: newVelocity, - position: newPos - }); - }; - } + Entities.editEntity(this.satellite, { + velocity: newVelocity, + position: newPos + }); + }; + } - function mouseDoublePressEvent(event) { - var pickRay = Camera.computePickRay(event.x, event.y); - var addVector = Vec3.multiply(pickRay.direction, distance); - var point = Vec3.sum(Camera.getPosition(), addVector); + function mouseDoublePressEvent(event) { + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(pickRay.direction, distance); + var point = Vec3.sum(Camera.getPosition(), addVector); - // Create a new satellite - activeSatellite = new Satellite(point, center); - satellites.push(activeSatellite); - } + // Create a new satellite + activeSatellite = new Satellite(point, center); + satellites.push(activeSatellite); + } - function mousePressEvent(event) { - if (!activeSatellite) { - return; - } - // Reset label - if (activeSatellite.arrow) { - activeSatellite.arrow.deleteLabel(); - } - var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); - var pickRay = Camera.computePickRay(event.x, event.y) - var rayPickResult = Entities.findRayIntersection(pickRay, true); - if (rayPickResult.entityID === activeSatellite.satellite) { - // Create a draggable vector arrow at satellite position - activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); - activeSatellite.arrow.onMousePressEvent(event); - activeSatellite.arrow.isDragging = true; - } - } + function mousePressEvent(event) { + if (!activeSatellite) { + return; + } + // Reset label + if (activeSatellite.arrow) { + activeSatellite.arrow.deleteLabel(); + } + var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.4, Quat.getFront(Camera.getOrientation()))); + var pickRay = Camera.computePickRay(event.x, event.y) + var rayPickResult = Entities.findRayIntersection(pickRay, true); + if (rayPickResult.entityID === activeSatellite.satellite) { + // Create a draggable vector arrow at satellite position + activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition); + activeSatellite.arrow.onMousePressEvent(event); + activeSatellite.arrow.isDragging = true; + } + } - function mouseMoveEvent(event) { - if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { - return; - } - activeSatellite.arrow.onMouseMoveEvent(event); - } + function mouseMoveEvent(event) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseMoveEvent(event); + } - function mouseReleaseEvent(event) { - if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { - return; - } - activeSatellite.arrow.onMouseReleaseEvent(event); - activeSatellite.launch(); - activeSatellite.arrow.cleanup(); - } + function mouseReleaseEvent(event) { + if (!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) { + return; + } + activeSatellite.arrow.onMouseReleaseEvent(event); + activeSatellite.launch(); + activeSatellite.arrow.cleanup(); + } - var counter = 0.0; - var CHECK_ENERGY_PERIOD = 500; + var counter = 0.0; + var CHECK_ENERGY_PERIOD = 500; - function update(deltaTime) { - if (!activeSatellite) { - return; - } - // Update all satellites - for (var i = 0; i < satellites.length; i++) { - if (!satellites[i].launched) { - continue; - } - satellites[i].update(deltaTime); - } + function update(deltaTime) { + if (!activeSatellite) { + return; + } + // Update all satellites + for (var i = 0; i < satellites.length; i++) { + if (!satellites[i].launched) { + continue; + } + satellites[i].update(deltaTime); + } - counter++; - if (counter % CHECK_ENERGY_PERIOD == 0) { - var prop = activeSatellite.getProperties(); - var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); - if (Math.abs(error) <= ERROR_THRESH) { - activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); - } else { - activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); - } - } - } + counter++; + if (counter % CHECK_ENERGY_PERIOD == 0) { + var prop = activeSatellite.getProperties(); + var error = calcEnergyError(prop.position, Vec3.length(prop.velocity)); + if (Math.abs(error) <= ERROR_THRESH) { + activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit."); + } else { + activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit."); + } + } + } - this.endGame = function() { - for (var i = 0; i < satellites.length; i++) { - Entities.deleteEntity(satellites[i].satellite); - satellites[i].arrow.cleanup(); - } - earth.cleanup(); - } + this.endGame = function() { + for (var i = 0; i < satellites.length; i++) { + Entities.deleteEntity(satellites[i].satellite); + satellites[i].arrow.cleanup(); + } + earth.cleanup(); + } - function calcEnergyError(pos, vel) { - //Calculate total energy error for active satellite's orbital motion - var radius = activeSatellite.radius; - var gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); - var initialVelocityCalculated = Math.sqrt((gravity * LARGE_BODY_MASS) / radius); + function calcEnergyError(pos, vel) { + //Calculate total energy error for active satellite's orbital motion + var radius = activeSatellite.radius; + var gravity = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (LARGE_BODY_MASS * PERIOD * PERIOD); + var initialVelocityCalculated = Math.sqrt((gravity * LARGE_BODY_MASS) / radius); - var totalEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(initialVelocityCalculated, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / radius); - var measuredEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(vel, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / Vec3.length(Vec3.subtract(pos, center))); - var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; - return error; - } + var totalEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(initialVelocityCalculated, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / radius); + var measuredEnergy = 0.5 * LARGE_BODY_MASS * Math.pow(vel, 2.0) - ((gravity * LARGE_BODY_MASS * SMALL_BODY_MASS) / Vec3.length(Vec3.subtract(pos, center))); + var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100; + return error; + } - Controller.mousePressEvent.connect(mousePressEvent); - Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); - Controller.mouseMoveEvent.connect(mouseMoveEvent); - Controller.mouseReleaseEvent.connect(mouseReleaseEvent); - Script.update.connect(update); - Script.scriptEnding.connect(this.endGame); + Controller.mousePressEvent.connect(mousePressEvent); + Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent); + Controller.mouseMoveEvent.connect(mouseMoveEvent); + Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + Script.update.connect(update); + Script.scriptEnding.connect(this.endGame); } \ No newline at end of file From 044ea2ace56303e1a5101dc282db4c1459f561ce Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 28 Jul 2015 19:31:43 -0700 Subject: [PATCH 8/8] Changed mirror position to not be achored to the head. But instead it's anchored to the "default" eye position, which is where the eyes are in the model, before IK or animations occur. --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3f185af5a1..967880ca8d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3381,7 +3381,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi // This was removed in commit 71e59cfa88c6563749594e25494102fe01db38e9 but could be further // investigated in order to adapt the technique while fixing the head rendering issue, // but the complexity of the hack suggests that a better approach - _mirrorCamera.setPosition(_myAvatar->getHead()->getEyePosition() + + _mirrorCamera.setPosition(_myAvatar->getDefaultEyePosition() + _myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale()); } _mirrorCamera.setProjection(glm::perspective(glm::radians(fov), aspect, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP));