// // golfClub.js // // Created by Philip Rosedale on April 11, 2016. // Some modifications by Thijs Wenker on Octobre 14, 2016 // 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 // // 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 = "http://hifi-production.s3.amazonaws.com/tutorials/golfClub/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 CLIENT_ONLY_BALL = false; var TRIGGER_CONTROLS = [ Controller.Standard.LT, Controller.Standard.RT, ]; function lowercaseFirstLetter(capitalizedString) { return capitalizedString.charAt(0).toLowerCase() + capitalizedString.slice(1); } // http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb function hexToRgb(hex) { // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; hex = hex.replace(shorthandRegex, function(m, r, g, b) { return r + r + g + g + b + b; }); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { red: parseInt(result[1], 16), green: parseInt(result[2], 16), blue: parseInt(result[3], 16) } : null; } 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 ballModel(clubID) { try { return JSON.parse(Entities.getEntityProperties(clubID, ['userData']).userData).ballModel; } catch (e) { } return null; } 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, color) { var firstLowerCaseColor = lowercaseFirstLetter(color); // Create a new sphere entity ball = Entities.addEntity({ type: 'Model', position: position, name: 'Ball - ' + color, 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, collisionsWillMove: true, modelURL: 'http://hifi-content.s3.amazonaws.com/caitlyn/production/minigolf%20course/putters/newBall.fbx', textures: JSON.stringify({ file4: 'http://hifi-content.s3.amazonaws.com/caitlyn/production/minigolf course/putters/ball_' + firstLowerCaseColor + '.png', file5: 'http://hifi-content.s3.amazonaws.com/caitlyn/production/minigolf course/putters/newBall.fbx/C:/Users/User/Documents/Substance Painter 2/export/lambert1_Normal_OpenGL.png', file6: 'http://hifi-content.s3.amazonaws.com/caitlyn/production/minigolf course/putters/newBall.fbx/C:/Users/User/Documents/Substance Painter 2/export/lambert1_Metallic.png', file7: 'http://hifi-content.s3.amazonaws.com/caitlyn/production/minigolf course/putters/newBall.fbx/C:/Users/User/Documents/Substance Painter 2/export/lambert1_Roughness.png', file8: 'http://hifi-content.s3.amazonaws.com/caitlyn/production/minigolf course/putters/newBall.fbx/C:/Users/User/Documents/Substance Painter 2/export/lambert1_Ambient_occlusion.png' }), collisionSoundURL: collisionSoundURL }, CLIENT_ONLY_BALL); } function checkClub(clubID, params) { var hand = params[0] == "left" ? 0 : 1; var makeNewBall = false; if (triggerPulled(hand)) { // If trigger just pulled, either drop new ball if (ball !== null) { Entities.deleteEntity(ball); } makeBall(inFrontOfMe(), ballModel(clubID)); } brakeBall(ball); } this.continueEquip = function(id, params) { // While holding the club, continuously check for trigger pull and brake ball if moving. checkClub(id, params); } this.startEquip = function(id, params) { var hand = params[0]; Messages.sendLocalMessage('Hifi-Teleport-Disabler', hand); } this.release = function() { Messages.sendLocalMessage('Hifi-Teleport-Disabler', 'none'); } });