diff --git a/scripts/tutorials/createTetherballStick.js b/scripts/tutorials/createTetherballStick.js new file mode 100644 index 0000000000..8d36d8ee59 --- /dev/null +++ b/scripts/tutorials/createTetherballStick.js @@ -0,0 +1,153 @@ +"use strict"; +/* jslint vars: true, plusplus: true, forin: true*/ +/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ +// +// createTetherballStick.js +// +// Created by Triplelexx on 17/03/04 +// Updated by MrRoboman on 17/03/26 +// Copyright 2017 High Fidelity, Inc. +// +// Creates an equippable stick with a tethered ball +// +// Distributed under the Apache License, Version 2.0. +// 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 ACTION_DISTANCE = 0.35; +var ACTION_TIMESCALE = 0.035; +var MAX_DISTANCE_MULTIPLIER = 4; +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 COLLISION_SOUND_URL = "http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav"; + +var avatarOrientation = MyAvatar.orientation; +avatarOrientation = Quat.safeEulerAngles(avatarOrientation); +avatarOrientation.x = 0; +avatarOrientation = Quat.fromVec3Degrees(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 lineID = Entities.addEntity({ + type: "PolyLine", + name: "TetherballStick Line", + color: { + red: 0, + green: 120, + blue: 250 + }, + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + position: ballStartPosition, + dimensions: { + x: 10, + y: 10, + z: 10 + }, + lifetime: LIFETIME +}); + +var actionID = Entities.addAction("offset", ballID, { + pointToOffsetFrom: stickStartPosition, + linearDistance: ACTION_DISTANCE, + linearTimeScale: ACTION_TIMESCALE +}); + +var STICK_PROPERTIES = { + type: 'Model', + name: "TetherballStick Stick", + modelURL: STICK_MODEL_URL, + position: stickStartPosition, + rotation: MyAvatar.orientation, + dimensions: { + x: 0.0651, + y: 0.0651, + z: 0.5270 + }, + script: STICK_SCRIPT_URL, + color: { + red: 200, + green: 0, + blue: 20 + }, + shapeType: 'box', + lifetime: LIFETIME, + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true, + ignoreIK: false + }, + 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, + lineID: lineID, + actionID: actionID, + lifetime: LIFETIME, + maxDistanceBetweenBallAndStick: ACTION_DISTANCE * MAX_DISTANCE_MULTIPLIER + }) +}; + +Entities.addEntity(STICK_PROPERTIES); +Script.stop(); diff --git a/scripts/tutorials/entity_scripts/tetherballStick.js b/scripts/tutorials/entity_scripts/tetherballStick.js new file mode 100644 index 0000000000..867074abd4 --- /dev/null +++ b/scripts/tutorials/entity_scripts/tetherballStick.js @@ -0,0 +1,140 @@ +"use strict"; +/* jslint vars: true, plusplus: true, forin: true*/ +/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ +// +// tetherballStick.js +// +// Created by Triplelexx on 17/03/04 +// Updated by MrRoboman on 17/03/26 +// Copyright 2017 High Fidelity, Inc. +// +// Entity script for an equippable stick with a tethered ball +// +// 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 LIFETIME_IF_LEAVE_DOMAIN = 2; + var LINE_WIDTH = 0.02; + var COLLISION_SOUND_URL = "http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav"; + var TIP_OFFSET = 0.26; + + tetherballStick = function() { + _this = this; + }; + + tetherballStick.prototype = { + + getUserData: function() { + try { + var stickProps = Entities.getEntityProperties(this.entityID); + var userData = JSON.parse(stickProps.userData); + return userData; + } catch (e) { + print("Error parsing Tetherball Stick UserData in file " + + e.fileName + " on line " + e.lineNumber); + } + }, + + preload: function(entityID) { + this.entityID = entityID; + + var userData = this.getUserData(); + this.ballID = userData.ballID; + this.lineID = userData.lineID; + this.actionID = userData.actionID; + this.maxDistanceBetweenBallAndStick = userData.maxDistanceBetweenBallAndStick; + }, + + update: function(dt) { + _this.drawLine(); + }, + + startEquip: function() { + Script.update.disconnect(this.update); + }, + + continueEquip: function(id, params) { + var stickProps = Entities.getEntityProperties(this.entityID); + [this.entityID, this.ballID, this.lineID].forEach(function(id) { + Entities.editEntity(id, { + lifetime: stickProps.age + LIFETIME_IF_LEAVE_DOMAIN + }); + }); + this.updateOffsetAction(); + this.capBallDistance(); + this.drawLine(); + }, + + releaseEquip: function() { + var userData = this.getUserData(); + [this.entityID, this.ballID, this.lineID].forEach(function(id) { + Entities.editEntity(id, { + lifetime: userData.lifetime + }); + }); + Script.update.connect(this.update); + }, + + getTipPosition: function() { + 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); + + return tipPosition; + }, + + updateOffsetAction: function() { + Entities.updateAction(this.ballID, this.actionID, { + pointToOffsetFrom: this.getTipPosition() + }); + }, + + capBallDistance: function() { + 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 = this.maxDistanceBetweenBallAndStick; + + if(distance > maxDistance) { + var direction = Vec3.normalize(Vec3.subtract(ballProps.position, tipPosition)); + var newPosition = Vec3.sum(tipPosition, Vec3.multiply(maxDistance, direction)); + Entities.editEntity(this.ballID, { + position: newPosition + }) + } + }, + + drawLine: function() { + var stickProps = Entities.getEntityProperties(this.entityID); + var tipPosition = this.getTipPosition(); + var ballProps = Entities.getEntityProperties(this.ballID); + var cameraQuat = Vec3.multiplyQbyV(Camera.getOrientation(), Vec3.UNIT_NEG_Z); + var linePoints = []; + var normals = []; + var strokeWidths = []; + linePoints.push(Vec3.ZERO); + normals.push(cameraQuat); + strokeWidths.push(LINE_WIDTH); + linePoints.push(Vec3.subtract(ballProps.position, tipPosition)); + normals.push(cameraQuat); + strokeWidths.push(LINE_WIDTH); + + var lineProps = Entities.getEntityProperties(this.lineID); + Entities.editEntity(this.lineID, { + linePoints: linePoints, + normals: normals, + strokeWidths: strokeWidths, + position: tipPosition, + }); + } + }; + + // entity scripts should return a newly constructed object of our type + return new tetherballStick(); +});