Merge pull request #6401 from ericrius1/rats

Created exterminatorGame, which allows users to spawn a pistol and shoot rats
This commit is contained in:
James B. Pollack 2015-12-01 11:39:05 -08:00
commit de100e5264
22 changed files with 32243 additions and 61 deletions

View file

@ -802,6 +802,7 @@ function MyController(hand) {
// equipping
Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]);
this.startHandGrasp();
this.setState(STATE_CONTINUE_EQUIP_BD);
}
@ -885,6 +886,7 @@ function MyController(hand) {
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
Entities.callEntityMethod(this.grabbedEntity, "unequip");
this.endHandGrasp();
}
};

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

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

@ -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,
@ -152,6 +159,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 = {
@ -1328,4 +1381,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,
@ -107,15 +115,14 @@ MasterReset = function() {
z: 503.49
});
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() {
@ -1304,4 +1358,4 @@ MasterReset = function() {
Script.scriptEnding.connect(cleanup);
}
};
};