324 lines
12 KiB
JavaScript
324 lines
12 KiB
JavaScript
// PinSetterEntity.js
|
|
// Copyright 2016 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
|
|
//
|
|
|
|
(function() {
|
|
var _this;
|
|
|
|
var BOWLING_ALLEY_PREFIX_URL = 'http://hifi-content.s3.amazonaws.com/caitlyn/production/bowlingAlley/';
|
|
|
|
var IMPORT_URL_PINSET = BOWLING_ALLEY_PREFIX_URL + 'bpins4.svo.json';
|
|
var IMPORT_URL_BALL = BOWLING_ALLEY_PREFIX_URL + 'bowlingBall.svo.json';
|
|
var BELL_SOUND_URL = BOWLING_ALLEY_PREFIX_URL + 'bell.wav';
|
|
var RETURN_SOUND_URL = BOWLING_ALLEY_PREFIX_URL + 'caitlynMeeks_ball%20return%20mechanism.wav';
|
|
|
|
var SECONDS_IN_HOUR = 3600;
|
|
var MAX_EQUIPMENT_LIFETIME = SECONDS_IN_HOUR;
|
|
var SECOND_BALL_WAIT_MILLISECONDS = 2000;
|
|
|
|
var TRIANGLE_NUMBER_OF_PINS = 4;
|
|
var TRIANGLE_WIDTH = 1;
|
|
|
|
var PIN_DIMENSIONS = {
|
|
x: 0.1638,
|
|
y: 0.3971,
|
|
z: 0.1638
|
|
};
|
|
|
|
var BOWLING_BALLS = [
|
|
{
|
|
name: 'Bowling ball - Salmon',
|
|
density: 5000,
|
|
dimensions: {
|
|
x: 0.245,
|
|
y: 0.245,
|
|
z: 0.245
|
|
}
|
|
},
|
|
{
|
|
name: 'Bowling ball - Purple',
|
|
density: 6000,
|
|
dimensions: {
|
|
x: 0.265,
|
|
y: 0.265,
|
|
z: 0.265
|
|
},
|
|
textures: JSON.stringify({
|
|
file4: BOWLING_ALLEY_PREFIX_URL + 'bowlingball_Base_Color_purple.png',
|
|
file5: BOWLING_ALLEY_PREFIX_URL + 'ball_salmon.fbx/../../../../Downloads/bowlingball.fbm/bowlingball_Roughness.png'
|
|
})
|
|
},
|
|
{
|
|
name: 'Bowling ball - Yellow',
|
|
density: 4000,
|
|
dimensions: {
|
|
x: 0.205,
|
|
y: 0.205,
|
|
z: 0.205
|
|
},
|
|
textures: JSON.stringify({
|
|
file4: BOWLING_ALLEY_PREFIX_URL + 'bowlingball_Base_Color_yellow.png',
|
|
file5: BOWLING_ALLEY_PREFIX_URL + 'ball_salmon.fbx/../../../../Downloads/bowlingball.fbm/bowlingball_Roughness.png'
|
|
})
|
|
},
|
|
{
|
|
name: 'Bowling ball - Blue',
|
|
density: 5500,
|
|
dimensions: {
|
|
x: 0.255,
|
|
y: 0.255,
|
|
z: 0.255
|
|
},
|
|
textures: JSON.stringify({
|
|
file4: BOWLING_ALLEY_PREFIX_URL + 'bowlingball_Base_Color_blue.png',
|
|
file5: BOWLING_ALLEY_PREFIX_URL + 'ball_salmon.fbx/../../../../Downloads/bowlingball.fbm/bowlingball_Roughness.png'
|
|
})
|
|
}
|
|
];
|
|
|
|
// See https://en.wikipedia.org/wiki/Triangular_number for Triangle numbers (T1 = 1, T2 = 3, T3 = 6 ... etc)
|
|
var getPinPositions = function(maxWidth, triangleNumber) {
|
|
var pinPositions = [];
|
|
var gapSpace = maxWidth / triangleNumber;
|
|
for (var row = 0; row < triangleNumber; row++) {
|
|
var rowPins = triangleNumber - row;
|
|
for (var rowPinIndex = 0; rowPinIndex < rowPins; rowPinIndex++) {
|
|
pinPositions.push({
|
|
x: (-((rowPins - 1) / 2) + rowPinIndex) * gapSpace,
|
|
z: row * gapSpace
|
|
})
|
|
}
|
|
}
|
|
|
|
return pinPositions;
|
|
};
|
|
|
|
var returnSound, ringSound;
|
|
|
|
// Creates an entity and returns a mixed object of the creation properties and the assigned entityID
|
|
var createEntity = function(entityProperties, parent) {
|
|
if (parent.rotation !== undefined) {
|
|
if (entityProperties.rotation !== undefined) {
|
|
entityProperties.rotation = Quat.multiply(parent.rotation, entityProperties.rotation);
|
|
} else {
|
|
entityProperties.rotation = parent.rotation;
|
|
}
|
|
}
|
|
if (parent.position !== undefined) {
|
|
var localPosition = (parent.rotation !== undefined) ? Vec3.multiplyQbyV(parent.rotation, entityProperties.position) : entityProperties.position;
|
|
entityProperties.position = Vec3.sum(localPosition, parent.position);
|
|
}
|
|
if (parent.id !== undefined) {
|
|
entityProperties.parentID = parent.id;
|
|
}
|
|
entityProperties.id = Entities.addEntity(entityProperties);
|
|
return entityProperties;
|
|
};
|
|
|
|
var createPin = function (transform, extraProperties, bowlingAlley) {
|
|
var entityProperties = {
|
|
compoundShapeURL: BOWLING_ALLEY_PREFIX_URL + 'bowlingpin_hull.obj',
|
|
dimensions: PIN_DIMENSIONS,
|
|
dynamic: true,
|
|
gravity: {
|
|
x: 0,
|
|
y: -9.8,
|
|
z: 0
|
|
},
|
|
modelURL: BOWLING_ALLEY_PREFIX_URL + 'bowlingpin.fbx',
|
|
name: 'Bowling Pin',
|
|
shapeType: 'compound',
|
|
type: 'Model',
|
|
userData: JSON.stringify({
|
|
isBowlingPin: true,
|
|
bowlingAlley: bowlingAlley,
|
|
grabbableKey: {
|
|
grabbable: false
|
|
}
|
|
}),
|
|
script: 'https://hifi-content.s3.amazonaws.com/lincoln/bowlingPinEntity.js',
|
|
lifetime: MAX_EQUIPMENT_LIFETIME
|
|
};
|
|
for (var key in extraProperties) {
|
|
if (extraProperties.hasOwnProperty(key)) {
|
|
entityProperties[key] = extraProperties[key];
|
|
}
|
|
}
|
|
return createEntity(entityProperties, transform);
|
|
};
|
|
|
|
var createBall = function (transform, extraProperties, bowlingAlley) {
|
|
var entityProperties = {
|
|
angularDamping: 0.3,
|
|
collisionsWillMove: 1,
|
|
damping: 0.01,
|
|
density: 5000,
|
|
dimensions: {
|
|
x: 0.245,
|
|
y: 0.245,
|
|
z: 0.245
|
|
},
|
|
angularVelocity: {
|
|
w: -0.12123292684555054,
|
|
x: 0.97888147830963135,
|
|
y: -0.075059115886688232,
|
|
z: -0.14644080400466919
|
|
},
|
|
velocity: Vec3.multiplyQbyV(transform.rotation, {
|
|
x: 0,
|
|
y: 0,
|
|
z: 1,
|
|
}),
|
|
collidesWith: 'static,dynamic,kinematic',
|
|
dynamic: true,
|
|
friction: 0.1,
|
|
gravity: {
|
|
x: 0,
|
|
y: -9.8,
|
|
z: 0
|
|
},
|
|
modelURL: BOWLING_ALLEY_PREFIX_URL + 'ball_salmon.fbx',
|
|
restitution: 0.2,
|
|
rotation: {
|
|
w: -0.12123292684555054,
|
|
x: 0.97888147830963135,
|
|
y: -0.075059115886688232,
|
|
z: -0.14644080400466919
|
|
},
|
|
shapeType: 'sphere',
|
|
type: 'Model',
|
|
userData: JSON.stringify({
|
|
isBowlingBall: true,
|
|
bowlingAlley: bowlingAlley,
|
|
grabbableKey: {
|
|
grabbable: true
|
|
}
|
|
}),
|
|
script: 'http://mpassets.highfidelity.com/f01af088-7410-40e2-a331-310e9a0d068e-v1/bowlingBallEntity.js',
|
|
lifetime: MAX_EQUIPMENT_LIFETIME
|
|
};
|
|
for (var key in extraProperties) {
|
|
if (extraProperties.hasOwnProperty(key)) {
|
|
entityProperties[key] = extraProperties[key];
|
|
}
|
|
}
|
|
|
|
Audio.playSound(returnSound, {
|
|
position: transform.position,
|
|
volume: 0.5
|
|
});
|
|
|
|
return createEntity(entityProperties, transform);
|
|
};
|
|
|
|
function ResetButton() {
|
|
_this = this;
|
|
}
|
|
|
|
ResetButton.prototype = {
|
|
entityID: null,
|
|
resetConsoleID: null,
|
|
bowlingAlleyID: null,
|
|
preload: function(entityID) {
|
|
print('preload(' + entityID + ')');
|
|
_this.entityID = entityID;
|
|
_this.resetConsoleID = Entities.getEntityProperties(_this.entityID, ['parentID']).parentID;
|
|
_this.bowlingAlleyID = Entities.getEntityProperties(_this.resetConsoleID, ['parentID']).parentID; // get the bowling alley's parent ID
|
|
ringSound = SoundCache.getSound(BELL_SOUND_URL);
|
|
returnSound = SoundCache.getSound(RETURN_SOUND_URL);
|
|
},
|
|
unload: function() {
|
|
// this would remove the pins when someone random is leaving (not what we intend)
|
|
// _this.clearPins();
|
|
},
|
|
clearPins: function() {
|
|
Entities.findEntities(MyAvatar.position, 1000).forEach(function(entity) {
|
|
try {
|
|
var userData = JSON.parse(Entities.getEntityProperties(entity, ['userData']).userData);
|
|
if (userData.isBowlingPin && userData.bowlingAlley === _this.bowlingAlleyID) {
|
|
print("Found pin, deleting it: " + entity);
|
|
Entities.deleteEntity(entity);
|
|
}
|
|
} catch(e) {}
|
|
});
|
|
},
|
|
createRandomBallInRetractor: function() {
|
|
var entProperties = Entities.getEntityProperties(_this.bowlingAlleyID, ['position', 'rotation']);
|
|
var jointIndex = Entities.getJointIndex(_this.bowlingAlleyID, 'ballLocatorJoint');
|
|
var jointLocInObjectFrame = Entities.getAbsoluteJointTranslationInObjectFrame(_this.bowlingAlleyID, jointIndex);
|
|
var jointLocInWorld = Vec3.sum(entProperties.position, Vec3.multiplyQbyV(entProperties.rotation, jointLocInObjectFrame));
|
|
createBall({
|
|
position: jointLocInWorld,
|
|
rotation: entProperties.rotation
|
|
}, BOWLING_BALLS[Math.floor(BOWLING_BALLS.length * Math.random())], _this.bowlingAlleyID);
|
|
},
|
|
clearBalls: function() {
|
|
Entities.findEntities(MyAvatar.position, 1000).forEach(function(entity) {
|
|
try {
|
|
var userData = JSON.parse(Entities.getEntityProperties(entity, ['userData']).userData);
|
|
if (userData.isBowlingBall && userData.bowlingAlley === _this.bowlingAlleyID) {
|
|
print("Found ball, deleting it: " + entity);
|
|
Entities.deleteEntity(entity);
|
|
}
|
|
} catch(e) {}
|
|
});
|
|
},
|
|
doTheRez: function() {
|
|
//print("START BOWLING RESET TRIGGER");
|
|
// Reset pins
|
|
var entProperties = Entities.getEntityProperties(_this.bowlingAlleyID);
|
|
var jointNames = Entities.getJointNames(_this.bowlingAlleyID);
|
|
//print("Joint Names " + jointNames);
|
|
var jointIndex = Entities.getJointIndex(_this.bowlingAlleyID, 'pinLocatorJoint');
|
|
//print("JOINT INDEX IS " + jointIndex);
|
|
var jointLocInObjectFrame = Entities.getAbsoluteJointTranslationInObjectFrame(_this.bowlingAlleyID, jointIndex);
|
|
var jointLocInWorld = Vec3.sum(entProperties.position, Vec3.multiplyQbyV(entProperties.rotation, jointLocInObjectFrame));
|
|
//print("LOCATION IS " + JSON.stringify(jointLocInWorld));
|
|
|
|
_this.clearPins();
|
|
|
|
//print("ADDING NEW PINS");
|
|
|
|
var pinHeightOffset = {y: PIN_DIMENSIONS.y / 2};
|
|
getPinPositions(TRIANGLE_WIDTH, TRIANGLE_NUMBER_OF_PINS).forEach(function(pinPosition) {
|
|
createPin({
|
|
position: Vec3.sum(jointLocInWorld, pinHeightOffset),
|
|
rotation: entProperties.rotation
|
|
}, {
|
|
position: pinPosition
|
|
}, _this.bowlingAlleyID);
|
|
});
|
|
|
|
//print("PINS ADDED");
|
|
|
|
// Add new ball
|
|
_this.createRandomBallInRetractor();
|
|
|
|
Script.setTimeout(function() {
|
|
_this.createRandomBallInRetractor();
|
|
}, SECOND_BALL_WAIT_MILLISECONDS);
|
|
|
|
//Clipboard.importEntities(IMPORT_URL_BALL);
|
|
//Clipboard.pasteEntities(jointLocInWorld);
|
|
//print("BALL ADDED");
|
|
|
|
// Completion sound
|
|
Audio.playSound(ringSound, {
|
|
position: Entities.getEntityProperties(_this.entityID, ['position']).position,
|
|
volume: 0.5
|
|
});
|
|
},
|
|
startNearTrigger: function(entityID) {
|
|
_this.doTheRez();
|
|
},
|
|
clickReleaseOnEntity: function(entityID, mouseEvent) {
|
|
if (mouseEvent.isLeftButton) {
|
|
_this.doTheRez();
|
|
}
|
|
}
|
|
};
|
|
return new ResetButton();
|
|
});
|