Created
July 24, 2014 18:45
-
-
Save cozza13/1a191f7c0a4d63544242 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// frisbee.js | |
// examples | |
// | |
// Created by Thijs Wenker on 7/5/14. | |
// Copyright 2014 High Fidelity, Inc. | |
// | |
// This description is still work in progress | |
// | |
// 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("http://public.highfidelity.io/scripts/toolBars.js"); | |
const LEFT_PALM = 0; | |
const LEFT_TIP = 1; | |
const LEFT_BUTTON_FWD = 5; | |
const LEFT_BUTTON_3 = 3; | |
const RIGHT_PALM = 2; | |
const RIGHT_TIP = 3; | |
const RIGHT_BUTTON_FWD = 11; | |
const RIGHT_BUTTON_3 = 9; | |
const FRISBEE_RADIUS = 0.08; | |
const GRAVITY_STRENGTH = 0.5; | |
const TARGET_RADIUS = 0.5; | |
const MIN_SIMULATION_SPEED = 0.15; | |
const THROWN_VELOCITY_SCALING = 1.5; | |
const SOUNDS_ENABLED = false; | |
//const FRISBEE_MODEL_URL = "http://test.thoys.nl/hifi/models/frisbee/swirl.fbx"; | |
const FRISBEE_BUTTON_URL = "http://test.thoys.nl/hifi/images/frisbee/frisbee_button_by_Judas.svg"; | |
const FRISBEE_MODEL_SCALE = 275; | |
const FRISBEE_MENU = "Toys>Frisbee"; | |
const FRISBEE_DESIGN_MENU = "Toys>Frisbee>Design"; | |
const FRISBEE_ENABLED_SETTING = "Frisbee>Enabled"; | |
const FRISBEE_CREATENEW_SETTING = "Frisbee>CreateNew"; | |
const FRISBEE_DESIGN_SETTING = "Frisbee>Design"; | |
const FRISBEE_FORCE_MOUSE_CONTROLS_SETTING = "Frisbee>ForceMouseControls"; | |
const FRISBEE_DESIGNS = [ | |
{"name":"Interface", "model":"http://test.thoys.nl/hifi/models/frisbee/frisbee.fbx"}, | |
{"name":"Pizza", "model":"http://test.thoys.nl/hifi/models/frisbee/pizza.fbx"}, | |
{"name":"Swirl", "model":"http://test.thoys.nl/hifi/models/frisbee/swirl.fbx"}, | |
{"name":"Mayan", "model":"http://test.thoys.nl/hifi/models/frisbee/mayan.fbx"}, | |
]; | |
function randomFrisbee() { | |
return FRISBEE_DESIGNS[Math.floor(Math.random() * FRISBEE_DESIGNS.length)]; | |
} | |
const SPIN_MULTIPLIER = 1000; | |
const FRISBEE_LIFETIME = 300; // 5 minutes | |
var windowDimensions = Controller.getViewportDimensions(); | |
var toolHeight = 50; | |
var toolWidth = 50; | |
var frisbeeToggle; | |
var toolBar; | |
var frisbeeEnabled = true; | |
var newfrisbeeEnabled = false; | |
var forceMouseControls = false; | |
var hydrasConnected = false; | |
var selectedDesign = "Random"; | |
function loadSettings() { | |
frisbeeEnabled = Settings.getValue(FRISBEE_ENABLED_SETTING, "true") == "true"; | |
newfrisbeeEnabled = Settings.getValue(FRISBEE_CREATENEW_SETTING, "false") == "true"; | |
forceMouseControls = Settings.getValue(FRISBEE_FORCE_MOUSE_CONTROLS_SETTING, "false") == "true"; | |
selectedDesign = Settings.getValue(FRISBEE_DESIGN_SETTING, "Random"); | |
} | |
function saveSettings() { | |
Settings.setValue(FRISBEE_ENABLED_SETTING, frisbeeEnabled ? "true" : "false"); | |
Settings.setValue(FRISBEE_CREATENEW_SETTING, newfrisbeeEnabled ? "true" : "false"); | |
Settings.setValue(FRISBEE_FORCE_MOUSE_CONTROLS_SETTING, forceMouseControls ? "true" : "false"); | |
Settings.setValue(FRISBEE_DESIGN_SETTING, selectedDesign); | |
} | |
function moveOverlays() { | |
var newViewPort = Controller.getViewportDimensions(); | |
if (typeof(toolBar) === 'undefined') { | |
initToolBar(); | |
} else if (windowDimensions.x == newViewPort.x && | |
windowDimensions.y == newViewPort.y) { | |
return; | |
} | |
windowDimensions = newViewPort; | |
var toolsX = windowDimensions.x - 8 - toolBar.width; | |
var toolsY = (windowDimensions.y - toolBar.height) / 2 + 80; | |
toolBar.move(toolsX, toolsY); | |
} | |
function Hand(name, palm, tip, forwardButton, button3, trigger) { | |
this.name = name; | |
this.palm = palm; | |
this.tip = tip; | |
this.forwardButton = forwardButton; | |
this.button3 = button3; | |
this.trigger = trigger; | |
this.holdingFrisbee = false; | |
this.particle = false; | |
this.palmPosition = function() { return Controller.getSpatialControlPosition(this.palm); } | |
this.grabButtonPressed = function() { | |
return ( | |
Controller.isButtonPressed(this.forwardButton) || | |
Controller.isButtonPressed(this.button3) || | |
Controller.getTriggerValue(this.trigger) > 0.5 | |
) | |
}; | |
this.holdPosition = function() { return this.palm == LEFT_PALM ? MyAvatar.getLeftPalmPosition() : MyAvatar.getRightPalmPosition(); }; | |
this.holdRotation = function() { | |
var q = Controller.getSpatialControlRawRotation(this.palm); | |
q = Quat.multiply(MyAvatar.orientation, q); | |
//var euler = Quat.safeEulerAngles(q); | |
//q = Quat.fromPitchYawRollDegrees(0, euler.y*2,0); | |
return {x: q.x, y: q.y, z: q.z, w: q.w}; | |
}; | |
this.tipVelocity = function() { return Controller.getSpatialControlVelocity(this.tip); }; | |
} | |
function MouseControl(button) { | |
this.button = button; | |
} | |
var leftHand = new Hand("LEFT", LEFT_PALM, LEFT_TIP, LEFT_BUTTON_FWD, LEFT_BUTTON_3, 0); | |
var rightHand = new Hand("RIGHT", RIGHT_PALM, RIGHT_TIP, RIGHT_BUTTON_FWD, RIGHT_BUTTON_3, 1); | |
var leftMouseControl = new MouseControl("LEFT"); | |
var middleMouseControl = new MouseControl("MIDDLE"); | |
var rightMouseControl = new MouseControl("RIGHT"); | |
var mouseControls = [leftMouseControl, middleMouseControl, rightMouseControl]; | |
var currentMouseControl = false; | |
var newSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw"); | |
var catchSound = new Sound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw"); | |
var throwSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Switches%20and%20sliders/slider%20-%20whoosh1.raw"); | |
var simulatedFrisbees = []; | |
var wantDebugging = false; | |
function debugPrint(message) { | |
if (wantDebugging) { | |
print(message); | |
} | |
} | |
function playSound(sound, position) { | |
if (!SOUNDS_ENABLED) { | |
return; | |
} | |
var options = new AudioInjectionOptions(); | |
options.position = position; | |
options.volume = 1.0; | |
Audio.playSound(sound, options); | |
} | |
function cleanupFrisbees() { | |
simulatedFrisbees = []; | |
var particles = Particles.findParticles(MyAvatar.position, 1000); | |
for (particle in particles) { | |
Particles.deleteParticle(particles[particle]); | |
} | |
} | |
function checkControllerSide(hand) { | |
// If I don't currently have a frisbee in my hand, then try to catch closest one | |
if (!hand.holdingFrisbee && hand.grabButtonPressed()) { | |
var closestParticle = Particles.findClosestParticle(hand.palmPosition(), TARGET_RADIUS); | |
var modelUrl = Particles.getParticleProperties(closestParticle).modelURL; | |
if (closestParticle.isKnownID) {// && Particles.getParticleProperties(closestParticle).modelURL == FRISBEE_MODEL_URL) { | |
//print("whute"); | |
//print(closestParticle); | |
//print(Particles.getParticleProperties(closestParticle).age); | |
Particles.editParticle(closestParticle, {modelScale: 1, inHand: true, position: hand.holdPosition(), shouldDie: true}); | |
Particles.deleteParticle(closestParticle); | |
debugPrint(hand.message + " HAND- CAUGHT SOMETHING!!"); | |
var properties = { | |
position: hand.holdPosition(), | |
velocity: { x: 0, y: 0, z: 0}, | |
gravity: { x: 0, y: 0, z: 0}, | |
inHand: true, | |
radius: FRISBEE_RADIUS, | |
damping: 0.999, | |
modelURL: modelUrl, | |
modelScale: FRISBEE_MODEL_SCALE, | |
modelRotation: hand.holdRotation(), | |
lifetime: FRISBEE_LIFETIME // 5 minutes | |
}; | |
newParticle = Particles.addParticle(properties); | |
hand.holdingFrisbee = true; | |
hand.particle = newParticle; | |
playSound(catchSound, hand.holdPosition()); | |
return; // exit early | |
} | |
} | |
// If '3' is pressed, and not holding a ball, make a new one | |
if (hand.grabButtonPressed() && !hand.holdingFrisbee && newfrisbeeEnabled) { | |
var properties = { | |
position: hand.holdPosition(), | |
velocity: { x: 0, y: 0, z: 0}, | |
gravity: { x: 0, y: 0, z: 0}, | |
inHand: true, | |
radius: FRISBEE_RADIUS, | |
damping: 0.999, | |
modelURL: randomFrisbee().model, | |
modelScale: FRISBEE_MODEL_SCALE, | |
modelRotation: hand.holdRotation(), | |
lifetime: FRISBEE_LIFETIME | |
}; | |
newParticle = Particles.addParticle(properties); | |
hand.holdingFrisbee = true; | |
hand.particle = newParticle; | |
// Play a new ball sound | |
playSound(newSound, hand.holdPosition()); | |
return; // exit early | |
} | |
if (hand.holdingFrisbee) { | |
// If holding the frisbee keep it in the palm | |
if (hand.grabButtonPressed()) { | |
debugPrint(">>>>> " + hand.name + "-FRISBEE IN HAND, grabbing, hold and move"); | |
var properties = { | |
position: hand.holdPosition(), | |
modelRotation: hand.holdRotation() | |
}; | |
Particles.editParticle(hand.particle, properties); | |
} else { | |
debugPrint(">>>>> " + hand.name + "-FRISBEE IN HAND, not grabbing, THROW!!!"); | |
// If frisbee just released, add velocity to it! | |
var properties = { | |
velocity: Vec3.multiply(hand.tipVelocity(), THROWN_VELOCITY_SCALING), | |
inHand: false, | |
lifetime: FRISBEE_LIFETIME, | |
gravity: { x: 0, y: -GRAVITY_STRENGTH, z: 0}, | |
modelRotation: hand.holdRotation() | |
}; | |
Particles.editParticle(hand.particle, properties); | |
simulatedFrisbees.push(hand.particle); | |
hand.holdingFrisbee = false; | |
hand.particle = false; | |
playSound(throwSound, hand.holdPosition()); | |
} | |
} | |
} | |
function initToolBar() { | |
toolBar = new ToolBar(0, 0, ToolBar.VERTICAL); | |
frisbeeToggle = toolBar.addTool({ | |
imageURL: FRISBEE_BUTTON_URL, | |
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, | |
width: toolWidth, | |
height: toolHeight, | |
visible: true, | |
alpha: 0.9 | |
}, true); | |
enableNewFrisbee(newfrisbeeEnabled); | |
} | |
function hydraCheck() { | |
var numberOfButtons = Controller.getNumberOfButtons(); | |
var numberOfTriggers = Controller.getNumberOfTriggers(); | |
var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); | |
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; | |
hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2); | |
} | |
function checkController(deltaTime) { | |
moveOverlays(); | |
if (!frisbeeEnabled) { | |
return; | |
} | |
hydraCheck(); | |
// this is expected for hydras | |
if (hydrasConnected) { | |
checkControllerSide(leftHand); | |
checkControllerSide(rightHand); | |
} | |
if (!hydrasConnected || forceMouseControls) { | |
} | |
} | |
function controlFrisbees(deltaTime) { | |
var killSimulations = []; | |
for (frisbee in simulatedFrisbees) { | |
var properties = Particles.getParticleProperties(simulatedFrisbees[frisbee]); | |
//get the horizon length from the velocity origin in order to get speed | |
var speed = Vec3.length({x:properties.velocity.x, y:0, z:properties.velocity.z}); | |
if (speed < MIN_SIMULATION_SPEED) { | |
//kill the frisbee simulation when speed is low | |
killSimulations.push(frisbee); | |
continue; | |
} | |
Particles.editParticle(simulatedFrisbees[frisbee], {modelRotation: Quat.multiply(properties.modelRotation, Quat.fromPitchYawRollDegrees(0, speed * deltaTime * SPIN_MULTIPLIER, 0))}); | |
} | |
for (var i = killSimulations.length - 1; i >= 0; i--) { | |
simulatedFrisbees.splice(killSimulations[i], 1); | |
} | |
} | |
//catches interfering calls of hydra-cursors | |
function withinBounds(coords) { | |
return coords.x >= 0 && coords.x < windowDimensions.x && coords.y >= 0 && coords.y < windowDimensions.y; | |
} | |
function mouseMoveEvent(event) { | |
//print(withinBounds(event)); | |
//print("move"+event.x); | |
} | |
function mousePressEvent(event) { | |
print(event.x); | |
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); | |
if (frisbeeToggle == toolBar.clicked(clickedOverlay)) { | |
newfrisbeeEnabled = !newfrisbeeEnabled; | |
saveSettings(); | |
enableNewFrisbee(newfrisbeeEnabled); | |
} | |
} | |
function enableNewFrisbee(enable) { | |
if (toolBar.numberOfTools() > 0) { | |
toolBar.tools[0].select(enable); | |
} | |
} | |
function mouseReleaseEvent(event) { | |
print(JSON.stringify(event)); | |
} | |
function setupMenus() { | |
Menu.addMenu(FRISBEE_MENU); | |
Menu.addMenuItem({ | |
menuName: FRISBEE_MENU, | |
menuItemName: "Frisbee Enabled", | |
isCheckable: true, | |
isChecked: frisbeeEnabled | |
}); | |
Menu.addMenuItem({ | |
menuName: FRISBEE_MENU, | |
menuItemName: "Cleanup Frisbees" | |
}); | |
Menu.addMenuItem({ | |
menuName: FRISBEE_MENU, | |
menuItemName: "Force Mouse Controls", | |
isCheckable: true, | |
isChecked: forceMouseControls | |
}); | |
Menu.addMenu(FRISBEE_DESIGN_MENU); | |
Menu.addMenuItem({ | |
menuName: FRISBEE_DESIGN_MENU, | |
menuItemName: "Random Design" | |
}); | |
Menu.addMenuItem({ | |
menuName: FRISBEE_DESIGN_MENU, | |
menuItemName: "Interface Design" | |
}); | |
} | |
//startup calls: | |
loadSettings(); | |
setupMenus(); | |
function scriptEnding() { | |
toolBar.cleanup(); | |
Menu.removeMenu(FRISBEE_MENU); | |
} | |
function menuItemEvent(menuItem) { | |
if (menuItem == "Cleanup Frisbees") { | |
cleanupFrisbees(); | |
} else if (menuItem == "Frisbee Enabled") { | |
frisbeeEnabled = Menu.isOptionChecked(menuItem); | |
saveSettings(); | |
} else if (menuItem == "Force Mouse Controls") { | |
forceMouseControls = Menu.isOptionChecked(menuItem); | |
saveSettings(); | |
} else { | |
} | |
} | |
// register the call back so it fires before each data send | |
Controller.mouseMoveEvent.connect(mouseMoveEvent); | |
Controller.mousePressEvent.connect(mousePressEvent); | |
Controller.mouseReleaseEvent.connect(mouseReleaseEvent); | |
Menu.menuItemEvent.connect(menuItemEvent); | |
Script.scriptEnding.connect(scriptEnding); | |
Script.update.connect(checkController); | |
Script.update.connect(controlFrisbees); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment