Merge branch 'master' of https://github.com/highfidelity/hifi into baseball

This commit is contained in:
Atlante45 2015-12-01 15:14:58 -08:00
commit f06b5b05b3
31 changed files with 32397 additions and 99 deletions

View file

@ -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) {

View file

@ -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

View file

@ -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);

View file

@ -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);
@ -1248,4 +1299,4 @@ function cleanup() {
}
Script.scriptEnding.connect(cleanup);
Script.update.connect(update);
Script.update.connect(update);

View file

@ -0,0 +1 @@
/node_modules

View file

@ -0,0 +1 @@
web: node app.js

View file

@ -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/

View 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;

View file

@ -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')
);

View file

@ -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'])

View file

@ -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"
}
}

View file

@ -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%;
}

View file

@ -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>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,475 @@
//
// 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;
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() {
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)
}

View file

@ -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();
});

View file

@ -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);

View file

@ -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);

View file

@ -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);
})();
})();

View file

@ -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,
}
});

View 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);

View 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,
];
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 = {
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 < 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)
});
}
}
},
initControllerMapping: function() {
this.mapping = Controller.newMapping();
this.mapping.from(Controller.Standard.LT).hysteresis(0.0, 0.75).to(function(value) {
_this.triggerPress(0, value);
});
this.mapping.from(Controller.Standard.RT).hysteresis(0.0, 0.75).to(function(value) {
_this.triggerPress(1, value);
});
this.mapping.enable();
},
unload: function() {
this.mapping.disable();
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();
});

View 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);

View file

@ -139,6 +139,7 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
doKinematicUpdate(deltaTimeStep);
} else {
activateBody();
forceBodyNonStatic();
ObjectActionSpring::updateActionWorker(deltaTimeStep);
}
}
@ -189,6 +190,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
});
activateBody();
forceBodyNonStatic();
}
bool AvatarActionHold::updateArguments(QVariantMap arguments) {
@ -397,5 +399,6 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) {
_active = true;
});
activateBody();
forceBodyNonStatic();
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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...";

View file

@ -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 = {
@ -1134,7 +1188,7 @@
shapeType: 'box',
gravity: {
x: 0,
y: -0.5,
y: -3.0,
z: 0
},
velocity: {
@ -1328,4 +1382,4 @@
};
// entity scripts always need to return a newly constructed object of our type
return new ResetSwitch();
});
});

View file

@ -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);

View file

@ -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 = {
@ -183,7 +238,6 @@ MasterReset = function() {
}
})
});
}
function createFire() {
@ -1114,7 +1168,7 @@ MasterReset = function() {
shapeType: 'box',
gravity: {
x: 0,
y: -0.5,
y: -3.0,
z: 0
},
velocity: {
@ -1304,4 +1358,4 @@ MasterReset = function() {
Script.scriptEnding.connect(cleanup);
}
};
};