Skip to content

Instantly share code, notes, and snippets.

@cozza13
Created July 24, 2014 18:45
Show Gist options
  • Save cozza13/1a191f7c0a4d63544242 to your computer and use it in GitHub Desktop.
Save cozza13/1a191f7c0a4d63544242 to your computer and use it in GitHub Desktop.
//
// 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