// // golfClub.js // // Created by Philip Rosedale on April 11, 2016. // Copyright 2015 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 // // A simple golf club. If you have equipped it, and pull trigger, it will either make // you a new golf ball, or take you to your ball if one is not made. (function () { var ball = null; var collisionSoundURL = Script.getExternalPath(Script.ExternalPaths.Assets, "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav"); var triggerState = false; var BALL_GRAVITY = -9.8; var BALL_START_VELOCITY = 0.1; var BALL_MAX_RANGE = 10; var BALL_DROP_DISTANCE = 0.6; var BALL_DIAMETER = 0.07; var BALL_LIFETIME = 3600; var MAX_BRAKING_SPEED = 0.2; var BALL_BRAKING_RATE = 0.5; var TRIGGER_CONTROLS = [ Controller.Standard.LT, Controller.Standard.RT, ]; function triggerPulled(hand) { // Return true if the trigger has just been pulled var triggerValue = Controller.getValue(TRIGGER_CONTROLS[hand]); var oldTriggerState = triggerState; var TRIGGER_PULL_THRESHOLD = 0.5; var TRIGGER_RELEASE_THRESHOLD = 0.4; if (triggerValue > TRIGGER_PULL_THRESHOLD) { triggerState = true; } else if (triggerValue < TRIGGER_RELEASE_THRESHOLD) { triggerState = false; } return (triggerState && (oldTriggerState != triggerState)); } function ballPosition(ball) { // return the position of this entity var properties = Entities.getEntityProperties(ball, ['position']); if (!properties) { return null; } else { return properties.position; } } function gotoPointOnGround(position, away) { // Position yourself facing in the direction you were originally facing, but with a // point on the ground *away* meters from *position* and in front of you. var offset = Quat.getFront(MyAvatar.orientation); offset.y = 0.0; offset = Vec3.multiply(-away, Vec3.normalize(offset)); var newAvatarPosition = Vec3.sum(position, offset); // Assuming position is on ground, put me distance from eyes to hips higher, plus a 50% adjust for longer legs. // TODO: Need avatar callback for exact foot-to-hips height. var halfHeight = avatarHalfHeight(); print("Height = " + halfHeight); newAvatarPosition.y += (halfHeight * 1.5); MyAvatar.position = newAvatarPosition; } function inFrontOfMe() { return Vec3.sum(MyAvatar.position, Vec3.multiply(BALL_DROP_DISTANCE, Quat.getFront(MyAvatar.orientation))); } function avatarHalfHeight() { return MyAvatar.getDefaultEyePosition().y - MyAvatar.position.y; } function brakeBall(ball) { // Check the ball's velocity and slow it down if beyond a threshold var properties = Entities.getEntityProperties(ball, ['velocity']); if (properties) { var velocity = Vec3.length(properties.velocity); if ((velocity > 0) && (velocity < MAX_BRAKING_SPEED)) { Entities.editEntity(ball, { velocity: Vec3.multiply(BALL_BRAKING_RATE, properties.velocity) }); } } } function makeBall(position) { // Create a new sphere entity ball = Entities.addEntity({ type: "Sphere", position: position, color: { red: 255, green: 255, blue: 255 }, dimensions: { x: BALL_DIAMETER, y: BALL_DIAMETER, z: BALL_DIAMETER }, gravity: { x: 0, y: BALL_GRAVITY, z: 0 }, velocity: { x: 0, y: BALL_START_VELOCITY, z: 0 }, friction: 0.5, restitution: 0.5, shapeType: "sphere", dynamic: true, lifetime: BALL_LIFETIME, collisionSoundURL: collisionSoundURL }); } function checkClub(params) { var hand = params[0] == "left" ? 0 : 1; var makeNewBall = false; if (triggerPulled(hand)) { // If trigger just pulled, either drop new ball or go to existing one var position = ballPosition(ball); if (position && (Vec3.distance(MyAvatar.position, position) < BALL_MAX_RANGE)) { gotoPointOnGround(position, BALL_DROP_DISTANCE); } else { Entities.deleteEntity(ball); makeBall(inFrontOfMe()); } } brakeBall(ball); } this.continueEquip = function(id, params) { // While holding the club, continuously check for trigger pull and brake ball if moving. checkClub(params); } });