mirror of
https://github.com/overte-org/overte.git
synced 2025-04-07 22:33:04 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi
This commit is contained in:
commit
f5dfc7d3e4
40 changed files with 32483 additions and 171 deletions
|
@ -12,7 +12,6 @@
|
|||
#include <QThread>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
|
||||
#include "ScriptableAvatar.h"
|
||||
|
||||
// hold and priority unused but kept so that client side JS can run.
|
||||
|
@ -48,14 +47,12 @@ AnimationDetails ScriptableAvatar::getAnimationDetails() {
|
|||
}
|
||||
|
||||
void ScriptableAvatar::update(float deltatime) {
|
||||
if (_bind.isNull() && !_skeletonFBXURL.isEmpty()) { // AvatarData will parse the .fst, but not get the .fbx skeleton.
|
||||
_bind = DependencyManager::get<AnimationCache>()->getAnimation(_skeletonFBXURL);
|
||||
}
|
||||
|
||||
// Run animation
|
||||
if (_animation && _animation->isLoaded() && _animation->getFrames().size() > 0) {
|
||||
QStringList modelJoints = getJointNames();
|
||||
QStringList animationJoints = _animation->getJointNames();
|
||||
|
||||
if (_jointData.size() != modelJoints.size()) {
|
||||
_jointData.resize(modelJoints.size());
|
||||
}
|
||||
if (_animation && _animation->isLoaded() && _animation->getFrames().size() > 0 && _bind->isLoaded()) {
|
||||
|
||||
float currentFrame = _animationDetails.currentFrame + deltatime * _animationDetails.fps;
|
||||
if (_animationDetails.loop || currentFrame < _animationDetails.lastFrame) {
|
||||
|
@ -63,19 +60,29 @@ void ScriptableAvatar::update(float deltatime) {
|
|||
currentFrame -= (_animationDetails.lastFrame - _animationDetails.firstFrame);
|
||||
}
|
||||
_animationDetails.currentFrame = currentFrame;
|
||||
|
||||
const QVector<FBXJoint>& modelJoints = _bind->getGeometry().joints;
|
||||
QStringList animationJointNames = _animation->getJointNames();
|
||||
|
||||
if (_jointData.size() != modelJoints.size()) {
|
||||
_jointData.resize(modelJoints.size());
|
||||
}
|
||||
|
||||
const int frameCount = _animation->getFrames().size();
|
||||
const FBXAnimationFrame& floorFrame = _animation->getFrames().at((int)glm::floor(currentFrame) % frameCount);
|
||||
const FBXAnimationFrame& ceilFrame = _animation->getFrames().at((int)glm::ceil(currentFrame) % frameCount);
|
||||
const float frameFraction = glm::fract(currentFrame);
|
||||
|
||||
for (int i = 0; i < animationJoints.size(); i++) {
|
||||
const QString& name = animationJoints[i];
|
||||
int mapping = getJointIndex(name);
|
||||
for (int i = 0; i < animationJointNames.size(); i++) {
|
||||
const QString& name = animationJointNames[i];
|
||||
// As long as we need the model preRotations anyway, let's get the jointIndex from the bind skeleton rather than
|
||||
// trusting the .fst (which is sometimes not updated to match changes to .fbx).
|
||||
int mapping = _bind->getGeometry().getJointIndex(name);
|
||||
if (mapping != -1 && !_maskedJoints.contains(name)) {
|
||||
JointData& data = _jointData[mapping];
|
||||
|
||||
auto newRotation = safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);
|
||||
auto newRotation = modelJoints[mapping].preRotation *
|
||||
safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction);
|
||||
// We could probably do translations as in interpolation in model space (rather than the parent space that each frame is in),
|
||||
// but we don't do so for MyAvatar yet, so let's not be different here.
|
||||
if (data.rotation != newRotation) {
|
||||
|
|
|
@ -33,6 +33,7 @@ private:
|
|||
AnimationPointer _animation;
|
||||
AnimationDetails _animationDetails;
|
||||
QStringList _maskedJoints;
|
||||
AnimationPointer _bind; // a sleazy way to get the skeleton, given the various library/cmake dependencies
|
||||
};
|
||||
|
||||
#endif // hifi_ScriptableAvatar_h
|
|
@ -43,6 +43,7 @@ void OctreeInboundPacketProcessor::resetStats() {
|
|||
_totalPackets = 0;
|
||||
_lastNackTime = usecTimestampNow();
|
||||
|
||||
QWriteLocker locker(&_senderStatsLock);
|
||||
_singleSenderStats.clear();
|
||||
}
|
||||
|
||||
|
@ -220,6 +221,8 @@ void OctreeInboundPacketProcessor::trackInboundPacket(const QUuid& nodeUUID, uns
|
|||
_totalElementsInPacket += editsInPacket;
|
||||
_totalPackets++;
|
||||
|
||||
QWriteLocker locker(&_senderStatsLock);
|
||||
|
||||
// find the individual senders stats and track them there too...
|
||||
// see if this is the first we've heard of this node...
|
||||
if (_singleSenderStats.find(nodeUUID) == _singleSenderStats.end()) {
|
||||
|
@ -242,6 +245,8 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
|
|||
int packetsSent = 0;
|
||||
int totalBytesSent = 0;
|
||||
|
||||
QWriteLocker locker(&_senderStatsLock);
|
||||
|
||||
NodeToSenderStatsMapIterator i = _singleSenderStats.begin();
|
||||
while (i != _singleSenderStats.end()) {
|
||||
|
||||
|
@ -262,10 +267,9 @@ int OctreeInboundPacketProcessor::sendNackPackets() {
|
|||
}
|
||||
|
||||
const SharedNodePointer& destinationNode = DependencyManager::get<NodeList>()->nodeWithUUID(nodeUUID);
|
||||
// If the node no longer exists, wait until the ReceivedPacketProcessor has cleaned up the node
|
||||
// to remove it from our stats list.
|
||||
// FIXME Is it safe to clean it up here before ReceivedPacketProcess has?
|
||||
// if the node no longer exists, remove its stats
|
||||
if (!destinationNode) {
|
||||
i = _singleSenderStats.erase(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ public:
|
|||
|
||||
void resetStats();
|
||||
|
||||
NodeToSenderStatsMap& getSingleSenderStats() { return _singleSenderStats; }
|
||||
NodeToSenderStatsMap getSingleSenderStats() { QReadLocker locker(&_senderStatsLock); return _singleSenderStats; }
|
||||
|
||||
virtual void terminating() { _shuttingDown = true; ReceivedPacketProcessor::terminating(); }
|
||||
|
||||
|
@ -94,15 +94,16 @@ private:
|
|||
OctreeServer* _myServer;
|
||||
int _receivedPacketCount;
|
||||
|
||||
quint64 _totalTransitTime;
|
||||
quint64 _totalProcessTime;
|
||||
quint64 _totalLockWaitTime;
|
||||
quint64 _totalElementsInPacket;
|
||||
quint64 _totalPackets;
|
||||
std::atomic<uint64_t> _totalTransitTime;
|
||||
std::atomic<uint64_t> _totalProcessTime;
|
||||
std::atomic<uint64_t> _totalLockWaitTime;
|
||||
std::atomic<uint64_t> _totalElementsInPacket;
|
||||
std::atomic<uint64_t> _totalPackets;
|
||||
|
||||
NodeToSenderStatsMap _singleSenderStats;
|
||||
QReadWriteLock _senderStatsLock;
|
||||
|
||||
quint64 _lastNackTime;
|
||||
std::atomic<uint64_t> _lastNackTime;
|
||||
bool _shuttingDown;
|
||||
};
|
||||
#endif // hifi_OctreeInboundPacketProcessor_h
|
||||
|
|
|
@ -711,7 +711,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
|
||||
|
||||
int senderNumber = 0;
|
||||
NodeToSenderStatsMap& allSenderStats = _octreeInboundPacketProcessor->getSingleSenderStats();
|
||||
NodeToSenderStatsMap allSenderStats = _octreeInboundPacketProcessor->getSingleSenderStats();
|
||||
for (NodeToSenderStatsMapConstIterator i = allSenderStats.begin(); i != allSenderStats.end(); i++) {
|
||||
senderNumber++;
|
||||
QUuid senderID = i.key();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
/*jslint vars: true, plusplus: true*/
|
||||
/*global Agent, Avatar, Script, Entities, Vec3, print*/
|
||||
/*global Agent, Avatar, Script, Entities, Vec3, Quat, print*/
|
||||
//
|
||||
// animatedAvatar.js
|
||||
// examples/acScripts
|
||||
|
@ -16,15 +16,62 @@
|
|||
|
||||
var origin = {x: 500, y: 500, z: 500};
|
||||
var spread = 20; // meters
|
||||
var turnSpread = 90; // How many degrees should turn from front range over.
|
||||
var animationData = {url: "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/walk_fwd.fbx", lastFrame: 35};
|
||||
Avatar.skeletonModelURL = "https://hifi-public.s3.amazonaws.com/marketplace/contents/dd03b8e3-52fb-4ab3-9ac9-3b17e00cd85d/98baa90b3b66803c5d7bd4537fca6993.fst"; //lovejoy
|
||||
Avatar.displayName = "'Bot";
|
||||
var models = [ // Commented-out avatars do not animate properly on AC's. Presumably because ScriptableAvatar doesn't use model pre-rotations.
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/alan/alan.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/andrew/andrew.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/austin/austin.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/birarda/birarda.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/brad/brad.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/chris/chris2.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/clement/clement.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/emily/emily.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/ewing/ewing.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/howard/howard.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/huffman/huffman.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/james/james.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/philip/philip.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/ryan/ryan.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/sam/sam.fst",
|
||||
"https://hifi-public.s3.amazonaws.com/ozan/avatars/hifi_team/tony/tony.fst",
|
||||
|
||||
"https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/contents/1e57c395-612e-4acd-9561-e79dbda0bc49/faafb83c63a3e5e265884d270fc29f8b.fst",
|
||||
"https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/contents/615ca447-06ee-4215-8dd1-a609c2fcd0cd/c7af6d4224c501fdd9cb54e0101ff281.fst",
|
||||
"https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/contents/731c39d7-559a-4ce2-947c-3e2768f5471c/8d5eba2fd5bf068259556aec1861c5dd.fst",
|
||||
"https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/contents/8bdaa1ec-99df-4a29-a249-6941c7fd1930/37351a18a3dea468088fc3d822aaf29c.fst",
|
||||
"https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/contents/0909d7b7-c67e-45fb-acd9-a07380dc6b9c/da76b8c59dbc680bdda90df4b9a46faa.fst",
|
||||
"https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/contents/ad0dffd7-f811-487b-a20a-2509235491ef/29106da1f7e6a42c7907603421fd7df5.fst",
|
||||
"https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/contents/3ebe5c84-8b88-4d91-86ac-f104f3620fe3/3534b032d079514aa8960a316500ce13.fst",
|
||||
"https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/contents/dd03b8e3-52fb-4ab3-9ac9-3b17e00cd85d/98baa90b3b66803c5d7bd4537fca6993.fst",
|
||||
"https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/contents/ff060580-2fc7-4b6c-8e12-f023d05363cf/dadef29b1e60f23b413d1850d7e0dd4a.fst",
|
||||
"https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/contents/b55d3baf-4eb3-4cac-af4c-0fb66d0c907b/ad2c9157f3924ab1f7f6ea87a8cce6cc.fst",
|
||||
"https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/contents/d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73/4618d52e711fbb34df442b414da767bb.fst"
|
||||
];
|
||||
var nameMap = {
|
||||
faafb83c63a3e5e265884d270fc29f8b: 'albert',
|
||||
c7af6d4224c501fdd9cb54e0101ff281: 'boss',
|
||||
'8d5eba2fd5bf068259556aec1861c5dd': 'dougland',
|
||||
'37351a18a3dea468088fc3d822aaf29c': 'fightbot blue',
|
||||
da76b8c59dbc680bdda90df4b9a46faa: 'judd',
|
||||
'29106da1f7e6a42c7907603421fd7df5': 'kate',
|
||||
'3534b032d079514aa8960a316500ce13': 'lenny',
|
||||
'98baa90b3b66803c5d7bd4537fca6993': 'lovejoy',
|
||||
dadef29b1e60f23b413d1850d7e0dd4a: 'mery', // eyes no good
|
||||
ad2c9157f3924ab1f7f6ea87a8cce6cc: 'owen',
|
||||
'4618d52e711fbb34df442b414da767bb': 'will'
|
||||
};
|
||||
|
||||
Avatar.skeletonModelURL = models[Math.round(Math.random() * (models.length - 1))]; // pick one
|
||||
Avatar.displayName = Avatar.skeletonModelURL.match(/\/(\w*).fst/)[1]; // grab the file basename
|
||||
Avatar.displayName = nameMap[Avatar.displayName] || Avatar.displayName;
|
||||
var millisecondsToWaitBeforeStarting = 10 * 1000; // To give the various servers a chance to start.
|
||||
|
||||
Agent.isAvatar = true;
|
||||
function coord() { return (Math.random() * spread) - (spread / 2); } // randomly distribute a coordinate zero += spread/2.
|
||||
Script.setTimeout(function () {
|
||||
Avatar.position = Vec3.sum(origin, {x: coord(), y: 0, z: coord()});
|
||||
Avatar.orientation = Quat.fromPitchYawRollDegrees(0, turnSpread * (Math.random() - 0.5), 0);
|
||||
print("Starting at", JSON.stringify(Avatar.position));
|
||||
Avatar.startAnimation(animationData.url, animationData.fps || 30, 1, true, false, animationData.firstFrame || 0, animationData.lastFrame);
|
||||
}, millisecondsToWaitBeforeStarting);
|
||||
|
|
|
@ -200,6 +200,7 @@ function entityIsGrabbedByOther(entityID) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
function MyController(hand) {
|
||||
this.hand = hand;
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
|
@ -223,6 +224,8 @@ function MyController(hand) {
|
|||
this.rawTriggerValue = 0;
|
||||
this.rawBumperValue = 0;
|
||||
|
||||
this.overlayLine = null;
|
||||
|
||||
this.offsetPosition = {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
|
@ -318,6 +321,33 @@ function MyController(hand) {
|
|||
});
|
||||
}
|
||||
|
||||
this.overlayLineOn = function(closePoint, farPoint, color) {
|
||||
if (this.overlayLine === null) {
|
||||
var lineProperties = {
|
||||
lineWidth: 5,
|
||||
start: closePoint,
|
||||
end: farPoint,
|
||||
color: color,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
visible: true,
|
||||
alpha: 1
|
||||
};
|
||||
|
||||
this.overlayLine = Overlays.addOverlay("line3d", lineProperties);
|
||||
|
||||
} else {
|
||||
var success = Overlays.editOverlay(this.overlayLine, {
|
||||
lineWidth: 5,
|
||||
start: closePoint,
|
||||
end: farPoint,
|
||||
color: color,
|
||||
visible: true,
|
||||
ignoreRayIntersection: true, // always ignore this
|
||||
alpha: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.lineOn = function(closePoint, farPoint, color) {
|
||||
// draw a line
|
||||
if (this.pointer === null) {
|
||||
|
@ -356,6 +386,13 @@ function MyController(hand) {
|
|||
this.pointer = null;
|
||||
};
|
||||
|
||||
this.overlayLineOff = function() {
|
||||
if (this.overlayLine !== null) {
|
||||
Overlays.deleteOverlay(this.overlayLine);
|
||||
}
|
||||
this.overlayLine = null;
|
||||
};
|
||||
|
||||
this.triggerPress = function(value) {
|
||||
_this.rawTriggerValue = value;
|
||||
};
|
||||
|
@ -479,7 +516,11 @@ function MyController(hand) {
|
|||
this.setState(STATE_NEAR_GRABBING);
|
||||
} else { // equipping
|
||||
if (typeof grabbableData.spatialKey !== 'undefined') {
|
||||
this.setState(STATE_EQUIP_SPRING);
|
||||
// TODO
|
||||
// if we go to STATE_EQUIP_SPRING the item will be pulled to the hand and will then switch
|
||||
// to STATE_EQUIP. This needs some debugging, so just jump straight to STATE_EQUIP here.
|
||||
// this.setState(STATE_EQUIP_SPRING);
|
||||
this.setState(STATE_EQUIP);
|
||||
} else {
|
||||
this.setState(STATE_EQUIP);
|
||||
}
|
||||
|
@ -493,7 +534,9 @@ function MyController(hand) {
|
|||
this.grabbedEntity = intersection.entityID;
|
||||
if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) {
|
||||
// if a distance pick in equip mode hits something with a spatialKey, equip it
|
||||
this.setState(STATE_EQUIP_SPRING);
|
||||
// TODO use STATE_EQUIP_SPRING here once it works right.
|
||||
// this.setState(STATE_EQUIP_SPRING);
|
||||
this.setState(STATE_EQUIP);
|
||||
return;
|
||||
} else if (this.state == STATE_SEARCHING) {
|
||||
this.setState(STATE_DISTANCE_HOLDING);
|
||||
|
@ -598,7 +641,8 @@ function MyController(hand) {
|
|||
}
|
||||
}
|
||||
|
||||
this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
||||
//this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
||||
this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR);
|
||||
};
|
||||
|
||||
this.distanceHolding = function() {
|
||||
|
@ -644,6 +688,9 @@ function MyController(hand) {
|
|||
this.currentAvatarPosition = MyAvatar.position;
|
||||
this.currentAvatarOrientation = MyAvatar.orientation;
|
||||
|
||||
this.overlayLineOff();
|
||||
|
||||
|
||||
};
|
||||
|
||||
this.continueDistanceHolding = function() {
|
||||
|
@ -751,6 +798,7 @@ function MyController(hand) {
|
|||
}
|
||||
|
||||
this.lineOff();
|
||||
this.overlayLineOff();
|
||||
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
||||
this.activateEntity(this.grabbedEntity, grabbedProperties);
|
||||
|
@ -802,6 +850,7 @@ function MyController(hand) {
|
|||
// equipping
|
||||
Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]);
|
||||
this.startHandGrasp();
|
||||
|
||||
this.setState(STATE_CONTINUE_EQUIP_BD);
|
||||
}
|
||||
|
||||
|
@ -885,11 +934,13 @@ function MyController(hand) {
|
|||
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
|
||||
Entities.callEntityMethod(this.grabbedEntity, "unequip");
|
||||
this.endHandGrasp();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
this.pullTowardEquipPosition = function() {
|
||||
this.lineOff();
|
||||
this.overlayLineOff();
|
||||
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
|
@ -1093,7 +1144,7 @@ function MyController(hand) {
|
|||
this.release = function() {
|
||||
|
||||
this.lineOff();
|
||||
|
||||
this.overlayLineOff();
|
||||
if (this.grabbedEntity !== null) {
|
||||
if (this.actionID !== null) {
|
||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
||||
|
@ -1215,10 +1266,10 @@ Controller.enableMapping(MAPPING_NAME);
|
|||
var handToDisable = 'none';
|
||||
|
||||
function update() {
|
||||
if (handToDisable !== LEFT_HAND) {
|
||||
if (handToDisable !== LEFT_HAND && handToDisable!=='both') {
|
||||
leftController.update();
|
||||
}
|
||||
if (handToDisable !== RIGHT_HAND) {
|
||||
if (handToDisable !== RIGHT_HAND && handToDisable!=='both') {
|
||||
rightController.update();
|
||||
}
|
||||
}
|
||||
|
@ -1226,15 +1277,20 @@ function update() {
|
|||
Messages.subscribe('Hifi-Hand-Disabler');
|
||||
|
||||
handleHandDisablerMessages = function(channel, message, sender) {
|
||||
|
||||
|
||||
if (sender === MyAvatar.sessionUUID) {
|
||||
handToDisable = message;
|
||||
if (message === 'left') {
|
||||
handToDisable = LEFT_HAND;
|
||||
}
|
||||
if (message === 'right') {
|
||||
handToDisable = RIGHT_HAND;
|
||||
}
|
||||
if(message==='both'){
|
||||
handToDisable='both';
|
||||
}
|
||||
if(message==='none'){
|
||||
handToDisable='none';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1248,4 +1304,4 @@ function cleanup() {
|
|||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
Script.update.connect(update);
|
||||
Script.update.connect(update);
|
||||
|
|
|
@ -22,8 +22,10 @@ var laserPointer = (function () {
|
|||
];
|
||||
|
||||
function isHandPointing(hand) {
|
||||
var MINIMUM_TRIGGER_PULL = 0.9;
|
||||
return Controller.getTriggerValue(hand) > MINIMUM_TRIGGER_PULL;
|
||||
var MINIMUM_TRIGGER_PULL = 0.9,
|
||||
controller;
|
||||
controller = hand === 0 ? Controller.Standard.LT : Controller.Standard.RT;
|
||||
return Controller.getValue(controller) > MINIMUM_TRIGGER_PULL;
|
||||
}
|
||||
|
||||
function isFingerPointing(hand) {
|
||||
|
|
|
@ -193,13 +193,12 @@ var leapHands = (function () {
|
|||
}
|
||||
|
||||
// Set avatar arms vertical, forearms horizontal, as "zero" position for calibration
|
||||
MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, -90.0));
|
||||
MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0));
|
||||
MyAvatar.setJointData("LeftHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0));
|
||||
MyAvatar.setJointData("RightArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 90.0));
|
||||
MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0));
|
||||
MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0));
|
||||
|
||||
MyAvatar.setJointRotation("LeftArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 0.0));
|
||||
MyAvatar.setJointRotation("LeftForeArm", Quat.fromPitchYawRollDegrees(0.0, 90.0, 90.0));
|
||||
MyAvatar.setJointRotation("LeftHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0));
|
||||
MyAvatar.setJointRotation("RightArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 0.0));
|
||||
MyAvatar.setJointRotation("RightForeArm", Quat.fromPitchYawRollDegrees(0.0, -90.0, -90.0));
|
||||
MyAvatar.setJointRotation("RightHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0));
|
||||
|
||||
// Wait for arms to assume their positions before calculating
|
||||
Script.setTimeout(finishCalibration, CALIBRATION_TIME);
|
||||
|
@ -382,23 +381,14 @@ var leapHands = (function () {
|
|||
|
||||
// Hand rotation in camera coordinates ...
|
||||
handRotation = {
|
||||
x: handRotation.z,
|
||||
y: handRotation.y,
|
||||
z: handRotation.x,
|
||||
x: -handRotation.x,
|
||||
y: -handRotation.z,
|
||||
z: -handRotation.y,
|
||||
w: handRotation.w
|
||||
};
|
||||
|
||||
// Hand rotation in avatar coordinates ...
|
||||
if (h === 0) {
|
||||
handRotation.x = -handRotation.x;
|
||||
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation);
|
||||
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 0, z: 1 }), handRotation);
|
||||
} else {
|
||||
handRotation.z = -handRotation.z;
|
||||
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation);
|
||||
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 0, z: 1 }), handRotation);
|
||||
}
|
||||
|
||||
handRotation = Quat.multiply(Quat.angleAxis(180.0, { x: 0, y: 1, z: 0 }), handRotation);
|
||||
cameraOrientation.x = -cameraOrientation.x;
|
||||
cameraOrientation.z = -cameraOrientation.z;
|
||||
handRotation = Quat.multiply(cameraOrientation, handRotation);
|
||||
|
@ -421,22 +411,14 @@ var leapHands = (function () {
|
|||
|
||||
// Hand rotation in camera coordinates ...
|
||||
handRotation = {
|
||||
x: handRotation.z,
|
||||
y: handRotation.y,
|
||||
z: handRotation.x,
|
||||
x: -handRotation.x,
|
||||
y: -handRotation.z,
|
||||
z: -handRotation.y,
|
||||
w: handRotation.w
|
||||
};
|
||||
|
||||
// Hand rotation in avatar coordinates ...
|
||||
if (h === 0) {
|
||||
handRotation.x = -handRotation.x;
|
||||
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }),
|
||||
handRotation);
|
||||
} else {
|
||||
handRotation.z = -handRotation.z;
|
||||
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }),
|
||||
handRotation);
|
||||
}
|
||||
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation);
|
||||
}
|
||||
|
||||
// Set hand position and orientation ...
|
||||
|
@ -462,7 +444,7 @@ var leapHands = (function () {
|
|||
w: locRotation.w
|
||||
};
|
||||
}
|
||||
MyAvatar.setJointData(fingers[h][i][j].jointName, locRotation);
|
||||
MyAvatar.setJointRotation(fingers[h][i][j].jointName, locRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
1
examples/example/games/exterminatorGame/gameServer/.gitignore
vendored
Normal file
1
examples/example/games/exterminatorGame/gameServer/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/node_modules
|
|
@ -0,0 +1 @@
|
|||
web: node app.js
|
|
@ -0,0 +1,5 @@
|
|||
This gameserver sets up a server with websockets that listen for messages from interface regarding when users shoot rats, and updates a real-time game board with that information. This is just a first pass, and the plan is to abstract this to work with any kind of game content creators wish to make with High Fidelity.
|
||||
|
||||
To enter the game: Run pistol.js and shoot at rats.
|
||||
For every rat you kill, you get a point.
|
||||
You're score will be displayed at https://desolate-bastion-1742.herokuapp.com/
|
76
examples/example/games/exterminatorGame/gameServer/app.js
Normal file
76
examples/example/games/exterminatorGame/gameServer/app.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('express');
|
||||
var http = require('http');
|
||||
var _ = require('underscore');
|
||||
var shortid = require('shortid');
|
||||
|
||||
|
||||
var app = express();
|
||||
var server = http.createServer(app);
|
||||
|
||||
var WebSocketServer = require('websocket').server;
|
||||
var wsServer = new WebSocketServer({
|
||||
httpServer: server
|
||||
});
|
||||
|
||||
var users = [];
|
||||
var connections = [];
|
||||
wsServer.on('request', function(request) {
|
||||
console.log("SOMEONE JOINED");
|
||||
var connection = request.accept(null, request.origin);
|
||||
connections.push(connection);
|
||||
connection.on('message', function(data) {
|
||||
var userData = JSON.parse(data.utf8Data);
|
||||
var user = _.find(users, function(user) {
|
||||
return user.username === userData.username;
|
||||
});
|
||||
if (user) {
|
||||
// This user already exists, so just update score
|
||||
users[users.indexOf(user)].score = userData.score;
|
||||
} else {
|
||||
users.push({
|
||||
id: shortid.generate(),
|
||||
username: userData.username,
|
||||
score: userData.score
|
||||
});
|
||||
}
|
||||
connections.forEach(function(aConnection) {
|
||||
aConnection.sendUTF(JSON.stringify({
|
||||
users: users
|
||||
}));
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/users', function(req, res) {
|
||||
res.send({
|
||||
users: users
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
/* Configuration */
|
||||
app.set('views', __dirname + '/views');
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
app.set('port', (process.env.PORT || 5000));
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
app.use(express.errorHandler({
|
||||
dumpExceptions: true,
|
||||
showStack: true
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
/* Start server */
|
||||
server.listen(app.get('port'), function() {
|
||||
console.log('Express server listening on port %d in %s mode', app.get('port'), app.get('env'));
|
||||
});
|
||||
|
||||
module.exports = app;
|
|
@ -0,0 +1,87 @@
|
|||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var _ = require('underscore')
|
||||
var $ = require('jquery');
|
||||
|
||||
var UserList = React.createClass({
|
||||
render: function(){
|
||||
var sortedUsers = _.sortBy(this.props.data.users, function(users){
|
||||
//Show higher scorers at top of board
|
||||
return 1 - users.score;
|
||||
});
|
||||
var users = sortedUsers.map(function(user) {
|
||||
|
||||
return (
|
||||
<User username = {user.username} score = {user.score} key = {user.id}></User>
|
||||
)
|
||||
});
|
||||
return (
|
||||
<div>{users}</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
var GameBoard = React.createClass({
|
||||
loadDataFromServer: function(data) {
|
||||
$.ajax({
|
||||
url: this.props.url,
|
||||
dataType: 'json',
|
||||
cache: false,
|
||||
success: function(data) {
|
||||
this.setState({data: data});
|
||||
}.bind(this),
|
||||
error: function(xhr, status, err) {
|
||||
console.error(this.props.url, status, err.toString());
|
||||
}.bind(this)
|
||||
});
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {data: {users: []}};
|
||||
},
|
||||
componentDidMount: function() {
|
||||
this.loadDataFromServer();
|
||||
//set up web socket
|
||||
var path = window.location.hostname + ":" + window.location.port;
|
||||
console.log("LOCATION ", path)
|
||||
var socketClient = new WebSocket("wss://" + path);
|
||||
var self = this;
|
||||
socketClient.onopen = function() {
|
||||
console.log("CONNECTED");
|
||||
socketClient.onmessage = function(data) {
|
||||
console.log("ON MESSAGE");
|
||||
self.setState({data: JSON.parse(data.data)});
|
||||
};
|
||||
};
|
||||
|
||||
},
|
||||
render: function() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className = "gameTitle">Kill All The Rats!</div>
|
||||
<div className = "boardHeader">
|
||||
<div className="username">PLAYER</div>
|
||||
<div className="score" > SCORE </div>
|
||||
</div>
|
||||
<UserList data ={this.state.data}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var User = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div className = "entry">
|
||||
<div className="username"> {this.props.username} </div>
|
||||
<div className="score" > {this.props.score} </div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})
|
||||
|
||||
React.render(
|
||||
<GameBoard url = "/users" />,
|
||||
document.getElementById('app')
|
||||
);
|
|
@ -0,0 +1,15 @@
|
|||
var gulp = require('gulp');
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
gulp.task('build', function() {
|
||||
exec('npm run build', function(msg){
|
||||
console.log(msg);
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('watch', function() {
|
||||
gulp.watch('client/*.jsx', ['build']);
|
||||
});
|
||||
|
||||
|
||||
gulp.task('default', ['build', 'watch'])
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "KillAllTheRats",
|
||||
"version": "0.6.9",
|
||||
"scripts": {
|
||||
"build": "browserify ./client/app.jsx -t babelify --outfile ./public/js/app.js",
|
||||
"start": "node app.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.13.1",
|
||||
"gulp": "^3.9.0",
|
||||
"jquery": "^2.1.4",
|
||||
"react": "^0.13.3",
|
||||
"shortid": "^2.2.4",
|
||||
"underscore": "^1.8.3",
|
||||
"websocket": "^1.0.22"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babelify": "^6.1.3",
|
||||
"browserify": "^10.2.6"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
body {
|
||||
font-family: Impact;
|
||||
background-color: #009DC0 ;
|
||||
font-size: 60px;
|
||||
}
|
||||
|
||||
.gameTitle {
|
||||
color: #D61010;
|
||||
}
|
||||
|
||||
.entry{
|
||||
width:100%;
|
||||
height:50px;
|
||||
border:1px solid #A9D1E1;
|
||||
color: white;
|
||||
margin-right:10px;
|
||||
padding: 10px;
|
||||
float:left;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.boardHeader{
|
||||
width:100%;
|
||||
height:50px;
|
||||
border:5px solid #A9D1E1;
|
||||
color: white;
|
||||
margin-right:10px;
|
||||
padding: 10px;
|
||||
float:left;
|
||||
font-size: 40px;
|
||||
}
|
||||
.username{
|
||||
font-weight: bold;
|
||||
float: left;
|
||||
margin-right: 50%;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<title>Kill The Rats!</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
30691
examples/example/games/exterminatorGame/gameServer/public/js/app.js
Normal file
30691
examples/example/games/exterminatorGame/gameServer/public/js/app.js
Normal file
File diff suppressed because it is too large
Load diff
477
examples/example/games/exterminatorGame/pistol.js
Normal file
477
examples/example/games/exterminatorGame/pistol.js
Normal file
|
@ -0,0 +1,477 @@
|
|||
//
|
||||
// pistol.js
|
||||
// examples
|
||||
//
|
||||
// Created by Eric Levin on 11/12/2015
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that turns the hydra controllers and mouse into a entity gun.
|
||||
// It reads the controller, watches for trigger pulls, and adds a force to any entity it hits
|
||||
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
Script.include("../../../libraries/utils.js");
|
||||
Script.include("../../../libraries/constants.js");
|
||||
|
||||
var GUN_FORCE =20;
|
||||
|
||||
Messages.sendMessage('Hifi-Hand-Disabler', "both");
|
||||
|
||||
var gameName = "Kill All The Rats!"
|
||||
// var HOST = "localhost:5000"
|
||||
var HOST = "desolate-bastion-1742.herokuapp.com";
|
||||
var socketClient = new WebSocket("ws://" + HOST);
|
||||
var username = GlobalServices.username;
|
||||
var currentScore = 0;
|
||||
|
||||
function score() {
|
||||
currentScore++;
|
||||
socketClient.send(JSON.stringify({
|
||||
username: username,
|
||||
score: currentScore,
|
||||
gameName: gameName
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
var fireSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Guns/GUN-SHOT2.raw");
|
||||
var LASER_LENGTH = 100;
|
||||
var LASER_WIDTH = 2;
|
||||
var POSE_CONTROLS = [Controller.Standard.LeftHand, Controller.Standard.RightHand];
|
||||
var TRIGGER_CONTROLS = [Controller.Standard.LT, Controller.Standard.RT];
|
||||
var MIN_THROWER_DELAY = 1000;
|
||||
var MAX_THROWER_DELAY = 1000;
|
||||
var RELOAD_INTERVAL = 5;
|
||||
var GUN_MODEL = HIFI_PUBLIC_BUCKET + "cozza13/gun/m1911-handgun+1.fbx?v=4";
|
||||
var BULLET_VELOCITY = 10.0;
|
||||
var GUN_OFFSETS = [{
|
||||
x: 0.04,
|
||||
y: 0.26,
|
||||
z: 0.04
|
||||
}, {
|
||||
x: 0.04,
|
||||
y: 0.26,
|
||||
z: 0.04
|
||||
}];
|
||||
|
||||
var GUN_ORIENTATIONS = [Quat.fromPitchYawRollDegrees(0, 90, 90), Quat.fromPitchYawRollDegrees(0, -90, 270)];
|
||||
|
||||
//x -> y
|
||||
//y -> z
|
||||
// z -> x
|
||||
var BARREL_OFFSETS = [ {
|
||||
x: -0.12,
|
||||
y: 0.12,
|
||||
z: 0.04
|
||||
}, {
|
||||
x: 0.12,
|
||||
y: 0.12,
|
||||
z: 0.04
|
||||
} ];
|
||||
|
||||
|
||||
|
||||
var pointers = [];
|
||||
|
||||
pointers.push(Overlays.addOverlay("line3d", {
|
||||
start: ZERO_VECTOR,
|
||||
end: ZERO_VECTOR,
|
||||
color: COLORS.RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: LASER_WIDTH
|
||||
}));
|
||||
|
||||
pointers.push(Overlays.addOverlay("line3d", {
|
||||
start: ZERO_VECTOR,
|
||||
end: ZERO_VECTOR,
|
||||
color: COLORS.RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: LASER_WIDTH
|
||||
}));
|
||||
|
||||
var mapping = Controller.newMapping();
|
||||
var validPoses = [false, false];
|
||||
var barrelVectors = [0, 0];
|
||||
var barrelTips = [0, 0];
|
||||
|
||||
|
||||
// If enabled, anything can be shot, otherwise, an entity needs to have "isShootable" set in its userData
|
||||
var shootAnything = true;
|
||||
|
||||
|
||||
function update(deltaTime) {
|
||||
// FIXME we should also expose MyAvatar.handPoses[2], MyAvatar.tipPoses[2]
|
||||
var tipPoses = [MyAvatar.leftHandTipPose, MyAvatar.rightHandTipPose];
|
||||
|
||||
for (var side = 0; side < 2; side++) {
|
||||
// First check if the controller is valid
|
||||
var controllerPose = Controller.getPoseValue(POSE_CONTROLS[side]);
|
||||
validPoses[side] = controllerPose.valid;
|
||||
// Need to adjust the laser
|
||||
var tipPose = tipPoses[side];
|
||||
var handRotation = tipPoses[side].rotation;
|
||||
var barrelOffset = Vec3.multiplyQbyV(handRotation, BARREL_OFFSETS[side]);
|
||||
barrelTips[side] = Vec3.sum(tipPose.translation, barrelOffset);
|
||||
barrelVectors[side] = Vec3.multiplyQbyV(handRotation, {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
});
|
||||
|
||||
var laserTip = Vec3.sum(Vec3.multiply(LASER_LENGTH, barrelVectors[side]), barrelTips[side]);
|
||||
// Update Lasers
|
||||
Overlays.editOverlay(pointers[side], {
|
||||
start: barrelTips[side],
|
||||
end: laserTip,
|
||||
alpha: 1,
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function displayPointer(side) {
|
||||
Overlays.editOverlay(pointers[side], {
|
||||
visible: true
|
||||
});
|
||||
}
|
||||
|
||||
function hidePointer(side) {
|
||||
Overlays.editOverlay(pointers[side], {
|
||||
visible: false
|
||||
});
|
||||
}
|
||||
|
||||
function fire(side, value) {
|
||||
if (value == 0) {
|
||||
return;
|
||||
}
|
||||
Audio.playSound(fireSound, {
|
||||
position: barrelTips[side],
|
||||
volume: 0.5
|
||||
});
|
||||
|
||||
var shotDirection = Vec3.normalize(barrelVectors[side]);
|
||||
var pickRay = {
|
||||
origin: barrelTips[side],
|
||||
direction: shotDirection
|
||||
};
|
||||
createMuzzleFlash(barrelTips[side]);
|
||||
|
||||
var intersection = Entities.findRayIntersectionBlocking(pickRay, true);
|
||||
if (intersection.intersects) {
|
||||
Script.setTimeout(function() {
|
||||
createEntityHitEffect(intersection.intersection);
|
||||
if (shootAnything && intersection.properties.collisionsWillMove === 1) {
|
||||
// Any entity with collisions will move can be shot
|
||||
Entities.editEntity(intersection.entityID, {
|
||||
velocity: Vec3.multiply(shotDirection, GUN_FORCE)
|
||||
});
|
||||
}
|
||||
|
||||
if (intersection.properties.name === "rat") {
|
||||
score();
|
||||
createBloodSplatter(intersection.intersection);
|
||||
Entities.deleteEntity(intersection.entityID);
|
||||
|
||||
}
|
||||
//Attempt to call entity method's shot method
|
||||
var forceDirection = JSON.stringify({
|
||||
forceDirection: shotDirection
|
||||
});
|
||||
Entities.callEntityMethod(intersection.entityID, 'onShot', [forceDirection]);
|
||||
|
||||
}, 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function scriptEnding() {
|
||||
Messages.sendMessage('Hifi-Hand-Disabler', 'none');
|
||||
mapping.disable();
|
||||
for (var i = 0; i < pointers.length; ++i) {
|
||||
Overlays.deleteOverlay(pointers[i]);
|
||||
}
|
||||
MyAvatar.detachOne(GUN_MODEL);
|
||||
MyAvatar.detachOne(GUN_MODEL);
|
||||
clearPose();
|
||||
}
|
||||
|
||||
MyAvatar.attach(GUN_MODEL, "LeftHand", GUN_OFFSETS[0], GUN_ORIENTATIONS[0], 0.40);
|
||||
MyAvatar.attach(GUN_MODEL, "RightHand", GUN_OFFSETS[1], GUN_ORIENTATIONS[1], 0.40);
|
||||
|
||||
function showPointer(side) {
|
||||
Overlays.editOverlay(pointers[side], {
|
||||
visible: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
mapping.from(Controller.Standard.LT).hysteresis(0.0, 0.5).to(function(value) {
|
||||
fire(0, value);
|
||||
});
|
||||
|
||||
|
||||
mapping.from(Controller.Standard.RT).hysteresis(0.0, 0.5).to(function(value) {
|
||||
fire(1, value);
|
||||
});
|
||||
mapping.enable();
|
||||
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.update.connect(update);
|
||||
|
||||
|
||||
function createEntityHitEffect(position) {
|
||||
var flash = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: position,
|
||||
lifetime: 4,
|
||||
"name": "Flash Emitter",
|
||||
"color": {
|
||||
red: 228,
|
||||
green: 128,
|
||||
blue: 12
|
||||
},
|
||||
"maxParticles": 1000,
|
||||
"lifespan": 0.15,
|
||||
"emitRate": 1000,
|
||||
"emitSpeed": 1,
|
||||
"speedSpread": 0,
|
||||
"emitOrientation": {
|
||||
"x": -0.4,
|
||||
"y": 1,
|
||||
"z": -0.2,
|
||||
"w": 0.7071068286895752
|
||||
},
|
||||
"emitDimensions": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"polarStart": 0,
|
||||
"polarFinish": Math.PI,
|
||||
"azimuthStart": -3.1415927410125732,
|
||||
"azimuthFinish": 2,
|
||||
"emitAcceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"particleRadius": 0.03,
|
||||
"radiusSpread": 0.02,
|
||||
"radiusStart": 0.02,
|
||||
"radiusFinish": 0.03,
|
||||
"colorSpread": {
|
||||
red: 100,
|
||||
green: 100,
|
||||
blue: 20
|
||||
},
|
||||
"alpha": 1,
|
||||
"alphaSpread": 0,
|
||||
"alphaStart": 0,
|
||||
"alphaFinish": 0,
|
||||
"additiveBlending": true,
|
||||
"textures": "http://ericrius1.github.io/PartiArt/assets/star.png"
|
||||
});
|
||||
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(flash, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function createBloodSplatter(position) {
|
||||
var splatter = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: position,
|
||||
lifetime: 4,
|
||||
"name": "Blood Splatter",
|
||||
"color": {
|
||||
red: 230,
|
||||
green: 2,
|
||||
blue: 30
|
||||
},
|
||||
"maxParticles": 1000,
|
||||
"lifespan": 0.3,
|
||||
"emitRate": 1000,
|
||||
"emitSpeed": 0.5,
|
||||
"speedSpread": 0,
|
||||
"emitOrientation": {
|
||||
"x": -0.4,
|
||||
"y": 1,
|
||||
"z": -0.2,
|
||||
"w": 0.7071068286895752
|
||||
},
|
||||
"emitDimensions": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"polarStart": 0,
|
||||
"polarFinish": Math.PI,
|
||||
"azimuthStart": -3.1415927410125732,
|
||||
"azimuthFinish": 2,
|
||||
"emitAcceleration": {
|
||||
"x": 0,
|
||||
"y": -5,
|
||||
"z": 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"particleRadius": 0.05,
|
||||
"radiusSpread": 0.03,
|
||||
"radiusStart": 0.05,
|
||||
"radiusFinish": 0.05,
|
||||
"colorSpread": {
|
||||
red: 40,
|
||||
green: 0,
|
||||
blue: 30
|
||||
},
|
||||
"alpha": 1,
|
||||
"alphaSpread": 0,
|
||||
"alphaStart": 0,
|
||||
"alphaFinish": 0,
|
||||
"textures": "http://ericrius1.github.io/PartiArt/assets/star.png"
|
||||
});
|
||||
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(splatter, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100)
|
||||
|
||||
}
|
||||
|
||||
|
||||
function createMuzzleFlash(position) {
|
||||
var smoke = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: position,
|
||||
lifetime: 1,
|
||||
"name": "Smoke Hit Emitter",
|
||||
"maxParticles": 1000,
|
||||
"lifespan": 4,
|
||||
"emitRate": 20,
|
||||
emitSpeed: 0,
|
||||
"speedSpread": 0,
|
||||
"emitDimensions": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"polarStart": 0,
|
||||
"polarFinish": 0,
|
||||
"azimuthStart": -3.1415927410125732,
|
||||
"azimuthFinish": 3.14,
|
||||
"emitAcceleration": {
|
||||
"x": 0,
|
||||
"y": 0.5,
|
||||
"z": 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": .2,
|
||||
"y": 0,
|
||||
"z": .2
|
||||
},
|
||||
"radiusSpread": .04,
|
||||
"particleRadius": 0.07,
|
||||
"radiusStart": 0.07,
|
||||
"radiusFinish": 0.07,
|
||||
"alpha": 0.7,
|
||||
"alphaSpread": 0,
|
||||
"alphaStart": 0,
|
||||
"alphaFinish": 0,
|
||||
"additiveBlending": 0,
|
||||
"textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png"
|
||||
});
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(smoke, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100);
|
||||
|
||||
var flash = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: position,
|
||||
lifetime: 4,
|
||||
"name": "Muzzle Flash",
|
||||
"color": {
|
||||
red: 228,
|
||||
green: 128,
|
||||
blue: 12
|
||||
},
|
||||
"maxParticles": 1000,
|
||||
"lifespan": 0.1,
|
||||
"emitRate": 1000,
|
||||
"emitSpeed": 0.5,
|
||||
"speedSpread": 0,
|
||||
"emitOrientation": {
|
||||
"x": -0.4,
|
||||
"y": 1,
|
||||
"z": -0.2,
|
||||
"w": 0.7071068286895752
|
||||
},
|
||||
"emitDimensions": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"polarStart": 0,
|
||||
"polarFinish": Math.PI,
|
||||
"azimuthStart": -3.1415927410125732,
|
||||
"azimuthFinish": 2,
|
||||
"emitAcceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"particleRadius": 0.05,
|
||||
"radiusSpread": 0.01,
|
||||
"radiusStart": 0.05,
|
||||
"radiusFinish": 0.05,
|
||||
"colorSpread": {
|
||||
red: 100,
|
||||
green: 100,
|
||||
blue: 20
|
||||
},
|
||||
"alpha": 1,
|
||||
"alphaSpread": 0,
|
||||
"alphaStart": 0,
|
||||
"alphaFinish": 0,
|
||||
"additiveBlending": true,
|
||||
"textures": "http://ericrius1.github.io/PartiArt/assets/star.png"
|
||||
});
|
||||
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(flash, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100)
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// Rat.js
|
||||
// examples/toybox/entityScripts
|
||||
//
|
||||
// Created by Eric Levin on11/11/15.
|
||||
// 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
|
||||
/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */
|
||||
|
||||
|
||||
(function() {
|
||||
var scriptURL = Script.resolvePath('pistol.js');
|
||||
var _this;
|
||||
PistolScriptSpawner = function() {
|
||||
_this = this;
|
||||
this.forceMultiplier = 1;
|
||||
};
|
||||
|
||||
PistolScriptSpawner.prototype = {
|
||||
|
||||
enterEntity: function() {
|
||||
|
||||
Script.load(scriptURL);
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new PistolScriptSpawner();
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation())));
|
||||
var scriptURL = Script.resolvePath("pistolScriptSpawner.js");
|
||||
var modelURL = "http://s3.amazonaws.com/hifi-public/cozza13/gun/m1911-handgun+1.fbx";
|
||||
var pistolSpawnerEntity = Entities.addEntity({
|
||||
type: 'Box',
|
||||
position: center,
|
||||
dimensions: {x: 0.38, y: 1.9, z: 3.02},
|
||||
script: scriptURL,
|
||||
visible: false,
|
||||
ignoreForCollisions: true
|
||||
});
|
||||
|
||||
var pistol = Entities.addEntity({
|
||||
type: 'Model',
|
||||
modelURL: modelURL,
|
||||
position: center,
|
||||
dimensions: {x: 0.38, y: 1.9, z: 3.02},
|
||||
script: scriptURL,
|
||||
color: {red: 200, green: 0, blue: 20},
|
||||
ignoreForCollisions: true
|
||||
});
|
||||
|
||||
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(pistolSpawnerEntity);
|
||||
Entities.deleteEntity(pistol);
|
||||
}
|
||||
|
||||
// Script.update.connect(update);
|
||||
Script.scriptEnding.connect(cleanup);
|
|
@ -67,12 +67,12 @@ var colorPalette = [{
|
|||
var MIN_STROKE_WIDTH = 0.002;
|
||||
var MAX_STROKE_WIDTH = 0.05;
|
||||
|
||||
function controller(side, cycleColorButton) {
|
||||
function controller(side, triggerAction) {
|
||||
this.triggerHeld = false;
|
||||
this.triggerThreshold = 0.9;
|
||||
this.side = side;
|
||||
this.trigger = side == LEFT ? Controller.Stantard.LT : Controller.Standard.RT;
|
||||
this.cycleColorButton = side == LEFT ? Controller.Stantard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb;
|
||||
this.triggerAction = triggerAction;
|
||||
this.cycleColorButton = side == LEFT ? Controller.Standard.LeftPrimaryThumb : Controller.Standard.RightPrimaryThumb;
|
||||
|
||||
this.points = [];
|
||||
this.normals = [];
|
||||
|
@ -116,6 +116,7 @@ function controller(side, cycleColorButton) {
|
|||
y: LINE_DIMENSIONS,
|
||||
z: LINE_DIMENSIONS
|
||||
},
|
||||
textures: "http://localhost:8080/trails.png",
|
||||
lifetime: LIFETIME
|
||||
});
|
||||
this.points = [];
|
||||
|
@ -174,7 +175,7 @@ function controller(side, cycleColorButton) {
|
|||
this.cycleColorButtonPressed = Controller.getValue(this.cycleColorButton);
|
||||
this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation;
|
||||
this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation;
|
||||
this.triggerValue = Controller.getValue(this.trigger);
|
||||
this.triggerValue = Controller.getActionValue(this.triggerAction);
|
||||
|
||||
|
||||
if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) {
|
||||
|
@ -212,8 +213,8 @@ function vectorIsZero(v) {
|
|||
}
|
||||
|
||||
|
||||
var rightController = new controller(RIGHT);
|
||||
var leftController = new controller(LEFT);
|
||||
var rightController = new controller(RIGHT, Controller.findAction("RIGHT_HAND_CLICK"));
|
||||
var leftController = new controller(LEFT, Controller.findAction("LEFT_HAND_CLICK"));
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
|
|
|
@ -1,81 +1,138 @@
|
|||
|
||||
(function () {
|
||||
(function() {
|
||||
var spawnPoint = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation())));
|
||||
|
||||
// constructor
|
||||
|
||||
function TestBox() {
|
||||
this.entity = Entities.addEntity({ type: "Box",
|
||||
position: spawnPoint,
|
||||
dimentions: { x: 1, y: 1, z: 1 },
|
||||
color: { red: 100, green: 100, blue: 255 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
visible: true,
|
||||
locked: false,
|
||||
lifetime: 6000});
|
||||
this.entity = Entities.addEntity({
|
||||
type: "Box",
|
||||
position: spawnPoint,
|
||||
dimentions: {
|
||||
x: 1,
|
||||
y: 1,
|
||||
z: 1
|
||||
},
|
||||
color: {
|
||||
red: 100,
|
||||
green: 100,
|
||||
blue: 255
|
||||
},
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
visible: true,
|
||||
locked: false,
|
||||
lifetime: 6000
|
||||
});
|
||||
var self = this;
|
||||
this.timer = Script.setInterval(function () {
|
||||
var colorProp = { color: { red: Math.random() * 255,
|
||||
green: Math.random() * 255,
|
||||
blue: Math.random() * 255 } };
|
||||
this.timer = Script.setInterval(function() {
|
||||
var colorProp = {
|
||||
color: {
|
||||
red: Math.random() * 255,
|
||||
green: Math.random() * 255,
|
||||
blue: Math.random() * 255
|
||||
}
|
||||
};
|
||||
Entities.editEntity(self.entity, colorProp);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
TestBox.prototype.Destroy = function () {
|
||||
TestBox.prototype.Destroy = function() {
|
||||
Script.clearInterval(this.timer);
|
||||
Entities.editEntity(this.entity, { locked: false });
|
||||
Entities.editEntity(this.entity, {
|
||||
locked: false
|
||||
});
|
||||
Entities.deleteEntity(this.entity);
|
||||
}
|
||||
|
||||
// constructor
|
||||
|
||||
function TestFx(color, emitDirection, emitRate, emitStrength, blinkRate) {
|
||||
var PI = 3.141593;
|
||||
var DEG_TO_RAD = PI / 180.0;
|
||||
|
||||
this.entity = Entities.addEntity({ type: "ParticleEffect",
|
||||
isEmitting: true,
|
||||
position: spawnPoint,
|
||||
dimensions: {x: 2, y: 2, z: 2},
|
||||
emitSpeed: 0.05,
|
||||
maxParticles: 2,
|
||||
speedSpread: 2,
|
||||
polarFinish: 30 * DEG_TO_RAD,
|
||||
emitAcceleration: {x: 0, y: -9.8, z: 0},
|
||||
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
||||
color: color,
|
||||
lifespan: 1.0,
|
||||
visible: true,
|
||||
locked: false });
|
||||
this.entity = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
isEmitting: true,
|
||||
position: spawnPoint,
|
||||
dimensions: {
|
||||
x: 2,
|
||||
y: 2,
|
||||
z: 2
|
||||
},
|
||||
emitSpeed: 0.05,
|
||||
maxParticles: 2,
|
||||
speedSpread: 2,
|
||||
polarFinish: 30 * DEG_TO_RAD,
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
z: 0
|
||||
},
|
||||
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
||||
color: color,
|
||||
lifespan: 1.0,
|
||||
visible: true,
|
||||
locked: false
|
||||
});
|
||||
|
||||
this.isPlaying = true;
|
||||
|
||||
var self = this;
|
||||
this.timer = Script.setInterval(function () {
|
||||
this.timer = Script.setInterval(function() {
|
||||
// flip is playing state
|
||||
self.isPlaying = !self.isPlaying;
|
||||
var emittingProp = { isEmitting: self.isPlaying };
|
||||
var emittingProp = {
|
||||
isEmitting: self.isPlaying
|
||||
};
|
||||
Entities.editEntity(self.entity, emittingProp);
|
||||
}, (1 / blinkRate) * 1000);
|
||||
}
|
||||
|
||||
TestFx.prototype.Destroy = function () {
|
||||
TestFx.prototype.Destroy = function() {
|
||||
Script.clearInterval(this.timer);
|
||||
Entities.editEntity(this.entity, { locked: false });
|
||||
Entities.editEntity(this.entity, {
|
||||
locked: false
|
||||
});
|
||||
Entities.deleteEntity(this.entity);
|
||||
}
|
||||
|
||||
var objs = [];
|
||||
|
||||
function Init() {
|
||||
objs.push(new TestBox());
|
||||
objs.push(new TestFx({ red: 255, green: 0, blue: 0 },
|
||||
{ x: 0.5, y: 1.0, z: 0.0 },
|
||||
100, 3, 1));
|
||||
objs.push(new TestFx({ red: 0, green: 255, blue: 0 },
|
||||
{ x: 0, y: 1, z: 0 },
|
||||
1000, 5, 0.5));
|
||||
objs.push(new TestFx({ red: 0, green: 0, blue: 255 },
|
||||
{ x: -0.5, y: 1, z: 0 },
|
||||
100, 3, 1));
|
||||
objs.push(new TestFx({
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0
|
||||
}, {
|
||||
x: 0.5,
|
||||
y: 1.0,
|
||||
z: 0.0
|
||||
},
|
||||
100, 3, 1));
|
||||
objs.push(new TestFx({
|
||||
red: 0,
|
||||
green: 255,
|
||||
blue: 0
|
||||
}, {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
},
|
||||
1000, 5, 0.5));
|
||||
objs.push(new TestFx({
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 255
|
||||
}, {
|
||||
x: -0.5,
|
||||
y: 1,
|
||||
z: 0
|
||||
},
|
||||
100, 3, 1));
|
||||
}
|
||||
|
||||
function ShutDown() {
|
||||
|
@ -88,6 +145,4 @@
|
|||
|
||||
Init();
|
||||
Script.scriptEnding.connect(ShutDown);
|
||||
})();
|
||||
|
||||
|
||||
})();
|
|
@ -36,14 +36,10 @@
|
|||
Entities.editEntity(this.entityID, {
|
||||
animation: {
|
||||
url: "https://hifi-public.s3.amazonaws.com/models/Bboys/zombie_scream.fbx",
|
||||
currentFrame: 0
|
||||
running: true
|
||||
}
|
||||
});
|
||||
|
||||
Entities.editEntity(_this.entityID, {
|
||||
animationIsPlaying: true
|
||||
});
|
||||
|
||||
var position = Entities.getEntityProperties(this.entityID, "position").position;
|
||||
this.audioInjector = Audio.playSound(this.screamSounds[randInt(0, this.screamSounds.length)], {
|
||||
position: position,
|
||||
|
@ -67,8 +63,10 @@
|
|||
this.audioInjector.stop();
|
||||
Entities.editEntity(this.entityID, {
|
||||
animation: {
|
||||
url: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx",
|
||||
currentFrame: 0
|
||||
// Providing actual model fbx for animation used to work, now contorts doll into a weird ball
|
||||
// See bug: https://app.asana.com/0/26225263936266/70097355490098
|
||||
// url: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx",
|
||||
running: false,
|
||||
}
|
||||
});
|
||||
|
||||
|
|
46
examples/toybox/pistol/createPistol.js
Normal file
46
examples/toybox/pistol/createPistol.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(Camera.getOrientation())));
|
||||
var scriptURL = Script.resolvePath('pistol.js');
|
||||
var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/gun.fbx";
|
||||
|
||||
|
||||
var pistol = Entities.addEntity({
|
||||
type: 'Model',
|
||||
modelURL: modelURL,
|
||||
position: center,
|
||||
dimensions: {
|
||||
x: 0.05,
|
||||
y: .23,
|
||||
z: .36
|
||||
},
|
||||
script: scriptURL,
|
||||
color: {
|
||||
red: 200,
|
||||
green: 0,
|
||||
blue: 20
|
||||
},
|
||||
shapeType: 'box',
|
||||
collisionsWillMove: true,
|
||||
gravity: {x: 0, y: -5.0, z: 0},
|
||||
restitution: 0,
|
||||
collisionSoundURL: "https://s3.amazonaws.com/hifi-public/sounds/Guns/Gun_Drop_and_Metalli_1.wav",
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(45, 90, 0)
|
||||
},
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(pistol);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
354
examples/toybox/pistol/pistol.js
Normal file
354
examples/toybox/pistol/pistol.js
Normal file
|
@ -0,0 +1,354 @@
|
|||
//
|
||||
// pistol.js
|
||||
// examples/toybox/entityScripts
|
||||
//
|
||||
// Created by Eric Levin on11/11/15.
|
||||
// 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
|
||||
/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */
|
||||
|
||||
|
||||
(function() {
|
||||
Script.include("../../libraries/utils.js");
|
||||
Script.include("../../libraries/constants.js");
|
||||
|
||||
var _this;
|
||||
// if the trigger value goes below this while held, the can will stop spraying. if it goes above, it will spray
|
||||
var DISABLE_LASER_THRESHOLD = 0.2;
|
||||
var TRIGGER_CONTROLS = [
|
||||
Controller.Standard.LT,
|
||||
Controller.Standard.RT,
|
||||
];
|
||||
var RELOAD_THRESHOLD = 0.95;
|
||||
|
||||
Pistol = function() {
|
||||
_this = this;
|
||||
this.equipped = false;
|
||||
this.forceMultiplier = 1;
|
||||
this.laserLength = 100;
|
||||
this.laserOffsets = {
|
||||
y: .095
|
||||
};
|
||||
this.firingOffsets = {
|
||||
z: 0.16
|
||||
}
|
||||
this.fireSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Guns/GUN-SHOT2.raw");
|
||||
this.ricochetSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Guns/Ricochet.L.wav");
|
||||
this.playRichochetSoundChance = 0.1;
|
||||
this.fireVolume = 0.2;
|
||||
this.bulletForce = 10;
|
||||
|
||||
|
||||
|
||||
this.showLaser = false;
|
||||
};
|
||||
|
||||
Pistol.prototype = {
|
||||
canShoot: false,
|
||||
|
||||
startEquip: function(id, params) {
|
||||
this.equipped = true;
|
||||
this.hand = JSON.parse(params[0]);
|
||||
},
|
||||
|
||||
continueNearGrab: function() {
|
||||
if (!this.equipped) {
|
||||
return;
|
||||
}
|
||||
this.toggleWithTriggerPressure();
|
||||
if (this.showLaser) {
|
||||
this.updateLaser();
|
||||
}
|
||||
},
|
||||
toggleWithTriggerPressure: function() {
|
||||
this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.hand]);
|
||||
|
||||
if (this.triggerValue < RELOAD_THRESHOLD) {
|
||||
// print('RELOAD');
|
||||
this.canShoot = true;
|
||||
}
|
||||
if (this.canShoot === true && this.triggerValue === 1) {
|
||||
// print('SHOOT');
|
||||
this.fire();
|
||||
this.canShoot = false;
|
||||
}
|
||||
|
||||
if (this.triggerValue < DISABLE_LASER_THRESHOLD && this.showLaser === true) {
|
||||
this.showLaser = false;
|
||||
Overlays.editOverlay(this.laser, {
|
||||
visible: false
|
||||
});
|
||||
} else if (this.triggerValue >= DISABLE_LASER_THRESHOLD && this.showLaser === false) {
|
||||
this.showLaser = true
|
||||
Overlays.editOverlay(this.laser, {
|
||||
visible: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
updateLaser: function() {
|
||||
var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
|
||||
var position = gunProps.position;
|
||||
var rotation = gunProps.rotation;
|
||||
this.firingDirection = Quat.getFront(rotation);
|
||||
var upVec = Quat.getUp(rotation);
|
||||
this.barrelPoint = Vec3.sum(position, Vec3.multiply(upVec, this.laserOffsets.y));
|
||||
var laserTip = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.laserLength));
|
||||
this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z))
|
||||
Overlays.editOverlay(this.laser, {
|
||||
start: this.barrelPoint,
|
||||
end: laserTip,
|
||||
alpha: 1
|
||||
});
|
||||
},
|
||||
|
||||
unequip: function() {
|
||||
this.hand = null;
|
||||
this.equipped = false;
|
||||
Overlays.editOverlay(this.laser, {
|
||||
visible: false
|
||||
});
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
// this.initControllerMapping();
|
||||
this.laser = Overlays.addOverlay("line3d", {
|
||||
start: ZERO_VECTOR,
|
||||
end: ZERO_VECTOR,
|
||||
color: COLORS.RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: 2
|
||||
});
|
||||
},
|
||||
|
||||
triggerPress: function(hand, value) {
|
||||
if (this.hand === hand && value === 1) {
|
||||
//We are pulling trigger on the hand we have the gun in, so fire
|
||||
this.fire();
|
||||
}
|
||||
},
|
||||
|
||||
fire: function() {
|
||||
var pickRay = {
|
||||
origin: this.barrelPoint,
|
||||
direction: this.firingDirection
|
||||
};
|
||||
Audio.playSound(this.fireSound, {
|
||||
position: this.barrelPoint,
|
||||
volume: this.fireVolume
|
||||
});
|
||||
|
||||
this.createGunFireEffect(this.barrelPoint)
|
||||
var intersection = Entities.findRayIntersectionBlocking(pickRay, true);
|
||||
if (intersection.intersects) {
|
||||
this.createEntityHitEffect(intersection.intersection);
|
||||
if (Math.random() < this.playRichochetSoundChance) {
|
||||
Script.setTimeout(function() {
|
||||
Audio.playSound(_this.ricochetSound, {
|
||||
position: intersection.intersection,
|
||||
volume: _this.fireVolume
|
||||
});
|
||||
}, randFloat(10, 200));
|
||||
}
|
||||
if (intersection.properties.collisionsWillMove === 1) {
|
||||
// Any entity with collisions will move can be shot
|
||||
Entities.editEntity(intersection.entityID, {
|
||||
velocity: Vec3.multiply(this.firingDirection, this.bulletForce)
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
unload: function() {
|
||||
Overlays.deleteOverlay(this.laser);
|
||||
},
|
||||
|
||||
createEntityHitEffect: function(position) {
|
||||
var flash = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: position,
|
||||
lifetime: 4,
|
||||
"name": "Flash Emitter",
|
||||
"color": {
|
||||
red: 228,
|
||||
green: 128,
|
||||
blue: 12
|
||||
},
|
||||
"maxParticles": 1000,
|
||||
"lifespan": 0.15,
|
||||
"emitRate": 1000,
|
||||
"emitSpeed": 1,
|
||||
"speedSpread": 0,
|
||||
"emitOrientation": {
|
||||
"x": -0.4,
|
||||
"y": 1,
|
||||
"z": -0.2,
|
||||
"w": 0.7071068286895752
|
||||
},
|
||||
"emitDimensions": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"polarStart": 0,
|
||||
"polarFinish": Math.PI,
|
||||
"azimuthStart": -3.1415927410125732,
|
||||
"azimuthFinish": 2,
|
||||
"emitAcceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"particleRadius": 0.03,
|
||||
"radiusSpread": 0.02,
|
||||
"radiusStart": 0.02,
|
||||
"radiusFinish": 0.03,
|
||||
"colorSpread": {
|
||||
red: 100,
|
||||
green: 100,
|
||||
blue: 20
|
||||
},
|
||||
"alpha": 1,
|
||||
"alphaSpread": 0,
|
||||
"alphaStart": 0,
|
||||
"alphaFinish": 0,
|
||||
"additiveBlending": true,
|
||||
"textures": "http://ericrius1.github.io/PartiArt/assets/star.png"
|
||||
});
|
||||
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(flash, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100);
|
||||
|
||||
},
|
||||
|
||||
createGunFireEffect: function(position) {
|
||||
var smoke = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: position,
|
||||
lifetime: 1,
|
||||
"name": "Smoke Hit Emitter",
|
||||
"maxParticles": 1000,
|
||||
"lifespan": 4,
|
||||
"emitRate": 20,
|
||||
emitSpeed: 0,
|
||||
"speedSpread": 0,
|
||||
"emitDimensions": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"polarStart": 0,
|
||||
"polarFinish": 0,
|
||||
"azimuthStart": -3.1415927410125732,
|
||||
"azimuthFinish": 3.14,
|
||||
"emitAcceleration": {
|
||||
"x": 0,
|
||||
"y": 0.5,
|
||||
"z": 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": .2,
|
||||
"y": 0,
|
||||
"z": .2
|
||||
},
|
||||
"radiusSpread": .04,
|
||||
"particleRadius": 0.07,
|
||||
"radiusStart": 0.07,
|
||||
"radiusFinish": 0.07,
|
||||
"alpha": 0.7,
|
||||
"alphaSpread": 0,
|
||||
"alphaStart": 0,
|
||||
"alphaFinish": 0,
|
||||
"additiveBlending": 0,
|
||||
"textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png"
|
||||
});
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(smoke, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100);
|
||||
|
||||
var flash = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: position,
|
||||
lifetime: 4,
|
||||
"name": "Muzzle Flash",
|
||||
"color": {
|
||||
red: 228,
|
||||
green: 128,
|
||||
blue: 12
|
||||
},
|
||||
"maxParticles": 1000,
|
||||
"lifespan": 0.1,
|
||||
"emitRate": 1000,
|
||||
"emitSpeed": 0.5,
|
||||
"speedSpread": 0,
|
||||
"emitOrientation": {
|
||||
"x": -0.4,
|
||||
"y": 1,
|
||||
"z": -0.2,
|
||||
"w": 0.7071068286895752
|
||||
},
|
||||
"emitDimensions": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"polarStart": 0,
|
||||
"polarFinish": Math.PI,
|
||||
"azimuthStart": -3.1415927410125732,
|
||||
"azimuthFinish": 2,
|
||||
"emitAcceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"particleRadius": 0.05,
|
||||
"radiusSpread": 0.01,
|
||||
"radiusStart": 0.05,
|
||||
"radiusFinish": 0.05,
|
||||
"colorSpread": {
|
||||
red: 100,
|
||||
green: 100,
|
||||
blue: 20
|
||||
},
|
||||
"alpha": 1,
|
||||
"alphaSpread": 0,
|
||||
"alphaStart": 0,
|
||||
"alphaFinish": 0,
|
||||
"additiveBlending": true,
|
||||
"textures": "http://ericrius1.github.io/PartiArt/assets/star.png"
|
||||
});
|
||||
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(flash, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100)
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new Pistol();
|
||||
});
|
117
examples/weapons/shootingRangeSpawner.js
Normal file
117
examples/weapons/shootingRangeSpawner.js
Normal file
|
@ -0,0 +1,117 @@
|
|||
Script.include("../libraries/utils.js");
|
||||
|
||||
var shootingRangeURL = "https://s3.amazonaws.com/hifi-public/eric/models/shootingRange/shootingRange.fbx";
|
||||
var floorURL = "https://s3.amazonaws.com/hifi-public/eric/models/shootingRange/shootingRange.fbx";
|
||||
MyAvatar.bodyYaw = 0;
|
||||
var rangePosition = Vec3.sum(MyAvatar.position, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: -30
|
||||
});
|
||||
var rangeDimensions = {
|
||||
x: 44,
|
||||
y: 29,
|
||||
z: 96
|
||||
}
|
||||
var shootingRange = Entities.addEntity({
|
||||
type: 'Model',
|
||||
modelURL: shootingRangeURL,
|
||||
position: rangePosition,
|
||||
dimensions: rangeDimensions
|
||||
});
|
||||
|
||||
|
||||
var floorPosition = Vec3.subtract(rangePosition, {
|
||||
x: 0,
|
||||
y: 2,
|
||||
z: 0
|
||||
});
|
||||
var shootingRangeFloor = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: floorURL,
|
||||
shapeType: 'box',
|
||||
position: floorPosition,
|
||||
dimensions: {
|
||||
x: 93,
|
||||
y: 1,
|
||||
z: 93
|
||||
}
|
||||
})
|
||||
|
||||
var monsters = [];
|
||||
var numMonsters = 10;
|
||||
var monsterURLS = ["https://s3.amazonaws.com/hifi-public/eric/models/shootingRange/monster1.fbx", "https://s3.amazonaws.com/hifi-public/eric/models/shootingRange/monster2.fbx"]
|
||||
initMonsters();
|
||||
|
||||
function initMonsters() {
|
||||
for (var i = 0; i < numMonsters; i++) {
|
||||
|
||||
var index = randInt(0, monsterURLS.length);
|
||||
var monsterURL = monsterURLS[index]
|
||||
var monsterPosition = Vec3.sum(rangePosition, {
|
||||
x: -rangeDimensions.x / 2 - i * randFloat(5, 10),
|
||||
y: 0,
|
||||
z: randFloat(-10, 10)
|
||||
});
|
||||
var monster = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: monsterURL,
|
||||
position: monsterPosition,
|
||||
dimensions: {
|
||||
x: 1.5,
|
||||
y: 1.6,
|
||||
z: 0.07
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
shapeType: 'box',
|
||||
velocity: {
|
||||
x: randFloat(1, 3),
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
damping: 0
|
||||
});
|
||||
|
||||
monsters.push(monster);
|
||||
}
|
||||
}
|
||||
|
||||
function checkMonsters() {
|
||||
|
||||
// check monsters to see if they've gone out of bounds, if so, set them back to starting point
|
||||
monsters.forEach(function(monster) {
|
||||
var position = Entities.getEntityProperties(monster, "position").position;
|
||||
if (position.x > rangePosition.x + rangeDimensions.x / 2 ||
|
||||
position.z < rangePosition.z - rangeDimensions.z / 2 ||
|
||||
position.y < rangePosition.y - rangeDimensions.y / 2 || position.y > rangePosition.y + rangeDimensions.y / 2) {
|
||||
var monsterPosition = Vec3.sum(rangePosition, {
|
||||
x: -rangeDimensions.x / 2 - randFloat(5, 10),
|
||||
y: 0,
|
||||
z: randFloat(-10, 10)
|
||||
});
|
||||
Entities.editEntity(monster, {
|
||||
position: monsterPosition,
|
||||
velocity: {
|
||||
x: randFloat(1, 3),
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
angularVelocity: {x: 0, y: 0, z:0},
|
||||
rotation: Quat.fromPitchYawRollDegrees(0, 0, 0),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var checkMonsterInterval = Script.setInterval(checkMonsters, 1000);
|
||||
|
||||
function cleanup() {
|
||||
Script.clearInterval(checkMonsterInterval);
|
||||
Entities.deleteEntity(shootingRange);
|
||||
Entities.deleteEntity(shootingRangeFloor);
|
||||
monsters.forEach(function(monster) {
|
||||
Entities.deleteEntity(monster);
|
||||
});
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
|
@ -2856,6 +2856,8 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
_controllerScriptingInterface->updateInputControllers();
|
||||
|
||||
// Transfer the user inputs to the driveKeys
|
||||
// FIXME can we drop drive keys and just have the avatar read the action states directly?
|
||||
myAvatar->clearDriveKeys();
|
||||
|
|
|
@ -106,6 +106,7 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
|
|||
doKinematicUpdate(deltaTimeStep);
|
||||
} else {
|
||||
activateBody();
|
||||
forceBodyNonStatic();
|
||||
ObjectActionSpring::updateActionWorker(deltaTimeStep);
|
||||
}
|
||||
}
|
||||
|
@ -156,6 +157,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
|
|||
});
|
||||
|
||||
activateBody();
|
||||
forceBodyNonStatic();
|
||||
}
|
||||
|
||||
bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
||||
|
@ -328,5 +330,6 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) {
|
|||
_active = true;
|
||||
});
|
||||
|
||||
activateBody();
|
||||
forceBodyNonStatic();
|
||||
}
|
||||
|
|
|
@ -44,9 +44,11 @@ void AvatarUpdate::synchronousProcess() {
|
|||
bool AvatarUpdate::process() {
|
||||
PerformanceTimer perfTimer("AvatarUpdate");
|
||||
quint64 start = usecTimestampNow();
|
||||
quint64 deltaMicroseconds = 0;
|
||||
quint64 deltaMicroseconds = 10000;
|
||||
if (_lastAvatarUpdate > 0) {
|
||||
deltaMicroseconds = start - _lastAvatarUpdate;
|
||||
} else {
|
||||
deltaMicroseconds = 10000; // 10 ms
|
||||
}
|
||||
float deltaSeconds = (float) deltaMicroseconds / (float) USECS_PER_SECOND;
|
||||
_lastAvatarUpdate = start;
|
||||
|
|
|
@ -84,13 +84,12 @@ glm::vec2 ControllerScriptingInterface::getViewportDimensions() const {
|
|||
return qApp->getUiSize();
|
||||
}
|
||||
|
||||
controller::InputController::Pointer ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {
|
||||
// This is where we retreive the Device Tracker category and then the sub tracker within it
|
||||
controller::InputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) {
|
||||
// This is where we retrieve the Device Tracker category and then the sub tracker within it
|
||||
auto icIt = _inputControllers.find(0);
|
||||
if (icIt != _inputControllers.end()) {
|
||||
return (*icIt).second;
|
||||
}
|
||||
|
||||
return (*icIt).second.get();
|
||||
}
|
||||
|
||||
// Look for device
|
||||
DeviceTracker::ID deviceID = DeviceTracker::getDeviceID(deviceName.toStdString());
|
||||
|
@ -110,18 +109,24 @@ controller::InputController::Pointer ControllerScriptingInterface::createInputCo
|
|||
controller::InputController::Pointer inputController = std::make_shared<InputController>(deviceID, trackerID, this);
|
||||
controller::InputController::Key key = inputController->getKey();
|
||||
_inputControllers.insert(InputControllerMap::value_type(key, inputController));
|
||||
return inputController;
|
||||
return inputController.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return controller::InputController::Pointer();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::releaseInputController(controller::InputController::Pointer input) {
|
||||
void ControllerScriptingInterface::releaseInputController(controller::InputController* input) {
|
||||
_inputControllers.erase(input->getKey());
|
||||
}
|
||||
|
||||
void ControllerScriptingInterface::updateInputControllers() {
|
||||
for (auto it = _inputControllers.begin(); it != _inputControllers.end(); it++) {
|
||||
(*it).second->update();
|
||||
}
|
||||
}
|
||||
|
||||
InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
|
||||
_deviceTrackerId(deviceTrackerId),
|
||||
_subTrackerId(subTrackerId),
|
||||
|
|
|
@ -85,6 +85,8 @@ public:
|
|||
bool isKeyCaptured(const KeyEvent& event) const;
|
||||
bool isJoystickCaptured(int joystickIndex) const;
|
||||
|
||||
void updateInputControllers();
|
||||
|
||||
public slots:
|
||||
|
||||
virtual void captureKeyEvents(const KeyEvent& event);
|
||||
|
@ -96,8 +98,8 @@ public slots:
|
|||
virtual glm::vec2 getViewportDimensions() const;
|
||||
|
||||
/// Factory to create an InputController
|
||||
virtual controller::InputController::Pointer createInputController(const QString& deviceName, const QString& tracker);
|
||||
virtual void releaseInputController(controller::InputController::Pointer input);
|
||||
virtual controller::InputController* createInputController(const QString& deviceName, const QString& tracker);
|
||||
virtual void releaseInputController(controller::InputController* input);
|
||||
|
||||
signals:
|
||||
void keyPressEvent(const KeyEvent& event);
|
||||
|
|
|
@ -116,7 +116,7 @@ void AvatarData::setOrientation(const glm::quat& orientation, bool overideRefere
|
|||
glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation));
|
||||
_bodyPitch = eulerAngles.x;
|
||||
_bodyYaw = eulerAngles.y;
|
||||
_bodyRoll = eulerAngles.z;
|
||||
_bodyRoll = eulerAngles.z;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1212,7 +1212,14 @@ void AvatarData::setJointMappingsFromNetworkReply() {
|
|||
|
||||
QByteArray line;
|
||||
while (!(line = networkReply->readLine()).isEmpty()) {
|
||||
if (!(line = line.trimmed()).startsWith("jointIndex")) {
|
||||
line = line.trimmed();
|
||||
if (line.startsWith("filename")) {
|
||||
int filenameIndex = line.indexOf('=') + 1;
|
||||
if (filenameIndex > 0) {
|
||||
_skeletonFBXURL = _skeletonModelURL.resolved(QString(line.mid(filenameIndex).trimmed()));
|
||||
}
|
||||
}
|
||||
if (!line.startsWith("jointIndex")) {
|
||||
continue;
|
||||
}
|
||||
int jointNameIndex = line.indexOf('=') + 1;
|
||||
|
@ -1522,6 +1529,17 @@ QJsonObject AvatarData::toJson() const {
|
|||
}
|
||||
|
||||
void AvatarData::fromJson(const QJsonObject& json) {
|
||||
// The head setOrientation likes to overwrite the avatar orientation,
|
||||
// so lets do the head first
|
||||
// Most head data is relative to the avatar, and needs no basis correction,
|
||||
// but the lookat vector does need correction
|
||||
if (json.contains(JSON_AVATAR_HEAD)) {
|
||||
if (!_headData) {
|
||||
_headData = new HeadData(this);
|
||||
}
|
||||
_headData->fromJson(json[JSON_AVATAR_HEAD].toObject());
|
||||
}
|
||||
|
||||
if (json.contains(JSON_AVATAR_HEAD_MODEL)) {
|
||||
auto faceModelURL = json[JSON_AVATAR_HEAD_MODEL].toString();
|
||||
if (faceModelURL != getFaceModelURL().toString()) {
|
||||
|
@ -1593,15 +1611,6 @@ void AvatarData::fromJson(const QJsonObject& json) {
|
|||
}
|
||||
setRawJointData(jointArray);
|
||||
}
|
||||
|
||||
// Most head data is relative to the avatar, and needs no basis correction,
|
||||
// but the lookat vector does need correction
|
||||
if (json.contains(JSON_AVATAR_HEAD)) {
|
||||
if (!_headData) {
|
||||
_headData = new HeadData(this);
|
||||
}
|
||||
_headData->fromJson(json[JSON_AVATAR_HEAD].toObject());
|
||||
}
|
||||
}
|
||||
|
||||
// Every frame will store both a basis for the recording and a relative transform
|
||||
|
|
|
@ -392,6 +392,7 @@ protected:
|
|||
|
||||
QUrl _faceModelURL; // These need to be empty so that on first time setting them they will not short circuit
|
||||
QUrl _skeletonModelURL; // These need to be empty so that on first time setting them they will not short circuit
|
||||
QUrl _skeletonFBXURL;
|
||||
QVector<AttachmentData> _attachmentData;
|
||||
QString _displayName;
|
||||
|
||||
|
|
|
@ -248,7 +248,7 @@ QByteArray OctreePersistThread::getPersistFileContents() const {
|
|||
}
|
||||
|
||||
void OctreePersistThread::persist() {
|
||||
if (_tree->isDirty()) {
|
||||
if (_tree->isDirty() && _initialLoadComplete) {
|
||||
|
||||
_tree->withWriteLock([&] {
|
||||
qCDebug(octree) << "pruning Octree before saving...";
|
||||
|
|
|
@ -81,6 +81,9 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) {
|
|||
out = qobject_cast<AvatarData*>(object.toQObject());
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(controller::InputController*)
|
||||
static int inputControllerPointerId = qRegisterMetaType<controller::InputController*>();
|
||||
|
||||
QScriptValue inputControllerToScriptValue(QScriptEngine *engine, controller::InputController* const &in) {
|
||||
return engine->newQObject(in);
|
||||
}
|
||||
|
@ -89,8 +92,6 @@ void inputControllerFromScriptValue(const QScriptValue &object, controller::Inpu
|
|||
out = qobject_cast<controller::InputController*>(object.toQObject());
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool hasCorrectSyntax(const QScriptProgram& program) {
|
||||
const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode());
|
||||
if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
var _this;
|
||||
|
||||
var gunScriptURL = Script.resolvePath("../examples/toybox/pistol/pistol.js");
|
||||
var sprayPaintScriptURL = Script.resolvePath("../examples/toybox/spray_paint/sprayPaintCan.js");
|
||||
var catScriptURL = Script.resolvePath("../examples/toybox/cat/cat.js");
|
||||
var flashlightScriptURL = Script.resolvePath('../examples/toybox/flashlight/flashlight.js');
|
||||
|
@ -85,6 +86,12 @@
|
|||
z: 505.09
|
||||
});
|
||||
|
||||
createGun({
|
||||
x: 546.2,
|
||||
y: 495.5,
|
||||
z: 505.2
|
||||
});
|
||||
|
||||
createWand({
|
||||
x: 546.71,
|
||||
y: 495.55,
|
||||
|
@ -125,11 +132,12 @@
|
|||
createLights();
|
||||
|
||||
createCat({
|
||||
x: 551.09,
|
||||
y: 494.98,
|
||||
z: 503.49
|
||||
x: 551.0,
|
||||
y: 495.3,
|
||||
z: 503.3
|
||||
});
|
||||
|
||||
|
||||
createSprayCan({
|
||||
x: 549.7,
|
||||
y: 495.6,
|
||||
|
@ -152,6 +160,52 @@
|
|||
});
|
||||
}
|
||||
|
||||
function createGun(position) {
|
||||
var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/gun.fbx";
|
||||
|
||||
var pistol = Entities.addEntity({
|
||||
type: 'Model',
|
||||
name: "pistol",
|
||||
modelURL: modelURL,
|
||||
position: position,
|
||||
collisionSoundURL: "https://s3.amazonaws.com/hifi-public/sounds/Guns/Gun_Drop_and_Metalli_1.wav",
|
||||
dimensions: {
|
||||
x: 0.05,
|
||||
y: 0.23,
|
||||
z: 0.36
|
||||
},
|
||||
script: gunScriptURL,
|
||||
color: {
|
||||
red: 200,
|
||||
green: 0,
|
||||
blue: 20
|
||||
},
|
||||
shapeType: 'box',
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -3.0,
|
||||
z: 0
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(45, 90, 0)
|
||||
},
|
||||
invertSolidWhileHeld: true
|
||||
},
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function createBow() {
|
||||
|
||||
var startPosition = {
|
||||
|
@ -187,6 +241,7 @@
|
|||
gravity: BOW_GRAVITY,
|
||||
shapeType: 'compound',
|
||||
compoundShapeURL: COLLISION_HULL_URL,
|
||||
collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/bow_fall.L.wav",
|
||||
script: bowScriptURL,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
|
@ -595,6 +650,7 @@
|
|||
z: 0.08
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/flashlight_drop.L.wav",
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -3.5,
|
||||
|
@ -1131,10 +1187,11 @@
|
|||
z: 0.07
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/SpryPntCnDrp1.L.wav",
|
||||
shapeType: 'box',
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -0.5,
|
||||
y: -3.0,
|
||||
z: 0
|
||||
},
|
||||
velocity: {
|
||||
|
@ -1328,4 +1385,4 @@
|
|||
};
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new ResetSwitch();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -20,17 +20,29 @@ function createHiddenMasterSwitch() {
|
|||
type: "Box",
|
||||
name: "Master Switch",
|
||||
script: hiddenEntityScriptURL,
|
||||
dimensions: {x: 0.7, y: 0.2, z: 0.1},
|
||||
position: {x: 543.9, y: 496.05, z: 502.43},
|
||||
dimensions: {
|
||||
x: 0.7,
|
||||
y: 0.2,
|
||||
z: 0.1
|
||||
},
|
||||
position: {
|
||||
x: 543.9,
|
||||
y: 496.05,
|
||||
z: 502.43
|
||||
},
|
||||
rotation: Quat.fromPitchYawRollDegrees(0, 33, 0),
|
||||
visible: false
|
||||
visible: false,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
wantsTrigger: true
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
var entities = Entities.findEntities(MyAvatar.position, 100);
|
||||
|
||||
entities.forEach(function(entity) {
|
||||
//params: customKey, id, defaultValue
|
||||
var name = Entities.getEntityProperties(entity, "name").name
|
||||
if (name === "Master Switch") {
|
||||
Entities.deleteEntity(entity);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
var utilitiesScript = Script.resolvePath("../examples/libraries/utils.js");
|
||||
Script.include(utilitiesScript);
|
||||
|
||||
var gunScriptURL = Script.resolvePath("../examples/toybox/pistol/pistol.js");
|
||||
var sprayPaintScriptURL = Script.resolvePath("../examples/toybox/spray_paint/sprayPaintCan.js");
|
||||
var catScriptURL = Script.resolvePath("../examples/toybox/cat/cat.js");
|
||||
var flashlightScriptURL = Script.resolvePath('../examples/toybox/flashlight/flashlight.js');
|
||||
|
@ -58,6 +59,13 @@ MasterReset = function() {
|
|||
z: 505.09
|
||||
});
|
||||
|
||||
createGun({
|
||||
x: 546.2,
|
||||
y: 495.5,
|
||||
z: 505.2
|
||||
});
|
||||
|
||||
|
||||
createWand({
|
||||
x: 546.71,
|
||||
y: 495.55,
|
||||
|
@ -102,20 +110,19 @@ MasterReset = function() {
|
|||
|
||||
|
||||
createCat({
|
||||
x: 551.09,
|
||||
y: 494.98,
|
||||
z: 503.49
|
||||
x: 551.0,
|
||||
y: 495.3,
|
||||
z: 503.3
|
||||
});
|
||||
|
||||
|
||||
createSprayCan({
|
||||
x: 549.7,
|
||||
y: 495.6,
|
||||
z: 503.91
|
||||
});
|
||||
|
||||
createBow();
|
||||
|
||||
createBow();
|
||||
}
|
||||
|
||||
function deleteAllToys() {
|
||||
|
@ -130,6 +137,54 @@ MasterReset = function() {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
function createGun(position) {
|
||||
var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/gun.fbx";
|
||||
|
||||
var pistol = Entities.addEntity({
|
||||
type: 'Model',
|
||||
name: "pistol",
|
||||
modelURL: modelURL,
|
||||
position: position,
|
||||
dimensions: {
|
||||
x: 0.05,
|
||||
y: 0.23,
|
||||
z: 0.36
|
||||
},
|
||||
script: gunScriptURL,
|
||||
color: {
|
||||
red: 200,
|
||||
green: 0,
|
||||
blue: 20
|
||||
},
|
||||
shapeType: 'box',
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -5.0,
|
||||
z: 0
|
||||
},
|
||||
restitution: 0,
|
||||
collisionsWillMove: true,
|
||||
collisionSoundURL: "https://s3.amazonaws.com/hifi-public/sounds/Guns/Gun_Drop_and_Metalli_1.wav",
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: -0.1
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(100, 90, 0)
|
||||
},
|
||||
invertSolidWhileHeld: true
|
||||
},
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function createBow() {
|
||||
|
||||
var startPosition = {
|
||||
|
@ -165,6 +220,7 @@ MasterReset = function() {
|
|||
gravity: BOW_GRAVITY,
|
||||
shapeType: 'compound',
|
||||
compoundShapeURL: COLLISION_HULL_URL,
|
||||
collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/bow_fall.L.wav",
|
||||
script: bowScriptURL,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
|
@ -183,7 +239,6 @@ MasterReset = function() {
|
|||
}
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function createFire() {
|
||||
|
@ -575,6 +630,7 @@ MasterReset = function() {
|
|||
z: 0.08
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/flashlight_drop.L.wav",
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -3.5,
|
||||
|
@ -1111,10 +1167,11 @@ MasterReset = function() {
|
|||
z: 0.07
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/SpryPntCnDrp1.L.wav",
|
||||
shapeType: 'box',
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -0.5,
|
||||
y: -3.0,
|
||||
z: 0
|
||||
},
|
||||
velocity: {
|
||||
|
@ -1304,4 +1361,4 @@ MasterReset = function() {
|
|||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue