mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 13:17:53 +02:00
Attach the wand.js script to an entity and then move it around to make bubbles. Customize bubble behavior with bubble.js - make sure to update the path reference in wand.js
This commit is contained in:
parent
cd1dac50ad
commit
80c18c227e
2 changed files with 382 additions and 0 deletions
39
examples/toys/bubblewand/bubble.js
Normal file
39
examples/toys/bubblewand/bubble.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
(function() {
|
||||
|
||||
var popSound;
|
||||
this.preload = function(entityID) {
|
||||
// console.log('bubble preload')
|
||||
this.entityID = entityID;
|
||||
popSound = SoundCache.getSound("http://hifi-public.s3.amazonaws.com/james/bubblewand/sounds/pop.wav");
|
||||
|
||||
}
|
||||
|
||||
this.collisionWithEntity = function(myID, otherID, collision) {
|
||||
|
||||
Entities.deleteEntity(myID);
|
||||
this.burstBubbleSound(collision.contactPoint)
|
||||
|
||||
};
|
||||
|
||||
this.unload = function(entityID) {
|
||||
// console.log('bubble unload')
|
||||
// this.properties = Entities.getEntityProperties(entityID);
|
||||
//var location = this.properties.position;
|
||||
//this.burstBubbleSound();
|
||||
};
|
||||
|
||||
|
||||
|
||||
this.burstBubbleSound = function(location) {
|
||||
|
||||
var audioOptions = {
|
||||
volume: 0.5,
|
||||
position: location
|
||||
}
|
||||
|
||||
//Audio.playSound(popSound, audioOptions);
|
||||
|
||||
}
|
||||
|
||||
|
||||
})
|
343
examples/toys/bubblewand/wand.js
Normal file
343
examples/toys/bubblewand/wand.js
Normal file
|
@ -0,0 +1,343 @@
|
|||
// wand.js
|
||||
// part of bubblewand
|
||||
//
|
||||
// Created by James B. Pollack @imgntn -- 09/03/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Makes bubbles when you wave the object around, or hold it near your mouth and make noise into the microphone.
|
||||
//
|
||||
// For the example, it's attached to a wand -- but you can attach it to whatever entity you want. I dream of BubbleBees :) bzzzz...pop!
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
function randInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
|
||||
|
||||
function convertRange(value, r1, r2) {
|
||||
return (value - r1[0]) * (r2[1] - r2[0]) / (r1[1] - r1[0]) + r2[0];
|
||||
}
|
||||
|
||||
// helpers -- @zappoman
|
||||
// Computes the penetration between a point and a sphere (centered at the origin)
|
||||
// if point is inside sphere: returns true and stores the result in 'penetration'
|
||||
// (the vector that would move the point outside the sphere)
|
||||
// otherwise returns false
|
||||
function findSphereHit(point, sphereRadius) {
|
||||
var EPSILON = 0.000001; //smallish positive number - used as margin of error for some computations
|
||||
var vectorLength = Vec3.length(point);
|
||||
if (vectorLength < EPSILON) {
|
||||
return true;
|
||||
}
|
||||
var distance = vectorLength - sphereRadius;
|
||||
if (distance < 0.0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function findSpherePointHit(sphereCenter, sphereRadius, point) {
|
||||
return findSphereHit(Vec3.subtract(point, sphereCenter), sphereRadius);
|
||||
}
|
||||
|
||||
function findSphereSphereHit(firstCenter, firstRadius, secondCenter, secondRadius) {
|
||||
return findSpherePointHit(firstCenter, firstRadius + secondRadius, secondCenter);
|
||||
}
|
||||
|
||||
(function() {
|
||||
var console = {};
|
||||
console.log = function(p) {
|
||||
if (arguments.length > 1) {
|
||||
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
print(arguments[i])
|
||||
}
|
||||
|
||||
} else {
|
||||
print(p)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var bubbleModel = "http://hifi-public.s3.amazonaws.com/james/bubblewand/models/bubble/bubble.fbx";
|
||||
var bubbleScript = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/scripts/bubble.js?' + randInt(2, 5096);
|
||||
var popSound = SoundCache.getSound("http://hifi-public.s3.amazonaws.com/james/bubblewand/sounds/pop.wav");
|
||||
var wandModel = "http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/wand.fbx";
|
||||
|
||||
|
||||
|
||||
var targetSize = 0.4;
|
||||
var targetColor = {
|
||||
red: 128,
|
||||
green: 128,
|
||||
blue: 128
|
||||
};
|
||||
var targetColorHit = {
|
||||
red: 0,
|
||||
green: 255,
|
||||
blue: 0
|
||||
};
|
||||
var moveCycleColor = {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var handSize = 0.25;
|
||||
var leftCubePosition = MyAvatar.getLeftPalmPosition();
|
||||
var rightCubePosition = MyAvatar.getRightPalmPosition();
|
||||
|
||||
var RIGHT_FRONT = 512;
|
||||
|
||||
var leftHand = Overlays.addOverlay("cube", {
|
||||
position: leftCubePosition,
|
||||
size: handSize,
|
||||
color: {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 255
|
||||
},
|
||||
alpha: 1,
|
||||
solid: false
|
||||
});
|
||||
|
||||
var rightHand = Overlays.addOverlay("cube", {
|
||||
position: rightCubePosition,
|
||||
size: handSize,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0
|
||||
},
|
||||
alpha: 1,
|
||||
solid: false
|
||||
});
|
||||
|
||||
var gustZoneOverlay = Overlays.addOverlay("cube", {
|
||||
position: getGustDetectorPosition(),
|
||||
size: targetSize,
|
||||
color: targetColor,
|
||||
alpha: 1,
|
||||
solid: false
|
||||
});
|
||||
|
||||
|
||||
function getGustDetectorPosition() {
|
||||
var DISTANCE_IN_FRONT = 0.2;
|
||||
var DISTANCE_UP = 0.5;
|
||||
var DISTANCE_TO_SIDE = 0.0;
|
||||
|
||||
var up = Quat.getUp(MyAvatar.orientation);
|
||||
var front = Quat.getFront(MyAvatar.orientation);
|
||||
var right = Quat.getRight(MyAvatar.orientation);
|
||||
|
||||
var upOffset = Vec3.multiply(up, DISTANCE_UP);
|
||||
var rightOffset = Vec3.multiply(right, DISTANCE_TO_SIDE);
|
||||
var frontOffset = Vec3.multiply(front, DISTANCE_IN_FRONT);
|
||||
|
||||
var offset = Vec3.sum(Vec3.sum(rightOffset, frontOffset), upOffset);
|
||||
var position = Vec3.sum(MyAvatar.position, offset);
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
var BUBBLE_GRAVITY = {
|
||||
x: 0,
|
||||
y: -0.05,
|
||||
z: 0
|
||||
}
|
||||
|
||||
|
||||
var thisEntity = this;
|
||||
|
||||
this.preload = function(entityID) {
|
||||
print('PRELOAD')
|
||||
this.entityID = entityID;
|
||||
this.properties = Entities.getEntityProperties(this.entityID);
|
||||
BubbleWand.lastPosition = this.properties.position;
|
||||
}
|
||||
|
||||
this.unload = function(entityID) {
|
||||
Overlays.deleteOverlay(leftHand);
|
||||
Overlays.deleteOverlay(rightHand);
|
||||
Overlays.deleteOverlay(rightFront)
|
||||
Entities.editEntity(entityID, {
|
||||
name: ""
|
||||
});
|
||||
Script.update.disconnect(BubbleWand.update);
|
||||
collectGarbage();
|
||||
};
|
||||
|
||||
|
||||
var BubbleWand = {
|
||||
bubbles: [],
|
||||
currentBubble: null,
|
||||
update: function() {
|
||||
BubbleWand.updateControllerState();
|
||||
},
|
||||
updateControllerState: function() {
|
||||
var _t = this;
|
||||
var properties = Entities.getEntityProperties(thisEntity.entityID);
|
||||
var wandPosition = properties.position;
|
||||
|
||||
var leftHandPos = MyAvatar.getLeftPalmPosition();
|
||||
var rightHandPos = MyAvatar.getRightPalmPosition();
|
||||
|
||||
Overlays.editOverlay(leftHand, {
|
||||
position: leftHandPos
|
||||
});
|
||||
Overlays.editOverlay(rightHand, {
|
||||
position: rightHandPos
|
||||
});
|
||||
|
||||
//not really a sphere...
|
||||
var hitTargetWithWand = findSphereSphereHit(wandPosition, handSize / 2, getGustDetectorPosition(), targetSize / 2)
|
||||
|
||||
var mouthMode;
|
||||
if (hitTargetWithWand) {
|
||||
Overlays.editOverlay(gustZoneOverlay, {
|
||||
position: getGustDetectorPosition(),
|
||||
color: targetColorHit
|
||||
})
|
||||
mouthMode = true;
|
||||
|
||||
} else {
|
||||
Overlays.editOverlay(gustZoneOverlay, {
|
||||
position: getGustDetectorPosition(),
|
||||
color: targetColor
|
||||
})
|
||||
mouthMode=false;
|
||||
}
|
||||
|
||||
var velocity = Vec3.subtract(wandPosition,BubbleWand.lastPosition)
|
||||
|
||||
|
||||
|
||||
_t.lastPosition = wandPosition;
|
||||
|
||||
//print('VELOCITY:::'+JSON.stringify(velocity))
|
||||
var velocityStrength = Vec3.length(velocity) *100;
|
||||
print('velocityStrength::' + velocityStrength);
|
||||
//todo: angular velocity without the controller
|
||||
// var angularVelocity = Controller.getSpatialControlRawAngularVelocity(hands.leftHand.tip);
|
||||
var dimensions = Entities.getEntityProperties(_t.currentBubble).dimensions;
|
||||
|
||||
var volumeLevel = MyAvatar.audioAverageLoudness;
|
||||
var convertedVolume = convertRange(volumeLevel, [0, 5000], [0, 10]);
|
||||
// print('CONVERTED VOLUME:' + convertedVolume);
|
||||
|
||||
var growthFactor = convertedVolume + velocityStrength;
|
||||
// print('growthFactor::' + growthFactor);
|
||||
if (velocityStrength > 1 || convertedVolume > 1) {
|
||||
var bubbleSize = randInt(1, 5)
|
||||
bubbleSize = bubbleSize / 10;
|
||||
if (dimensions.x > bubbleSize) {
|
||||
console.log('RELEASE BUBBLE')
|
||||
var lifetime = randInt(3, 8);
|
||||
//sound is somewhat unstable at the moment
|
||||
// Script.setTimeout(function() {
|
||||
// _t.burstBubbleSound(_t.currentBubble)
|
||||
// }, lifetime * 1000)
|
||||
//need to add some kind of forward velocity for bubble that you blow
|
||||
Entities.editEntity(_t.currentBubble, {
|
||||
velocity: Vec3.normalize(velocity),
|
||||
// angularVelocity: Controller.getSpatialControlRawAngularVelocity(hands.leftHand.tip),
|
||||
lifetime: lifetime
|
||||
});
|
||||
|
||||
_t.spawnBubble();
|
||||
return
|
||||
} else {
|
||||
if (mouthMode) {
|
||||
dimensions.x += 0.015 * convertedVolume;
|
||||
dimensions.y += 0.015 * convertedVolume;
|
||||
dimensions.z += 0.015 * convertedVolume;
|
||||
|
||||
} else {
|
||||
dimensions.x += 0.015 * velocityStrength;
|
||||
dimensions.y += 0.015 * velocityStrength;
|
||||
dimensions.z += 0.015 * velocityStrength;
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if (dimensions.x >= 0.02) {
|
||||
dimensions.x -= 0.001;
|
||||
dimensions.y -= 0.001;
|
||||
dimensions.z -= 0.001;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Entities.editEntity(_t.currentBubble, {
|
||||
position: wandPosition,
|
||||
dimensions: dimensions
|
||||
});
|
||||
|
||||
},
|
||||
burstBubbleSound: function(bubble) {
|
||||
var position = Entities.getEntityProperties(bubble).position;
|
||||
var orientation = Entities.getEntityProperties(bubble).orientation;
|
||||
console.log('bubble position at pop: ' + JSON.stringify(position));
|
||||
var audioOptions = {
|
||||
volume: 0.5,
|
||||
position: position,
|
||||
orientation: orientation
|
||||
}
|
||||
|
||||
//Audio.playSound(popSound, audioOptions);
|
||||
|
||||
//remove this bubble from the array
|
||||
var i = BubbleWand.bubbles.indexOf(bubble);
|
||||
|
||||
if (i != -1) {
|
||||
BubbleWand.bubbles.splice(i, 1);
|
||||
}
|
||||
|
||||
},
|
||||
spawnBubble: function() {
|
||||
console.log('spawning bubble')
|
||||
var _t = this;
|
||||
var properties = Entities.getEntityProperties(thisEntity.entityID);
|
||||
var wandPosition = properties.position;
|
||||
|
||||
|
||||
_t.currentBubble = Entities.addEntity({
|
||||
type: 'Model',
|
||||
modelURL: bubbleModel,
|
||||
position: wandPosition,
|
||||
dimensions: {
|
||||
x: 0.01,
|
||||
y: 0.01,
|
||||
z: 0.01
|
||||
},
|
||||
ignoreForCollisions: true,
|
||||
gravity: BUBBLE_GRAVITY,
|
||||
// collisionSoundURL:popSound,
|
||||
shapeType: "sphere",
|
||||
script: bubbleScript,
|
||||
});
|
||||
_t.bubbles.push(_t.currentBubble)
|
||||
},
|
||||
init: function() {
|
||||
var _t = this;
|
||||
_t.spawnBubble();
|
||||
Script.update.connect(BubbleWand.update);
|
||||
}
|
||||
}
|
||||
|
||||
function collectGarbage() {
|
||||
console.log('COLLECTING GARBAGE!!!')
|
||||
Entities.deleteEntity(BubbleWand.currentBubble);
|
||||
while (BubbleWand.bubbles.length > 0) {
|
||||
Entities.deleteEntity(BubbleWand.bubbles.pop());
|
||||
}
|
||||
}
|
||||
|
||||
BubbleWand.init();
|
||||
|
||||
|
||||
|
||||
})
|
Loading…
Reference in a new issue