refactoring variables and constants, fix update loop to continue over unlaunched satellites

This commit is contained in:
bwent 2015-07-27 14:28:43 -07:00
parent e0d6609a99
commit 5272a1d6e7
3 changed files with 290 additions and 182 deletions

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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;
}
}