diff --git a/unpublishedScripts/DomainContent/Home/tiltMaze/createTiltMaze.js b/unpublishedScripts/DomainContent/Home/tiltMaze/createTiltMaze.js new file mode 100644 index 0000000000..7779bb7a07 --- /dev/null +++ b/unpublishedScripts/DomainContent/Home/tiltMaze/createTiltMaze.js @@ -0,0 +1,272 @@ +// +// createTiltMaze.js +// +// Created by James B. Pollack @imgntn on 2/15/2016 +// Copyright 2016 High Fidelity, Inc. +// +// This script creates a maze with a ball that you can tilt to try to get to the end. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var ball, ballSpawningAnchor, ballDetector, tiltMaze, lightAtTheEnd; + +var MAZE_MODEL_URL = "http://hifi-content.s3.amazonaws.com/DomainContent/Home/tiltMaze/newmaze_tex-4.fbx"; +var MAZE_COLLISION_HULL = "http://hifi-content.s3.amazonaws.com/DomainContent/Home/tiltMaze/newmaze_tex-3.obj"; +var MAZE_SCRIPT = Script.resolvePath('maze.js?' + Math.random()); + +var SCALE = 0.5; + +var MAZE_DIMENSIONS = Vec3.multiply(SCALE, { + x: 1, + y: 0.15, + z: 1 +}); + +var BALL_DIMENSIONS = Vec3.multiply(SCALE, { + x: 0.035, + y: 0.035, + z: 0.035 +}); + +var BALL_SPAWNER_DIMENSIONS = Vec3.multiply(SCALE, { + x: 0.05, + y: 0.05, + z: 0.05 +}); + +var BALL_DETECTOR_DIMENSIONS = Vec3.multiply(SCALE, { + x: 0.1, + y: 0.1, + z: 0.1 +}); + +var BALL_COLOR = { + red: 255, + green: 0, + blue: 0 +}; + +var DEBUG_COLOR = { + red: 0, + green: 255, + blue: 0 +}; + +var center = Vec3.sum(Vec3.sum(MyAvatar.position, { + x: 0, + y: 0.5, + z: 0 +}), Vec3.multiply(1.5, Quat.getFront(Camera.getOrientation()))); + +var CLEANUP = true; + +var BALL_FORWARD_OFFSET = -0.2 * SCALE; +var BALL_RIGHT_OFFSET = -0.4 * SCALE; +var BALL_VERTICAL_OFFSET = 0.02 * SCALE; + +var BALL_FRICTION = 0.7; +var BALL_RESTITUTION = 0.1; +var BALL_DAMPING = 0.6; +var BALL_ANGULAR_DAMPING = 0.2; +var BALL_DENSITY = 1000; +var BALL_GRAVITY = { + x: 0, + y: -9.8, + z: 0 +}; + +var MAZE_DENSITY = 1000; +var MAZE_RESTITUTION = 0.1; +var MAZE_DAMPING = 0.6; +var MAZE_ANGULAR_DAMPING = 0.6; + +var DETECTOR_VERTICAL_OFFSET = 0.0 * SCALE; +var DETECTOR_FORWARD_OFFSET = 0.35 * SCALE; +var DETECTOR_RIGHT_OFFSET = 0.35 * SCALE; + +var END_LIGHT_COLOR = { + red: 255, + green: 0, + blue: 0 +}; + +var END_LIGHT_DIMENSIONS = { + x: 0.2, + y: 0.2, + z: 0.8 +}; + +var END_LIGHT_INTENSITY = 0.035; +var END_LIGHT_CUTOFF = 30; +var END_LIGHT_EXPONENT = 1; + +var getBallStartLocation = function() { + var mazeProps = Entities.getEntityProperties(tiltMaze); + var right = Quat.getRight(mazeProps.rotation); + var front = Quat.getFront(mazeProps.rotation); + var vertical = { + x: 0, + y: BALL_VERTICAL_OFFSET, + z: 0 + }; + + var finalOffset = Vec3.sum(vertical, Vec3.multiply(right, BALL_RIGHT_OFFSET)); + finalOffset = Vec3.sum(finalOffset, Vec3.multiply(front, BALL_FORWARD_OFFSET)); + var location = Vec3.sum(mazeProps.position, finalOffset); + return location; +}; + +var getBallFinishLocation = function() { + var mazeProps = Entities.getEntityProperties(tiltMaze); + var right = Quat.getRight(mazeProps.rotation); + var forward = Quat.getFront(mazeProps.rotation); + var up = Quat.getUp(mazeProps.rotation); + + var position = Vec3.sum(mazeProps.position, Vec3.multiply(up, DETECTOR_VERTICAL_OFFSET)); + position = Vec3.sum(position, Vec3.multiply(right, DETECTOR_RIGHT_OFFSET)); + position = Vec3.sum(position, Vec3.multiply(forward, DETECTOR_FORWARD_OFFSET)); + + return position; +}; + + +var createBall = function(position) { + var properties = { + name: 'Hifi Tilt Maze Ball', + type: 'Sphere', + position: getBallStartLocation(), + dynamic: true, + collisionless: false, + friction: BALL_FRICTION, + restitution: BALL_RESTITUTION, + angularDamping: BALL_ANGULAR_DAMPING, + damping: BALL_DAMPING, + gravity: BALL_GRAVITY, + density: BALL_DENSITY, + color: BALL_COLOR, + dimensions: BALL_DIMENSIONS, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + + }; + + ball = Entities.addEntity(properties); + +}; + +var createBallSpawningAnchor = function() { + var properties = { + name: 'Hifi Tilt Maze Ball Detector', + parentID: tiltMaze, + type: 'Box', + color: DEBUG_COLOR, + dimensions: BALL_SPAWNER_DIMENSIONS, + position: getBallStartLocation(), + collisionless: true, + visible: false, + }; + + ballSpawningAnchor = Entities.addEntity(properties); +}; + + +var createBallDetector = function() { + + var properties = { + name: 'Hifi Tilt Maze Ball Detector', + parentID: tiltMaze, + type: 'Box', + color: DEBUG_COLOR, + shapeType: 'none', + dimensions: BALL_DETECTOR_DIMENSIONS, + position: getBallFinishLocation(), + collisionless: true, + dynamic: false, + visible: false, + }; + + ballDetector = Entities.addEntity(properties); + +}; + +var createTiltMaze = function(position) { + var properties = { + name: 'Hifi Tilt Maze', + type: 'Model', + modelURL: MAZE_MODEL_URL, + compoundShapeURL: MAZE_COLLISION_HULL, + dimensions: MAZE_DIMENSIONS, + position: position, + restitution: MAZE_RESTITUTION, + damping: MAZE_DAMPING, + angularDamping: MAZE_ANGULAR_DAMPING, + dynamic: true, + density: MAZE_DENSITY, + script: MAZE_SCRIPT + } + + tiltMaze = Entities.addEntity(properties); + +}; + +var createLightAtTheEnd = function() { + + var mazeProps = Entities.getEntityProperties(tiltMaze, 'position'); + + var up = Quat.getUp(mazeProps.rotation); + var down = Vec3.multiply(-1, up); + + var emitOrientation = Quat.rotationBetween(Vec3.UNIT_NEG_Z, down); + + var position = getBallFinishLocation(); + var lightProperties = { + parentID: tiltMaze, + name: 'Hifi Tilt Maze End Light', + type: "Light", + isSpotlight: true, + dimensions: END_LIGHT_DIMENSIONS, + color: END_LIGHT_COLOR, + intensity: END_LIGHT_INTENSITY, + exponent: END_LIGHT_EXPONENT, + cutoff: END_LIGHT_CUTOFF, + lifetime: -1, + position: position, + rotation: emitOrientation + }; + + lightAtTheEnd = Entities.addEntity(lightProperties); +}; + +var createAll = function() { + createTiltMaze(center); + createBallSpawningAnchor(); + createBallDetector(center); + createBall(center); + createLightAtTheEnd(); + Entities.editEntity(tiltMaze, { + userData: JSON.stringify({ + tiltMaze: { + firstBall: ball, + ballSpawner: ballSpawningAnchor, + detector: ballDetector, + lightAtTheEnd: lightAtTheEnd + } + }) + }); +}; + +createAll(); + +if (CLEANUP === true) { + Script.scriptEnding.connect(function() { + Entities.deleteEntity(tiltMaze); + Entities.deleteEntity(ball); + Entities.deleteEntity(ballSpawningAnchor); + Entities.deleteEntity(lightAtTheEnd); + }); +}; \ No newline at end of file diff --git a/unpublishedScripts/DomainContent/Home/tiltMaze/maze.js b/unpublishedScripts/DomainContent/Home/tiltMaze/maze.js new file mode 100644 index 0000000000..557861ba30 --- /dev/null +++ b/unpublishedScripts/DomainContent/Home/tiltMaze/maze.js @@ -0,0 +1,212 @@ +// +// maze.js +// +// +// Created by James B. Pollack @imgntn on 2/15/2016 +// Copyright 2016 High Fidelity, Inc. +// +// This script resets a ball to its original position when the ball enters it. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { + + Script.include('../../../../libraries/utils.js'); + + var SCALE = 0.5; + var VICTORY_SOUND; + var BALL_DISTANCE_THRESHOLD = 1 * SCALE; + + var BALL_DETECTOR_THRESHOLD = 0.075 * SCALE; + var BALL_FORWARD_OFFSET = -0.2 * SCALE; + var BALL_RIGHT_OFFSET = -0.4 * SCALE; + var BALL_VERTICAL_OFFSET = 0.02 * SCALE; + + + var BALL_FRICTION = 0.7; + var BALL_RESTITUTION = 0.1; + var BALL_DAMPING = 0.6; + var BALL_ANGULAR_DAMPING = 0.2; + var BALL_DENSITY = 1000; + var BALL_GRAVITY = { + x: 0, + y: -9.8, + z: 0 + }; + + var BALL_DIMENSIONS = Vec3.multiply(SCALE, { + x: 0.05, + y: 0.05, + z: 0.05 + }); + + var BALL_COLOR = { + red: 255, + green: 0, + blue: 0 + }; + + var _this; + + function Maze() { + _this = this; + return; + } + + Maze.prototype = { + ball: null, + ballLocked: false, + preload: function(entityID) { + this.entityID = entityID; + VICTORY_SOUND = SoundCache.getSound("http://hifi-content.s3.amazonaws.com/DomainContent/Home/tiltMaze/levelUp.wav"); + }, + startNearGrab: function() { + //check to make sure a ball is in range, otherwise create one + this.testBallDistance(); + }, + continueNearGrab: function() { + this.testWinDistance(); + this.testBallDistance(); + }, + continueDistantGrab: function() { + this.testBallDistance(); + this.testWinDistance(); + }, + releaseGrab: function() { + this.testBallDistance(); + }, + getBallStartLocation: function() { + var mazeProps = Entities.getEntityProperties(this.entityID); + var right = Quat.getRight(mazeProps.rotation); + var front = Quat.getFront(mazeProps.rotation); + var vertical = { + x: 0, + y: BALL_VERTICAL_OFFSET, + z: 0 + }; + + var finalOffset = Vec3.sum(vertical, Vec3.multiply(right, BALL_RIGHT_OFFSET)); + finalOffset = Vec3.sum(finalOffset, Vec3.multiply(front, BALL_FORWARD_OFFSET)); + var location = Vec3.sum(mazeProps.position, finalOffset); + return location; + }, + createBall: function() { + if (this.ballLocked === true) { + return; + } + + var properties = { + name: 'Hifi Tilt Maze Ball', + type: 'Sphere', + position: this.getBallStartLocation(), + dynamic: true, + collisionless: false, + friction: BALL_FRICTION, + restitution: BALL_RESTITUTION, + angularDamping: BALL_ANGULAR_DAMPING, + damping: BALL_DAMPING, + gravity: BALL_GRAVITY, + density: BALL_DENSITY, + color: BALL_COLOR, + dimensions: BALL_DIMENSIONS + }; + + this.ball = Entities.addEntity(properties); + }, + destroyBall: function() { + var results = Entities.findEntities(MyAvatar.position, 10); + results.forEach(function(result) { + var props = Entities.getEntityProperties(result, ['name']); + var isAMazeBall = props.name.indexOf('Maze Ball'); + if (isAMazeBall > -1 && result === _this.ball) { + Entities.deleteEntity(result); + } + }) + }, + testBallDistance: function() { + if (this.ballLocked === true) { + return; + } + + var userData = Entities.getEntityProperties(this.entityID, 'userData').userData; + var data = null; + try { + data = JSON.parse(userData); + } catch (e) { + // print('error parsing json in maze userdata') + } + if (data === null) { + // print('data is null in userData') + return; + } + + var ballPosition; + if (this.ball === null) { + this.ball = data.tiltMaze.firstBall; + ballPosition = Entities.getEntityProperties(data.tiltMaze.firstBall, 'position').position; + + } else { + ballPosition = Entities.getEntityProperties(this.ball, 'position').position; + } + + var ballSpawnerPosition = Entities.getEntityProperties(data.tiltMaze.ballSpawner, 'position').position; + + var separation = Vec3.distance(ballPosition, ballSpawnerPosition); + if (separation > BALL_DISTANCE_THRESHOLD) { + this.destroyBall(); + this.createBall(); + } + }, + testWinDistance: function() { + if (this.ballLocked === true) { + return; + } + // print('testing win distance') + var userData = Entities.getEntityProperties(this.entityID, 'userData').userData; + var data = null; + try { + data = JSON.parse(userData); + } catch (e) { + // print('error parsing json in maze userdata') + } + if (data === null) { + // print('data is null in userData') + return; + } + + var ballPosition; + if (this.ball === null) { + this.ball = data.tiltMaze.firstBall; + ballPosition = Entities.getEntityProperties(data.tiltMaze.firstBall, 'position').position; + } else { + ballPosition = Entities.getEntityProperties(this.ball, 'position').position; + } + + var ballDetectorPosition = Entities.getEntityProperties(data.tiltMaze.detector, 'position').position; + var separation = Vec3.distance(ballPosition, ballDetectorPosition); + if (separation < BALL_DETECTOR_THRESHOLD) { + this.ballLocked = true; + this.destroyBall(); + this.playVictorySound(); + Script.setTimeout(function() { + _this.ballLocked = false; + _this.createBall(); + }, 1500) + } + }, + playVictorySound: function() { + var position = Entities.getEntityProperties(this.entityID, "position").position; + + var audioProperties = { + volume: 0.25, + position: position + }; + Audio.playSound(VICTORY_SOUND, audioProperties); + + }, + }; + + return new Maze(); +}); \ No newline at end of file