mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 16:18:05 +02:00
Equip stick instead of grab. String is less rigid. Fixed bug where the ball was not recognized when other clients equipped the stick.
This commit is contained in:
parent
6763ca9b27
commit
49858d3ec5
2 changed files with 194 additions and 311 deletions
|
@ -14,20 +14,61 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
|
var NULL_UUID = "{00000000-0000-0000-0000-000000000000}";
|
||||||
|
var LIFETIME = 3600;
|
||||||
|
var BALL_SIZE = 0.175;
|
||||||
|
var BALL_DAMPING = 0.5;
|
||||||
|
var BALL_ANGULAR_DAMPING = 0.5;
|
||||||
|
var BALL_RESTITUTION = 0.4;
|
||||||
|
var BALL_DENSITY = 1000;
|
||||||
var STICK_SCRIPT_URL = Script.resolvePath("./entity_scripts/tetherballStick.js?v=" + Date.now());
|
var STICK_SCRIPT_URL = Script.resolvePath("./entity_scripts/tetherballStick.js?v=" + Date.now());
|
||||||
var STICK_MODEL_URL = "http://hifi-content.s3.amazonaws.com/caitlyn/production/raveStick/newRaveStick2.fbx";
|
var STICK_MODEL_URL = "http://hifi-content.s3.amazonaws.com/caitlyn/production/raveStick/newRaveStick2.fbx";
|
||||||
|
var COLLISION_SOUND_URL = "http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav";
|
||||||
|
|
||||||
var avatarOrientation = MyAvatar.orientation;
|
var avatarOrientation = MyAvatar.orientation;
|
||||||
avatarOrientation = Quat.safeEulerAngles(avatarOrientation);
|
avatarOrientation = Quat.safeEulerAngles(avatarOrientation);
|
||||||
avatarOrientation.x = 0;
|
avatarOrientation.x = 0;
|
||||||
avatarOrientation = Quat.fromVec3Degrees(avatarOrientation);
|
avatarOrientation = Quat.fromVec3Degrees(avatarOrientation);
|
||||||
var startPosition = Vec3.sum(MyAvatar.getRightPalmPosition(), Vec3.multiply(1, Quat.getFront(avatarOrientation)));
|
var front = Quat.getFront(avatarOrientation);
|
||||||
|
var stickStartPosition = Vec3.sum(MyAvatar.getRightPalmPosition(), front);
|
||||||
|
var ballStartPosition = Vec3.sum(stickStartPosition, Vec3.multiply(0.36, front));
|
||||||
|
|
||||||
|
var ballID = Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
modelURL: "http://hifi-content.s3.amazonaws.com/Examples%20Content/production/marblecollection/Star.fbx",
|
||||||
|
name: "TetherballStick Ball",
|
||||||
|
shapeType: "Sphere",
|
||||||
|
position: ballStartPosition,
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
collisionSoundURL: COLLISION_SOUND_URL,
|
||||||
|
dimensions: {
|
||||||
|
x: BALL_SIZE,
|
||||||
|
y: BALL_SIZE,
|
||||||
|
z: BALL_SIZE
|
||||||
|
},
|
||||||
|
gravity: {
|
||||||
|
x: 0.0,
|
||||||
|
y: -9.8,
|
||||||
|
z: 0.0
|
||||||
|
},
|
||||||
|
damping: BALL_DAMPING,
|
||||||
|
angularDamping: BALL_ANGULAR_DAMPING,
|
||||||
|
density: BALL_DENSITY,
|
||||||
|
restitution: BALL_RESTITUTION,
|
||||||
|
dynamic: true,
|
||||||
|
collidesWith: "static,dynamic,otherAvatar,",
|
||||||
|
userData: JSON.stringify({
|
||||||
|
grabbableKey: {
|
||||||
|
grabbable: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
var STICK_PROPERTIES = {
|
var STICK_PROPERTIES = {
|
||||||
type: 'Model',
|
type: 'Model',
|
||||||
name: "TetherballStick Stick",
|
name: "TetherballStick Stick",
|
||||||
modelURL: STICK_MODEL_URL,
|
modelURL: STICK_MODEL_URL,
|
||||||
position: startPosition,
|
position: stickStartPosition,
|
||||||
rotation: MyAvatar.orientation,
|
rotation: MyAvatar.orientation,
|
||||||
dimensions: {
|
dimensions: {
|
||||||
x: 0.0651,
|
x: 0.0651,
|
||||||
|
@ -41,31 +82,40 @@ var STICK_PROPERTIES = {
|
||||||
blue: 20
|
blue: 20
|
||||||
},
|
},
|
||||||
shapeType: 'box',
|
shapeType: 'box',
|
||||||
lifetime: 3600,
|
lifetime: LIFETIME,
|
||||||
userData: JSON.stringify({
|
userData: JSON.stringify({
|
||||||
grabbableKey: {
|
grabbableKey: {
|
||||||
grabbable: true,
|
invertSolidWhileHeld: true,
|
||||||
spatialKey: {
|
ignoreIK: false
|
||||||
rightRelativePosition: {
|
|
||||||
x: 0.05,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
},
|
|
||||||
leftRelativePosition: {
|
|
||||||
x: -0.05,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
},
|
|
||||||
relativeRotation: {
|
|
||||||
x: 0.4999999701976776,
|
|
||||||
y: 0.4999999701976776,
|
|
||||||
z: -0.4999999701976776,
|
|
||||||
w: 0.4999999701976776
|
|
||||||
}
|
|
||||||
},
|
|
||||||
invertSolidWhileHeld: true
|
|
||||||
},
|
},
|
||||||
ownerID: MyAvatar.sessionUUID
|
wearable: {
|
||||||
|
joints: {
|
||||||
|
RightHand: [{
|
||||||
|
x: 0.15539926290512085,
|
||||||
|
y: 0.14493153989315033,
|
||||||
|
z: 0.023641478270292282
|
||||||
|
}, {
|
||||||
|
x: 0.5481458902359009,
|
||||||
|
y: -0.4470711946487427,
|
||||||
|
z: -0.3148134648799896,
|
||||||
|
w: 0.6328644752502441
|
||||||
|
}],
|
||||||
|
LeftHand: [{
|
||||||
|
x: -0.14998853206634521,
|
||||||
|
y: 0.17033983767032623,
|
||||||
|
z: 0.023199155926704407
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 0.6623835563659668,
|
||||||
|
y: -0.1671387255191803,
|
||||||
|
z: 0.7071226835250854,
|
||||||
|
w: 0.1823924481868744
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ownerID: MyAvatar.sessionUUID,
|
||||||
|
ballID: ballID,
|
||||||
|
lifetime: LIFETIME
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,178 +18,107 @@
|
||||||
var _this;
|
var _this;
|
||||||
|
|
||||||
var NULL_UUID = "{00000000-0000-0000-0000-000000000000}";
|
var NULL_UUID = "{00000000-0000-0000-0000-000000000000}";
|
||||||
var ENTITY_CHECK_INTERVAL = 5; // time in sec
|
|
||||||
var LINE_WIDTH = 0.02;
|
var LINE_WIDTH = 0.02;
|
||||||
var BALL_SIZE = 0.175;
|
var MAX_DISTANCE_MULTIPLIER = 4;
|
||||||
var BALL_DAMPING = 0.5;
|
var ACTION_DISTANCE = 0.35;
|
||||||
var BALL_ANGULAR_DAMPING = 0.5;
|
var ACTION_TIMESCALE = 0.035;
|
||||||
var BALL_RESTITUTION = 0.4;
|
|
||||||
var BALL_DENSITY = 1000;
|
|
||||||
var MAX_DISTANCE_MULTIPLIER = 2;
|
|
||||||
var ACTION_DISTANCE = 0.25;
|
|
||||||
var ACTION_TIMESCALE = 0.025;
|
|
||||||
var ACTION_TAG = "TetherballStick Action";
|
|
||||||
var BALL_NAME = "TetherballStick Ball";
|
|
||||||
var LINE_NAME = "TetherballStick Line";
|
|
||||||
var COLLISION_SOUND_URL = "http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav";
|
var COLLISION_SOUND_URL = "http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav";
|
||||||
var INTERACT_SOUND_URL = "http://hifi-public.s3.amazonaws.com/sounds/color_busters/powerup.wav";
|
|
||||||
var INTERACT_SOUND_VOLUME = 0.2;
|
|
||||||
var USE_INTERACT_SOUND = false;
|
|
||||||
var AVATAR_CHECK_RANGE = 5; // in meters
|
|
||||||
var TIP_OFFSET = 0.26;
|
var TIP_OFFSET = 0.26;
|
||||||
var LIFETIME = 3600;
|
var LIFETIME = 3600;
|
||||||
|
|
||||||
tetherballStick = function() {
|
tetherballStick = function() {
|
||||||
_this = this;
|
_this = this;
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tetherballStick.prototype = {
|
tetherballStick.prototype = {
|
||||||
lastCheckForEntities: ENTITY_CHECK_INTERVAL,
|
entityID: NULL_UUID,
|
||||||
originalDimensions: null,
|
|
||||||
ownerID: NULL_UUID,
|
|
||||||
userID: NULL_UUID,
|
|
||||||
ballID: NULL_UUID,
|
ballID: NULL_UUID,
|
||||||
lineID: NULL_UUID,
|
lineID: NULL_UUID,
|
||||||
actionID: NULL_UUID,
|
|
||||||
INTERACT_SOUND: undefined,
|
getUserData: function(key) {
|
||||||
|
try {
|
||||||
|
var stickProps = Entities.getEntityProperties(this.entityID);
|
||||||
|
var userData = JSON.parse(stickProps.userData);
|
||||||
|
return userData[key];
|
||||||
|
} catch (e) {
|
||||||
|
print("Error parsing Tetherball Stick UserData in file " +
|
||||||
|
e.fileName + " on line " + e.lineNumber);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
preload: function(entityID) {
|
preload: function(entityID) {
|
||||||
this.entityID = entityID;
|
this.entityID = entityID;
|
||||||
if (USE_INTERACT_SOUND) {
|
this.ballID = this.getUserData("ballID");
|
||||||
this.INTERACT_SOUND = SoundCache.getSound(INTERACT_SOUND_URL);
|
|
||||||
}
|
|
||||||
this.originalDimensions = Entities.getEntityProperties(this.entityID).dimensions;
|
|
||||||
Script.update.connect(this.update);
|
|
||||||
},
|
|
||||||
|
|
||||||
unload: function() {
|
|
||||||
Script.update.disconnect(this.update);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
update: function(dt) {
|
update: function(dt) {
|
||||||
// _this during update due to loss of scope
|
_this.drawLine();
|
||||||
if (_this.lastCheckForEntities >= ENTITY_CHECK_INTERVAL) {
|
},
|
||||||
_this.lastCheckForEntities = 0;
|
|
||||||
// everyone will be running this update loop
|
|
||||||
// the only action is to increment the timer till ENTITY_CHECK_INTERVAL
|
|
||||||
// when that is reached the userdata ownerID is simply validated by everyone
|
|
||||||
// if it's invalid call setNewOwner, to set a new valid user
|
|
||||||
if (!_this.checkForOwner()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only one person should ever be running this far
|
startEquip: function(id, params) {
|
||||||
if (_this.ownerID == MyAvatar.sessionUUID) {
|
this.removeActions();
|
||||||
_this.checkForEntities();
|
this.createLine();
|
||||||
}
|
|
||||||
|
Script.update.connect(this.update);
|
||||||
|
},
|
||||||
|
|
||||||
|
continueEquip: function(id, params) {
|
||||||
|
var stickProps = Entities.getEntityProperties(this.entityID);
|
||||||
|
var ballProps = Entities.getEntityProperties(this.ballID);
|
||||||
|
var tipPosition = this.getTipPosition();
|
||||||
|
var distance = Vec3.distance(tipPosition, ballProps.position);
|
||||||
|
var maxDistance = ACTION_DISTANCE;
|
||||||
|
|
||||||
|
var dVel = Vec3.subtract(ballProps.velocity, stickProps.velocity);
|
||||||
|
var dPos = Vec3.subtract(ballProps.position, stickProps.position);
|
||||||
|
var ballWithinMaxDistance = distance <= maxDistance;
|
||||||
|
var ballMovingCloserToStick = Vec3.dot(dVel, dPos) < 0;
|
||||||
|
var ballAboveStick = ballProps.position.y > tipPosition.y;
|
||||||
|
|
||||||
|
if(this.hasAction()) {
|
||||||
|
if(ballWithinMaxDistance && (ballMovingCloserToStick || ballAboveStick)) {
|
||||||
|
this.removeActions();
|
||||||
} else {
|
} else {
|
||||||
_this.lastCheckForEntities += dt;
|
this.updateOffsetAction();
|
||||||
}
|
}
|
||||||
|
} else if(!ballWithinMaxDistance && !ballMovingCloserToStick){
|
||||||
|
this.createOffsetAction();
|
||||||
|
}
|
||||||
|
|
||||||
_this.drawLine();
|
this.capBallDistance();
|
||||||
},
|
},
|
||||||
|
|
||||||
getScale: function() {
|
releaseEquip: function(id, params) {
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
this.deleteLine();
|
||||||
return stickProps.dimensions.z / this.originalDimensions.z;
|
this.createSpringAction();
|
||||||
},
|
|
||||||
|
|
||||||
checkForOwner: function() {
|
Script.update.disconnect(this.update);
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
|
||||||
try {
|
|
||||||
var stickData = JSON.parse(stickProps.userData);
|
|
||||||
var owner = AvatarManager.getAvatar(stickData.ownerID);
|
|
||||||
if (owner.sessionUUID !== undefined) {
|
|
||||||
this.ownerID = owner.sessionUUID;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// UUID is invalid
|
|
||||||
this.setNewOwner();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// all other errors
|
|
||||||
this.setNewOwner();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setNewOwner: function() {
|
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
|
||||||
// I only want the closest client to be in charge of creating objects.
|
|
||||||
// the AvatarList also contains a null representing MyAvatar,
|
|
||||||
// a new array is created to start with containing the proper UUID
|
|
||||||
var avatarList = AvatarList.getAvatarIdentifiers()
|
|
||||||
.filter(Boolean) // remove the null
|
|
||||||
.concat(MyAvatar.sessionUUID); // add the ID
|
|
||||||
|
|
||||||
var closestAvatarID = undefined;
|
|
||||||
var closestAvatarDistance = AVATAR_CHECK_RANGE;
|
|
||||||
avatarList.forEach(function(avatarID) {
|
|
||||||
var avatar = AvatarList.getAvatar(avatarID);
|
|
||||||
var distFrom = Vec3.distance(avatar.position, stickProps.position);
|
|
||||||
if (distFrom < closestAvatarDistance) {
|
|
||||||
closestAvatarDistance = distFrom;
|
|
||||||
closestAvatarID = avatarID;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// add reference to userData
|
|
||||||
try {
|
|
||||||
var stickData = JSON.parse(stickProps.userData);
|
|
||||||
stickData.ownerID = closestAvatarID; //NOTE: this will assign undefined if all avatars are further than AVATAR_CHECK_RANGE
|
|
||||||
Entities.editEntity(this.entityID, {
|
|
||||||
userData: JSON.stringify(stickData)
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
checkForEntities: function() {
|
|
||||||
if (!this.hasBall()) {
|
|
||||||
this.createBall();
|
|
||||||
}
|
|
||||||
if (!this.hasAction()) {
|
|
||||||
this.createAction();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
playInteractionSound: function() {
|
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
|
||||||
var INTERACT_SOUND_OPTIONS = {
|
|
||||||
volume: INTERACT_SOUND_VOLUME,
|
|
||||||
loop: false,
|
|
||||||
position: stickProps.position
|
|
||||||
};
|
|
||||||
Audio.playSound(this.INTERACT_SOUND, INTERACT_SOUND_OPTIONS);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getTipPosition: function() {
|
getTipPosition: function() {
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
var stickProps = Entities.getEntityProperties(this.entityID);
|
||||||
|
var stickFront = Quat.getFront(stickProps.rotation);
|
||||||
|
var frontOffset = Vec3.multiply(stickFront, TIP_OFFSET);
|
||||||
|
var tipPosition = Vec3.sum(stickProps.position, frontOffset);
|
||||||
|
|
||||||
var scale = this.getScale();
|
return tipPosition;
|
||||||
var frontVec = Quat.getFront(stickProps.rotation);
|
|
||||||
var frontOffset = Vec3.multiply(frontVec, TIP_OFFSET * scale);
|
|
||||||
var tipPosition = Vec3.sum(stickProps.position, frontOffset);
|
|
||||||
|
|
||||||
return tipPosition;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getStickFrontPosition: function() {
|
getStickFrontPosition: function() {
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
var stickProps = Entities.getEntityProperties(this.entityID);
|
||||||
var stickFront = Quat.getFront(stickProps.rotation);
|
var stickFront = Quat.getFront(stickProps.rotation);
|
||||||
var tipPosition = this.getTipPosition();
|
var tipPosition = this.getTipPosition();
|
||||||
return Vec3.sum(tipPosition, Vec3.multiply(TIP_OFFSET*.4, stickFront));
|
var frontPostion = Vec3.sum(tipPosition, Vec3.multiply(TIP_OFFSET * 0.4, stickFront));
|
||||||
|
|
||||||
|
return frontPostion;
|
||||||
},
|
},
|
||||||
|
|
||||||
capBallDistance: function() {
|
capBallDistance: function() {
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
var stickProps = Entities.getEntityProperties(this.entityID);
|
||||||
var ballProps = Entities.getEntityProperties(this.ballID);
|
var ballProps = Entities.getEntityProperties(this.ballID);
|
||||||
var tipPosition = this.getTipPosition();
|
var tipPosition = this.getTipPosition();
|
||||||
var scale = this.getScale();
|
|
||||||
var distance = Vec3.distance(tipPosition, ballProps.position);
|
var distance = Vec3.distance(tipPosition, ballProps.position);
|
||||||
var maxDistance = ACTION_DISTANCE * MAX_DISTANCE_MULTIPLIER * scale;
|
var maxDistance = ACTION_DISTANCE * MAX_DISTANCE_MULTIPLIER;
|
||||||
|
|
||||||
if(distance > maxDistance) {
|
if(distance > maxDistance) {
|
||||||
var direction = Vec3.normalize(Vec3.subtract(ballProps.position, tipPosition));
|
var direction = Vec3.normalize(Vec3.subtract(ballProps.position, tipPosition));
|
||||||
|
@ -200,175 +129,39 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
startNearGrab: function(id, params) {
|
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
|
||||||
// set variables from data in case someone else created the components
|
|
||||||
try {
|
|
||||||
var stickData = JSON.parse(stickProps.userData);
|
|
||||||
this.userID = MyAvatar.sessionUUID;
|
|
||||||
this.ballID = stickData.ballID;
|
|
||||||
this.actionID = stickData.actionID;
|
|
||||||
if(!this.hasLine()) {
|
|
||||||
this.createLine();
|
|
||||||
}
|
|
||||||
if (USE_INTERACT_SOUND) {
|
|
||||||
var hand = params[0];
|
|
||||||
Controller.triggerShortHapticPulse(1, hand);
|
|
||||||
this.playInteractionSound();
|
|
||||||
}
|
|
||||||
} catch (e) { }
|
|
||||||
},
|
|
||||||
|
|
||||||
releaseGrab: function(id, params) {
|
|
||||||
this.userID = NULL_UUID;
|
|
||||||
if (USE_INTERACT_SOUND) {
|
|
||||||
this.playInteractionSound();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
continueNearGrab: function(id, params) {
|
|
||||||
this.repositionAction();
|
|
||||||
this.updateDimensions();
|
|
||||||
this.capBallDistance();
|
|
||||||
},
|
|
||||||
|
|
||||||
createLine: function() {
|
createLine: function() {
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
if(!this.hasLine()) {
|
||||||
this.lineID = Entities.addEntity({
|
this.lineID = Entities.addEntity({
|
||||||
type: "PolyLine",
|
type: "PolyLine",
|
||||||
name: LINE_NAME,
|
name: "TetherballStick Line",
|
||||||
color: {
|
color: {
|
||||||
red: 0,
|
red: 0,
|
||||||
green: 120,
|
green: 120,
|
||||||
blue: 250
|
blue: 250
|
||||||
},
|
},
|
||||||
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
||||||
position: stickProps.position,
|
position: this.getTipPosition(),
|
||||||
dimensions: {
|
dimensions: {
|
||||||
x: 10,
|
x: 10,
|
||||||
y: 10,
|
y: 10,
|
||||||
z: 10
|
z: 10
|
||||||
},
|
},
|
||||||
lifetime: LIFETIME
|
lifetime: this.getUserData("lifetime")
|
||||||
});
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteLine: function() {
|
deleteLine: function() {
|
||||||
Entities.deleteEntity(this.lineID);
|
Entities.deleteEntity(this.lineID);
|
||||||
this.lineID = NULL_UUID;
|
this.lineID = NULL_UUID;
|
||||||
},
|
},
|
||||||
|
|
||||||
hasLine: function() {
|
hasLine: function() {
|
||||||
var lineProps = Entities.getEntityProperties(this.lineID);
|
return this.lineID != NULL_UUID;
|
||||||
return lineProps.name == LINE_NAME;
|
|
||||||
},
|
|
||||||
|
|
||||||
createBall: function() {
|
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
|
||||||
|
|
||||||
this.ballID = Entities.addEntity({
|
|
||||||
type: "Model",
|
|
||||||
modelURL: "http://hifi-content.s3.amazonaws.com/Examples%20Content/production/marblecollection/Star.fbx",
|
|
||||||
name: BALL_NAME,
|
|
||||||
shapeType: "Sphere",
|
|
||||||
position: this.getStickFrontPosition(),
|
|
||||||
lifetime: LIFETIME,
|
|
||||||
collisionSoundURL: COLLISION_SOUND_URL,
|
|
||||||
dimensions: {
|
|
||||||
x: BALL_SIZE,
|
|
||||||
y: BALL_SIZE,
|
|
||||||
z: BALL_SIZE
|
|
||||||
},
|
|
||||||
gravity: {
|
|
||||||
x: 0.0,
|
|
||||||
y: -9.8,
|
|
||||||
z: 0.0
|
|
||||||
},
|
|
||||||
damping: BALL_DAMPING,
|
|
||||||
angularDamping: BALL_ANGULAR_DAMPING,
|
|
||||||
density: BALL_DENSITY,
|
|
||||||
restitution: BALL_RESTITUTION,
|
|
||||||
dynamic: true,
|
|
||||||
collidesWith: "static,dynamic,otherAvatar,",
|
|
||||||
userData: JSON.stringify({
|
|
||||||
grabbableKey: {
|
|
||||||
grabbable: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
// add reference to userData
|
|
||||||
try {
|
|
||||||
var stickData = JSON.parse(stickProps.userData);
|
|
||||||
stickData.ballID = this.ballID;
|
|
||||||
Entities.editEntity(this.entityID, {
|
|
||||||
userData: JSON.stringify(stickData)
|
|
||||||
});
|
|
||||||
} catch (e) {}
|
|
||||||
},
|
|
||||||
|
|
||||||
hasBall: function() {
|
|
||||||
// validate the userData to handle unexpected item deletion
|
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
|
||||||
try {
|
|
||||||
var data = JSON.parse(stickProps.userData);
|
|
||||||
var ballProps = Entities.getEntityProperties(data.ballID);
|
|
||||||
return ballProps.name == BALL_NAME;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
createAction: function() {
|
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
|
||||||
this.actionID = Entities.addAction("offset", this.ballID, {
|
|
||||||
pointToOffsetFrom: stickProps.position,
|
|
||||||
linearDistance: ACTION_DISTANCE,
|
|
||||||
tag: ACTION_TAG,
|
|
||||||
linearTimeScale: ACTION_TIMESCALE
|
|
||||||
});
|
|
||||||
|
|
||||||
// add reference to userData
|
|
||||||
try {
|
|
||||||
var stickData = JSON.parse(stickProps.userData);
|
|
||||||
stickData.actionID = this.actionID;
|
|
||||||
Entities.editEntity(this.entityID, {
|
|
||||||
userData: JSON.stringify(stickData)
|
|
||||||
});
|
|
||||||
} catch (e) {}
|
|
||||||
},
|
|
||||||
|
|
||||||
hasAction: function() {
|
|
||||||
// validate the userData to handle unexpected item deletion
|
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
|
||||||
try {
|
|
||||||
var stickData = JSON.parse(stickProps.userData);
|
|
||||||
var actionProps = Entities.getActionArguments(stickData.ballID, stickData.actionID);
|
|
||||||
return actionProps.tag == ACTION_TAG;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
hasRequiredComponents: function() {
|
|
||||||
return this.hasBall() && this.hasAction() && this.hasLine();
|
|
||||||
},
|
|
||||||
|
|
||||||
updateDimensions: function() {
|
|
||||||
var scale = this.getScale();
|
|
||||||
Entities.editEntity(this.ballID, {
|
|
||||||
dimensions: {
|
|
||||||
x: BALL_SIZE * scale,
|
|
||||||
y: BALL_SIZE * scale,
|
|
||||||
z: BALL_SIZE * scale
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
drawLine: function() {
|
drawLine: function() {
|
||||||
if(!this.hasLine())
|
if(this.hasLine()) {
|
||||||
return;
|
|
||||||
|
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
var stickProps = Entities.getEntityProperties(this.entityID);
|
||||||
var tipPosition = this.getTipPosition();
|
var tipPosition = this.getTipPosition();
|
||||||
var ballProps = Entities.getEntityProperties(this.ballID);
|
var ballProps = Entities.getEntityProperties(this.ballID);
|
||||||
|
@ -390,19 +183,59 @@
|
||||||
strokeWidths: strokeWidths,
|
strokeWidths: strokeWidths,
|
||||||
position: tipPosition,
|
position: tipPosition,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
repositionAction: function() {
|
createOffsetAction: function() {
|
||||||
var stickProps = Entities.getEntityProperties(this.entityID);
|
this.removeActions();
|
||||||
var tipPosition = this.getTipPosition();
|
|
||||||
var scale = this.getScale();
|
|
||||||
|
|
||||||
Entities.updateAction(this.ballID, this.actionID, {
|
Entities.addAction("offset", this.ballID, {
|
||||||
pointToOffsetFrom: tipPosition,
|
pointToOffsetFrom: this.getTipPosition(),
|
||||||
linearDistance: ACTION_DISTANCE * scale,
|
linearDistance: ACTION_DISTANCE,
|
||||||
tag: ACTION_TAG,
|
linearTimeScale: ACTION_TIMESCALE
|
||||||
linearTimeScale: ACTION_TIMESCALE
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
createSpringAction: function() {
|
||||||
|
this.removeActions();
|
||||||
|
|
||||||
|
Entities.addAction("spring", this.ballID, {
|
||||||
|
targetPosition: this.getTipPosition(),
|
||||||
|
linearTimeScale: ACTION_TIMESCALE
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateOffsetAction: function() {
|
||||||
|
var actionIDs = Entities.getActionIDs(this.ballID);
|
||||||
|
var actionID;
|
||||||
|
|
||||||
|
// Sometimes two offset actions are applied to the ball simultaneously.
|
||||||
|
// Here we ensure that only the most recent action is updated
|
||||||
|
// and the rest are deleted.
|
||||||
|
while(actionIDs.length > 1) {
|
||||||
|
actionID = actionIDs.shift();
|
||||||
|
Entities.deleteAction(this.ballID, actionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
actionID = actionIDs.shift();
|
||||||
|
if(actionID) {
|
||||||
|
Entities.updateAction(this.ballID, actionID, {
|
||||||
|
pointToOffsetFrom: this.getTipPosition()
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
removeActions: function() {
|
||||||
|
// Ball should only ever have one action, but sometimes sneaky little actions attach themselves
|
||||||
|
// So we remove all possible actions in this call.
|
||||||
|
var actionIDs = Entities.getActionIDs(this.ballID);
|
||||||
|
for(var i = 0; i < actionIDs.length; i++) {
|
||||||
|
Entities.deleteAction(this.ballID, actionIDs[i]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hasAction: function() {
|
||||||
|
return Entities.getActionIDs(this.ballID).length > 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue