From c67eafffba8c0398dc3098a1e75cce8907d64a04 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 20 Oct 2015 16:59:03 -0700 Subject: [PATCH] Add pitching.js --- examples/pitching.js | 365 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 365 insertions(+) create mode 100644 examples/pitching.js diff --git a/examples/pitching.js b/examples/pitching.js new file mode 100644 index 0000000000..046113cbc3 --- /dev/null +++ b/examples/pitching.js @@ -0,0 +1,365 @@ +//var PITCH_THUNK_SOUND_URL = "file:///C:/Users/Ryan/Downloads/323725__reitanna__thunk.wav"; +var PITCH_THUNK_SOUND_URL = "file:///C:/Users/Ryan/Downloads/thunk.wav"; +var PITCH_THUNK_SOUND_URL = "http://hifi-public.s3.amazonaws.com/sounds/ping_pong_gun/pong_sound.wav"; +var pitchSound = SoundCache.getSound(PITCH_THUNK_SOUND_URL, false); + +function info(message) { + print("[INFO] " + message); +} + +function error(message) { + print("[ERROR] " + message); +} + +var PITCHING_MACHINE_URL = "atp:87d4879530b698741ecc45f6f31789aac11f7865a2c3bec5fe9b061a182c80d4.fbx"; +var PITCHING_MACHINE_OUTPUT_OFFSET_PCT = { + x: 0.0, + y: 0.25, + z: -1.05, +}; +var PITCHING_MACHINE_PROPERTIES = { + name: "Pitching Machine", + type: "Model", + position: { + x: 0, + y: 0.8, + z: -22.3, + }, + velocity: { + x: 0, + y: -0.01, + z: 0 + }, + gravity: { + x: 0.0, + y: -9.8, + z: 0.0 + }, + registrationPoint: { + x: 0.5, + y: 0.5, + z: 0.5, + }, + rotation: Quat.fromPitchYawRollDegrees(0, 180, 0), + modelURL: PITCHING_MACHINE_URL, + dimensions: { + x: 0.4, + y: 0.61, + z: 0.39 + }, + collisionsWillMove: false, + shapeType: "Box", +}; +PITCHING_MACHINE_PROPERTIES.dimensions = Vec3.multiply(2.5, PITCHING_MACHINE_PROPERTIES.dimensions); + + +var PITCH_RATE = 5000; + +var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx"; +var BASEBALL_SPEED = 2.7; +var BASEBALL_RADIUS = 0.07468; +var BASEBALL_PROPERTIES = { + name: "Baseball", + type: "Model", + modelURL: BASEBALL_MODEL_URL, + shapeType: "Sphere", + position: { + x: 0, + y: 0, + z: 0 + }, + dimensions: { + x: BASEBALL_RADIUS, + y: BASEBALL_RADIUS, + z: BASEBALL_RADIUS + }, + collisionsWillMove: true, + angularVelocity: { + x: 17.0, + y: 0, + z: -8.0, + }, + angularDamping: 0.0, + damping: 0.0, + restitution: 0.5, + friction: 0.0, + lifetime: 20, + collisionSoundURL: PITCH_THUNK_SOUND_URL, + gravity: { + x: 0, + y: 0,//-9.8, + z: 0 + } +}; + + +var pitchingMachineID = Entities.addEntity(PITCHING_MACHINE_PROPERTIES); + +var pitchFromPosition = { x: 0, y: 1.0, z: 0 }; +var pitchDirection = { x: 0, y: 0, z: 1 }; + +function shallowCopy(obj) { + var copy = {} + for (var key in obj) { + copy[key] = obj[key]; + } + return copy; +} + +function randomInt(low, high) { + return low + (Math.random() * (high - low)); +} + +var ACCELERATION_SPREAD = 10.15; + +function createBaseball(position, velocity, ballScale) { + var properties = shallowCopy(BASEBALL_PROPERTIES); + properties.position = position; + properties.velocity = velocity; + properties.acceleration = { + x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + z: 0.0, + }; + properties.dimensions = Vec3.multiply(ballScale, properties.dimensions); + var entityID = Entities.addEntity(properties); + Script.addEventHandler(entityID, "collisionWithEntity", buildBaseballHitCallback(entityID)); + if (false && Math.random() < 0.5) { + for (var i = 0; i < 50; i++) { + Script.setTimeout(function() { + Entities.editEntity(entityID, { + gravity: { + x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + z: 0.0, + } + }) + }, i * 100); + } + } + return entityID; +} + +var buildBaseballHitCallback = function(entityID) { + var f = function(entityA, entityB, collision) { + var properties = Entities.getEntityProperties(entityID, ['position', 'velocity']); + var line = new InfiniteLine(properties.position, { red: 255, green: 128, blue: 89 }); + var lastPosition = properties.position; + Vec3.print("Velocity", properties.velocity); + Vec3.print("VelocityChange", collision.velocityChange); + Script.setInterval(function() { + var properties = Entities.getEntityProperties(entityID, ['position']); + if (Vec3.distance(properties.position, lastPosition)) { + line.enqueuePoint(properties.position); + lastPosition = properties.position; + } + }, 50); + Entities.editEntity(entityID, { + velocity: Vec3.multiply(3, properties.velocity), + gravity: { + x: 0, + y: -2.8, + z: 0 + } + }); + print("Baseball hit!"); + Script.removeEventHandler(entityID, "collisionWithEntity", f); + }; + return f; +} + + +function vec3Mult(a, b) { + return { + x: a.x * b.x, + y: a.y * b.y, + z: a.z * b.z, + }; +} + +var injector = null; +function pitchBall() { + var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); + var pitchFromPositionBase = machineProperties.position; + var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); + pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset); + var pitchFromPosition = Vec3.sum(pitchFromPositionBase, pitchFromOffset); + var pitchDirection = Quat.getFront(machineProperties.rotation); + var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x; + print("Creating baseball"); + var ballEntityID = createBaseball(pitchFromPosition, Vec3.multiply(BASEBALL_SPEED, pitchDirection), ballScale); + if (!injector) { + injector = Audio.playSound(pitchSound, { + position: pitchFromPosition, + volume: 1.0 + }); + } else { + injector.restart(); + } +} + +Script.scriptEnding.connect(function() { + Entities.deleteEntity(pitchingMachineID); +}) + +Script.setInterval(pitchBall, PITCH_RATE); + + + + +/****************************************************************************** + * PolyLine + *****************************************************************************/ +var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 }; +var MAX_LINE_LENGTH = 40; // This must be 2 or greater; +var PolyLine = function(position, color, defaultStrokeWidth) { + //info("Creating polyline"); + //Vec3.print("New line at", position); + this.position = position; + this.color = color; + this.defaultStrokeWidth = 0.10; + this.points = [ + { x: 0, y: 0, z: 0 }, + ]; + this.strokeWidths = [ + this.defaultStrokeWidth, + ] + this.normals = [ + { x: 1, y: 0, z: 0 }, + ] + this.entityID = Entities.addEntity({ + type: "PolyLine", + position: position, + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + dimensions: LINE_DIMENSIONS, + color: color, + lifetime: 20, + }); +}; + +PolyLine.prototype.enqueuePoint = function(position) { + if (this.isFull()) { + error("Hit max PolyLine size"); + return; + } + + //Vec3.print("pos", position); + //info("Number of points: " + this.points.length); + + position = Vec3.subtract(position, this.position); + this.points.push(position); + this.normals.push({ x: 1, y: 0, z: 0 }); + this.strokeWidths.push(this.defaultStrokeWidth); + Entities.editEntity(this.entityID, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + }); +}; + +PolyLine.prototype.dequeuePoint = function() { + if (this.points.length == 0) { + error("Hit min PolyLine size"); + return; + } + + this.points = this.points.slice(1); + this.normals = this.normals.slice(1); + this.strokeWidths = this.strokeWidths.slice(1); + + Entities.editEntity(this.entityID, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + }); +}; + +PolyLine.prototype.getFirstPoint = function() { + return Vec3.sum(this.position, this.points[0]); +}; + +PolyLine.prototype.getLastPoint = function() { + return Vec3.sum(this.position, this.points[this.points.length - 1]); +}; + +PolyLine.prototype.getSize = function() { + return this.points.length; +} + +PolyLine.prototype.isFull = function() { + return this.points.length >= MAX_LINE_LENGTH; +}; + +PolyLine.prototype.destroy = function() { + Entities.deleteEntity(this.entityID); + this.points = []; +}; + + +/****************************************************************************** + * InfiniteLine + *****************************************************************************/ +InfiniteLine = function(position, color) { + this.position = position; + this.color = color; + this.lines = [new PolyLine(position, color)]; + this.size = 0; +}; + +InfiniteLine.prototype.enqueuePoint = function(position) { + var currentLine; + + if (this.lines.length == 0) { + currentLine = new PolyLine(position, this.color); + this.lines.push(currentLine); + } else { + currentLine = this.lines[this.lines.length - 1]; + } + + if (currentLine.isFull()) { + //info("Current line is full, creating new line"); + //Vec3.print("Last line is", currentLine.getLastPoint()); + //Vec3.print("New line is", position); + var newLine = new PolyLine(currentLine.getLastPoint(), this.color); + this.lines.push(newLine); + currentLine = newLine; + } + + currentLine.enqueuePoint(position); + + ++this.size; +}; + +InfiniteLine.prototype.dequeuePoint = function() { + if (this.lines.length == 0) { + error("Trying to dequeue from InfiniteLine when no points are left"); + return; + } + + var lastLine = this.lines[0]; + lastLine.dequeuePoint(); + + if (lastLine.getSize() <= 1) { + this.lines = this.lines.slice(1); + } + + --this.size; +}; + +InfiniteLine.prototype.getFirstPoint = function() { + return this.lines.length > 0 ? this.lines[0].getFirstPoint() : null; +}; + +InfiniteLine.prototype.getLastPoint = function() { + return this.lines.length > 0 ? this.lines[lines.length - 1].getLastPoint() : null; +}; + +InfiniteLine.prototype.destroy = function() { + for (var i = 0; i < this.lines.length; ++i) { + this.lines[i].destroy(); + } + + this.size = 0; +};