mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #9602 from huffman/feat/shortbow-entity-server
Add shortbow to marketplace scripts
This commit is contained in:
commit
5b59939195
37 changed files with 3737 additions and 1 deletions
|
@ -3431,7 +3431,7 @@ void Application::idle(float nsecsElapsed) {
|
|||
#ifdef Q_OS_WIN
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [] {
|
||||
initCpuUsage();
|
||||
initCpuUsage();
|
||||
});
|
||||
|
||||
vec3 kernelUserAndSystem;
|
||||
|
|
111
unpublishedScripts/marketplace/shortbow/README.md
Normal file
111
unpublishedScripts/marketplace/shortbow/README.md
Normal file
|
@ -0,0 +1,111 @@
|
|||
# Shortbow
|
||||
|
||||
Shortbow is a wave-based archery game.
|
||||
|
||||
## Notes
|
||||
|
||||
There are several design decisions that are based on certain characteristics of the High Fidelity platform,
|
||||
and in particular, [server entity scripts](https://wiki.highfidelity.com/wiki/Creating_Entity_Server_Scripts),
|
||||
which are touched on below.
|
||||
It is recommended that you understand the basics of client entity scripts and server entity scripts (and their
|
||||
differences) if you plan on digging into the shortbow code.
|
||||
|
||||
* Client entity scripts end in `ClientEntity.js` and server entity scripts end in `ServerEntity.js`.
|
||||
* Server entity scripts are not guaranteed to have access to *other* entities, and should not rely on it.
|
||||
* You should not rely on using `Entities.getEntityProperties` to access the properties of entities
|
||||
other than the entity that the server entity script is running on. This also applies to other
|
||||
functions like `Entities.findEntities`. This means that something like the `ShortGameManager` (described below)
|
||||
will not know the entity IDs of entities like the start button or scoreboard text entities, so it
|
||||
has to find ways to work around that limitation.
|
||||
* You can, however, use `Entities.editEntity` to edit other entities.
|
||||
* *NOTE*: It is likely that this will change in the future, and server entity scripts will be able to
|
||||
query the existence of other entities in some way. This will obviate the need for some of the workarounds
|
||||
used in shortbow.
|
||||
* The Entity Script Server (where server entity scripts) does not run a physics simulation
|
||||
* Server entity scripts do not generate collision events like would be used with
|
||||
`Script.addEventHandler(entityID, "collisionWithEntity", collideHandler)`.
|
||||
* High Fidelity distributes its physics simulation to clients, so collisions need to be handled
|
||||
there. In the case of enemies in shortbow, for instance, the collisions are handled in the
|
||||
client entity script `enemeyClientEntity.js`.
|
||||
* If no client is present to run the physics simulation, entities will not physically interact with other
|
||||
entities.
|
||||
* But, entities will still apply their basic physical properties.
|
||||
|
||||
## Shortbow Game Manager
|
||||
|
||||
This section describes both `shortbowServerEntity.js` and `shortbowGameManager.js`. The `shortbowServerEntity.js` script
|
||||
exists on the main arena model entity, and is the parent of all of the other parts of the game, other than the
|
||||
enemies and bows that are spawned during gameplay.
|
||||
|
||||
The `shortbowServerEntity.js` script is a server entity script that runs the shortbow game. The actual logic for
|
||||
the game is stored inside `shortbowGameManager.js`, in the `ShortbowGameManager` prototype.
|
||||
|
||||
## Enemy Scripts
|
||||
|
||||
These scripts exist on each enemy that is spawned.
|
||||
|
||||
### enemyClientEntity.js
|
||||
|
||||
This script handles collision events on the client. There are two collisions events that it is interested in:
|
||||
|
||||
1. Collisions with arrows
|
||||
1. Arrow entities have "projectile" in their name
|
||||
1. Any other entity with "projectile" in its name could be used to destroy the enemy
|
||||
1. Collisions with the gate that the enemies roll towards
|
||||
1. The gate entity has "GateCollider" in its name
|
||||
|
||||
### enemyServerEntity.js
|
||||
|
||||
This script acts as a fail-safe to work around some of the limitations that are mentioned under [Notes](#notes).
|
||||
In particular, if no client is running the physics simulation of an enemy entity, it may fall through the floor
|
||||
of the arena or never have a collision event generated against the gate. A server entity script also
|
||||
cannot access the properties of another entity, so it can't know if the entity has moved far away from
|
||||
the arena.
|
||||
|
||||
To handle this, this script is used to periodically send heartbeats to the [ShortbowGameManager](#shortbow-game-manager)
|
||||
that runs the game. The heartbeats include the position of the enemy. If the script that received the
|
||||
heartbeats hasn't heard from `enemyServerEntity.js` in too long, or the entity has moved too far away, it
|
||||
will remove it from it's local list of enemies that still need to be destroyed. This ensure that the game
|
||||
doesn't get into a "hung" state where it's waiting for an enemy that will never escape through the gate or be
|
||||
destroyed.
|
||||
|
||||
## Start Button
|
||||
|
||||
These scripts exist on the start button.
|
||||
|
||||
### startGameButtonClientEntity.js
|
||||
|
||||
This script sends a message to the [ShortbowGameManager](#shortbow-game-manager) to request that the game be started.
|
||||
|
||||
### startGameButtonServerEntity.js
|
||||
|
||||
When the shortbow game starts the start button is hidden, and when the shortbow game ends it is shown again.
|
||||
As described in the [Notes](#notes), server entity scripts cannot access other entities, including their IDs.
|
||||
Because of this, the [ShortbowGameManager](#shortbow-game-manager) has no way of knowing the id of the start button,
|
||||
and thus being able to use `Entities.editEntity` to set its `visible` property to `true` or `false`. One way around
|
||||
this, and is what is used here, is to use `Messages` on a common channel to send messages to a server entity script
|
||||
on the start button to request that it be shown or hidden.
|
||||
|
||||
## Display (Scoreboard)
|
||||
|
||||
This script exists on each text entity that scoreboard is composed of. The scoreboard area is composed of a text entity for each of the following: Score, High Score, Wave, Lives.
|
||||
|
||||
### displayServerEntity.js
|
||||
|
||||
The same problem that exists for [startGameButtonServerEntity.js](#startgamebuttonserverentityjs) exists for
|
||||
the text entities on the scoreboard. This script works around the problem in the same way, but instead of
|
||||
receiving a message that tells it whether to hide or show itself, it receives a message that contains the
|
||||
text to update the text entity with. For intance, the "lives" display entity will receive a message each
|
||||
time a life is lost with the current number of lives.
|
||||
|
||||
## How is the "common channel" determined that is used in some of the client and server entity scripts?
|
||||
|
||||
Imagine that there are two instances of shortbow next to each. If the channel being used is always the same,
|
||||
and not differentiated in some way between the two instances, a "start game" message sent from [startGameButtonClientEntity.js](#startgamebuttoncliententityjs)
|
||||
on one game will be received and handled by both games, causing both of them to start. We need a way to create
|
||||
a channel that is unique to the scripts that are running for a particular instance of shortbow.
|
||||
|
||||
All of the entities in shortbow, besides the enemy entities, are children of the main arena entity that
|
||||
runs the game. All of the scripts on these entities can access their parentID, so they can use
|
||||
a prefix plus the parentID to generate a unique channel for that instance of shortbow.
|
||||
|
BIN
unpublishedScripts/marketplace/shortbow/bow/Arrow_impact1.L.wav
Normal file
BIN
unpublishedScripts/marketplace/shortbow/bow/Arrow_impact1.L.wav
Normal file
Binary file not shown.
BIN
unpublishedScripts/marketplace/shortbow/bow/Bow_draw.1.L.wav
Normal file
BIN
unpublishedScripts/marketplace/shortbow/bow/Bow_draw.1.L.wav
Normal file
Binary file not shown.
Binary file not shown.
BIN
unpublishedScripts/marketplace/shortbow/bow/arrow-sparkle.png
Normal file
BIN
unpublishedScripts/marketplace/shortbow/bow/arrow-sparkle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
BIN
unpublishedScripts/marketplace/shortbow/bow/arrow.fbx
Normal file
BIN
unpublishedScripts/marketplace/shortbow/bow/arrow.fbx
Normal file
Binary file not shown.
BIN
unpublishedScripts/marketplace/shortbow/bow/bow-deadly.fbx
Normal file
BIN
unpublishedScripts/marketplace/shortbow/bow/bow-deadly.fbx
Normal file
Binary file not shown.
671
unpublishedScripts/marketplace/shortbow/bow/bow.js
Normal file
671
unpublishedScripts/marketplace/shortbow/bow/bow.js
Normal file
|
@ -0,0 +1,671 @@
|
|||
//
|
||||
// Created by Seth Alves on 2016-9-7
|
||||
// Copyright 2016 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 MyAvatar, Vec3, Controller, Quat */
|
||||
|
||||
var GRAB_COMMUNICATIONS_SETTING = "io.highfidelity.isFarGrabbing";
|
||||
setGrabCommunications = function setFarGrabCommunications(on) {
|
||||
Settings.setValue(GRAB_COMMUNICATIONS_SETTING, on ? "on" : "");
|
||||
}
|
||||
getGrabCommunications = function getFarGrabCommunications() {
|
||||
return !!Settings.getValue(GRAB_COMMUNICATIONS_SETTING, "");
|
||||
}
|
||||
|
||||
// this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp:378
|
||||
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral
|
||||
|
||||
getGrabPointSphereOffset = function(handController) {
|
||||
if (handController === Controller.Standard.RightHand) {
|
||||
return GRAB_POINT_SPHERE_OFFSET;
|
||||
}
|
||||
return {
|
||||
x: GRAB_POINT_SPHERE_OFFSET.x * -1,
|
||||
y: GRAB_POINT_SPHERE_OFFSET.y,
|
||||
z: GRAB_POINT_SPHERE_OFFSET.z
|
||||
};
|
||||
};
|
||||
|
||||
// controllerWorldLocation is where the controller would be, in-world, with an added offset
|
||||
getControllerWorldLocation = function (handController, doOffset) {
|
||||
var orientation;
|
||||
var position;
|
||||
var pose = Controller.getPoseValue(handController);
|
||||
var valid = pose.valid;
|
||||
var controllerJointIndex;
|
||||
if (pose.valid) {
|
||||
if (handController === Controller.Standard.RightHand) {
|
||||
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND");
|
||||
} else {
|
||||
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
|
||||
}
|
||||
orientation = Quat.multiply(MyAvatar.orientation, MyAvatar.getAbsoluteJointRotationInObjectFrame(controllerJointIndex));
|
||||
position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, MyAvatar.getAbsoluteJointTranslationInObjectFrame(controllerJointIndex)));
|
||||
|
||||
// add to the real position so the grab-point is out in front of the hand, a bit
|
||||
if (doOffset) {
|
||||
var offset = getGrabPointSphereOffset(handController);
|
||||
position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, offset));
|
||||
}
|
||||
|
||||
} else if (!HMD.isHandControllerAvailable()) {
|
||||
// NOTE: keep this offset in sync with scripts/system/controllers/handControllerPointer.js:493
|
||||
var VERTICAL_HEAD_LASER_OFFSET = 0.1;
|
||||
position = Vec3.sum(Camera.position, Vec3.multiplyQbyV(Camera.orientation, {x: 0, y: VERTICAL_HEAD_LASER_OFFSET, z: 0}));
|
||||
orientation = Quat.multiply(Camera.orientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }));
|
||||
valid = true;
|
||||
}
|
||||
|
||||
return {position: position,
|
||||
translation: position,
|
||||
orientation: orientation,
|
||||
rotation: orientation,
|
||||
valid: valid};
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// bow.js
|
||||
//
|
||||
// This script attaches to a bow that you can pick up with a hand controller.
|
||||
// Created by James B. Pollack @imgntn on 10/19/2015
|
||||
// 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 Script, Controller, SoundCache, Entities, getEntityCustomData, setEntityCustomData, MyAvatar, Vec3, Quat, Messages */
|
||||
|
||||
|
||||
function getControllerLocation(controllerHand) {
|
||||
var standardControllerValue =
|
||||
(controllerHand === "right") ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
||||
return getControllerWorldLocation(standardControllerValue, true);
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
Script.include("/~/system/libraries/utils.js");
|
||||
|
||||
const NULL_UUID = "{00000000-0000-0000-0000-000000000000}";
|
||||
|
||||
const NOTCH_ARROW_SOUND_URL = Script.resolvePath('notch.wav');
|
||||
const SHOOT_ARROW_SOUND_URL = Script.resolvePath('String_release2.L.wav');
|
||||
const STRING_PULL_SOUND_URL = Script.resolvePath('Bow_draw.1.L.wav');
|
||||
const ARROW_HIT_SOUND_URL = Script.resolvePath('Arrow_impact1.L.wav');
|
||||
|
||||
const ARROW_MODEL_URL = Script.resolvePath('arrow.fbx');
|
||||
const ARROW_DIMENSIONS = {
|
||||
x: 0.20,
|
||||
y: 0.19,
|
||||
z: 0.93
|
||||
};
|
||||
|
||||
const MIN_ARROW_SPEED = 3.0;
|
||||
const MAX_ARROW_SPEED = 30.0;
|
||||
|
||||
const ARROW_TIP_OFFSET = 0.47;
|
||||
const ARROW_GRAVITY = {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
z: 0
|
||||
};
|
||||
|
||||
|
||||
const ARROW_LIFETIME = 15; // seconds
|
||||
const ARROW_PARTICLE_LIFESPAN = 2; // seconds
|
||||
|
||||
const TOP_NOTCH_OFFSET = 0.6;
|
||||
const BOTTOM_NOTCH_OFFSET = 0.6;
|
||||
|
||||
const LINE_DIMENSIONS = {
|
||||
x: 5.0,
|
||||
y: 5.0,
|
||||
z: 5.0
|
||||
};
|
||||
|
||||
const DRAW_STRING_THRESHOLD = 0.80;
|
||||
const DRAW_STRING_PULL_DELTA_HAPTIC_PULSE = 0.09;
|
||||
const DRAW_STRING_MAX_DRAW = 0.7;
|
||||
|
||||
|
||||
const MIN_ARROW_DISTANCE_FROM_BOW_REST = 0.2;
|
||||
const MAX_ARROW_DISTANCE_FROM_BOW_REST = ARROW_DIMENSIONS.z - 0.2;
|
||||
const MIN_HAND_DISTANCE_FROM_BOW_TO_KNOCK_ARROW = 0.25;
|
||||
const MIN_ARROW_DISTANCE_FROM_BOW_REST_TO_SHOOT = 0.30;
|
||||
|
||||
const NOTCH_OFFSET_FORWARD = 0.08;
|
||||
const NOTCH_OFFSET_UP = 0.035;
|
||||
|
||||
const SHOT_SCALE = {
|
||||
min1: 0.0,
|
||||
max1: 0.6,
|
||||
min2: 1.0,
|
||||
max2: 15.0
|
||||
};
|
||||
|
||||
const USE_DEBOUNCE = false;
|
||||
|
||||
const TRIGGER_CONTROLS = [
|
||||
Controller.Standard.LT,
|
||||
Controller.Standard.RT,
|
||||
];
|
||||
|
||||
function interval() {
|
||||
var lastTime = new Date().getTime();
|
||||
|
||||
return function getInterval() {
|
||||
var newTime = new Date().getTime();
|
||||
var delta = newTime - lastTime;
|
||||
lastTime = newTime;
|
||||
return delta;
|
||||
};
|
||||
}
|
||||
|
||||
var checkInterval = interval();
|
||||
|
||||
var _this;
|
||||
|
||||
function Bow() {
|
||||
_this = this;
|
||||
return;
|
||||
}
|
||||
|
||||
const STRING_NAME = 'Hifi-Bow-String';
|
||||
const ARROW_NAME = 'Hifi-Arrow-projectile';
|
||||
|
||||
const STATE_IDLE = 0;
|
||||
const STATE_ARROW_GRABBED = 1;
|
||||
|
||||
Bow.prototype = {
|
||||
topString: null,
|
||||
aiming: false,
|
||||
arrowTipPosition: null,
|
||||
preNotchString: null,
|
||||
stringID: null,
|
||||
arrow: null,
|
||||
stringData: {
|
||||
currentColor: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
}
|
||||
},
|
||||
|
||||
state: STATE_IDLE,
|
||||
sinceLastUpdate: 0,
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
this.stringPullSound = SoundCache.getSound(STRING_PULL_SOUND_URL);
|
||||
this.shootArrowSound = SoundCache.getSound(SHOOT_ARROW_SOUND_URL);
|
||||
this.arrowHitSound = SoundCache.getSound(ARROW_HIT_SOUND_URL);
|
||||
this.arrowNotchSound = SoundCache.getSound(NOTCH_ARROW_SOUND_URL);
|
||||
var userData = Entities.getEntityProperties(this.entityID, ["userData"]).userData;
|
||||
print(userData);
|
||||
this.userData = JSON.parse(userData);
|
||||
this.stringID = null;
|
||||
},
|
||||
|
||||
unload: function() {
|
||||
Messages.sendLocalMessage('Hifi-Hand-Disabler', "none");
|
||||
Entities.deleteEntity(this.arrow);
|
||||
},
|
||||
|
||||
startEquip: function(entityID, args) {
|
||||
this.hand = args[0];
|
||||
this.bowHand = args[0];
|
||||
this.stringHand = this.bowHand === "right" ? "left" : "right";
|
||||
|
||||
Entities.editEntity(_this.entityID, {
|
||||
collidesWith: "",
|
||||
});
|
||||
|
||||
var data = getEntityCustomData('grabbableKey', this.entityID, {});
|
||||
data.grabbable = false;
|
||||
setEntityCustomData('grabbableKey', this.entityID, data);
|
||||
|
||||
this.initString();
|
||||
|
||||
var self = this;
|
||||
this.updateIntervalID = Script.setInterval(function() { self.update(); }, 11);
|
||||
},
|
||||
|
||||
getStringHandPosition: function() {
|
||||
return getControllerLocation(this.stringHand).position;
|
||||
},
|
||||
|
||||
releaseEquip: function(entityID, args) {
|
||||
Script.clearInterval(this.updateIntervalID);
|
||||
this.updateIntervalID = null;
|
||||
|
||||
Messages.sendLocalMessage('Hifi-Hand-Disabler', "none");
|
||||
|
||||
var data = getEntityCustomData('grabbableKey', this.entityID, {});
|
||||
data.grabbable = true;
|
||||
setEntityCustomData('grabbableKey', this.entityID, data);
|
||||
Entities.deleteEntity(this.arrow);
|
||||
this.resetStringToIdlePosition();
|
||||
this.destroyArrow();
|
||||
Entities.editEntity(_this.entityID, {
|
||||
collidesWith: "static,dynamic,kinematic,otherAvatar,myAvatar"
|
||||
});
|
||||
},
|
||||
|
||||
update: function(entityID) {
|
||||
var self = this;
|
||||
self.deltaTime = checkInterval();
|
||||
//debounce during debugging -- maybe we're updating too fast?
|
||||
if (USE_DEBOUNCE === true) {
|
||||
self.sinceLastUpdate = self.sinceLastUpdate + self.deltaTime;
|
||||
|
||||
if (self.sinceLastUpdate > 60) {
|
||||
self.sinceLastUpdate = 0;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//invert the hands because our string will be held with the opposite hand of the first one we pick up the bow with
|
||||
this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[(this.hand === 'left') ? 1 : 0]);
|
||||
|
||||
this.bowProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
|
||||
var notchPosition = this.getNotchPosition(this.bowProperties);
|
||||
var stringHandPosition = this.getStringHandPosition();
|
||||
var handToNotch = Vec3.subtract(notchPosition, stringHandPosition);
|
||||
var pullBackDistance = Vec3.length(handToNotch);
|
||||
|
||||
if (this.state === STATE_IDLE) {
|
||||
this.pullBackDistance = 0;
|
||||
|
||||
this.resetStringToIdlePosition();
|
||||
if (this.triggerValue >= DRAW_STRING_THRESHOLD && pullBackDistance < MIN_HAND_DISTANCE_FROM_BOW_TO_KNOCK_ARROW && !this.backHandBusy) {
|
||||
//the first time aiming the arrow
|
||||
var handToDisable = (this.hand === 'right' ? 'left' : 'right');
|
||||
this.state = STATE_ARROW_GRABBED;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state === STATE_ARROW_GRABBED) {
|
||||
if (!this.arrow) {
|
||||
var handToDisable = (this.hand === 'right' ? 'left' : 'right');
|
||||
Messages.sendLocalMessage('Hifi-Hand-Disabler', handToDisable);
|
||||
this.playArrowNotchSound();
|
||||
this.arrow = this.createArrow();
|
||||
this.playStringPullSound();
|
||||
}
|
||||
|
||||
if (this.triggerValue < DRAW_STRING_THRESHOLD) {
|
||||
if (pullBackDistance >= (MIN_ARROW_DISTANCE_FROM_BOW_REST_TO_SHOOT)) {
|
||||
// The arrow has been pulled far enough back that we can release it
|
||||
Messages.sendLocalMessage('Hifi-Hand-Disabler', "none");
|
||||
this.updateArrowPositionInNotch(true, true);
|
||||
this.arrow = null;
|
||||
this.state = STATE_IDLE;
|
||||
this.resetStringToIdlePosition();
|
||||
} else {
|
||||
// The arrow has not been pulled far enough back so we just remove the arrow
|
||||
Messages.sendLocalMessage('Hifi-Hand-Disabler', "none");
|
||||
Entities.deleteEntity(this.arrow);
|
||||
this.arrow = null;
|
||||
this.state = STATE_IDLE;
|
||||
this.resetStringToIdlePosition();
|
||||
}
|
||||
} else {
|
||||
this.updateArrowPositionInNotch(false, true);
|
||||
this.updateString();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
destroyArrow: function() {
|
||||
var children = Entities.getChildrenIDs(this.entityID);
|
||||
children.forEach(function(childID) {
|
||||
var childName = Entities.getEntityProperties(childID, ["name"]).name;
|
||||
if (childName == ARROW_NAME) {
|
||||
Entities.deleteEntity(childID);
|
||||
// Continue iterating through children in case we've ended up in
|
||||
// a bad state where there are multiple arrows.
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
createArrow: function() {
|
||||
this.playArrowNotchSound();
|
||||
|
||||
var arrow = Entities.addEntity({
|
||||
name: ARROW_NAME,
|
||||
type: 'Model',
|
||||
modelURL: ARROW_MODEL_URL,
|
||||
shapeType: 'simple-compound',
|
||||
dimensions: ARROW_DIMENSIONS,
|
||||
position: this.bowProperties.position,
|
||||
parentID: this.entityID,
|
||||
dynamic: false,
|
||||
collisionless: true,
|
||||
collisionSoundURL: ARROW_HIT_SOUND_URL,
|
||||
damping: 0.01,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
},
|
||||
creatorSessionUUID: MyAvatar.sessionUUID
|
||||
})
|
||||
});
|
||||
|
||||
var makeArrowStick = function(entityA, entityB, collision) {
|
||||
Entities.editEntity(entityA, {
|
||||
localAngularVelocity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
localVelocity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
parentID: entityB,
|
||||
dynamic: false,
|
||||
collisionless: true,
|
||||
collidesWith: ""
|
||||
});
|
||||
Script.removeEventHandler(arrow, "collisionWithEntity", makeArrowStick);
|
||||
};
|
||||
|
||||
Script.addEventHandler(arrow, "collisionWithEntity", makeArrowStick);
|
||||
|
||||
return arrow;
|
||||
},
|
||||
|
||||
initString: function() {
|
||||
// Check for existence of string
|
||||
var children = Entities.getChildrenIDs(this.entityID);
|
||||
children.forEach(function(childID) {
|
||||
var childName = Entities.getEntityProperties(childID, ["name"]).name;
|
||||
if (childName == STRING_NAME) {
|
||||
this.stringID = childID;
|
||||
}
|
||||
});
|
||||
|
||||
// If thie string wasn't found, create it
|
||||
if (this.stringID === null) {
|
||||
this.stringID = Entities.addEntity({
|
||||
collisionless: true,
|
||||
dimensions: { "x": 5, "y": 5, "z": 5 },
|
||||
ignoreForCollisions: 1,
|
||||
linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ],
|
||||
lineWidth: 5,
|
||||
color: { red: 153, green: 102, blue: 51 },
|
||||
name: STRING_NAME,
|
||||
parentID: this.entityID,
|
||||
localPosition: { "x": 0, "y": 0.6, "z": 0.1 },
|
||||
localRotation: { "w": 1, "x": 0, "y": 0, "z": 0 },
|
||||
type: 'Line',
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
this.resetStringToIdlePosition();
|
||||
},
|
||||
|
||||
// This resets the string to a straight line
|
||||
resetStringToIdlePosition: function() {
|
||||
Entities.editEntity(this.stringID, {
|
||||
linePoints: [ { "x": 0, "y": 0, "z": 0 }, { "x": 0, "y": -1.2, "z": 0 } ],
|
||||
lineWidth: 5,
|
||||
localPosition: { "x": 0, "y": 0.6, "z": 0.1 },
|
||||
localRotation: { "w": 1, "x": 0, "y": 0, "z": 0 },
|
||||
});
|
||||
},
|
||||
|
||||
updateString: function() {
|
||||
var upVector = Quat.getUp(this.bowProperties.rotation);
|
||||
var upOffset = Vec3.multiply(upVector, TOP_NOTCH_OFFSET);
|
||||
var downVector = Vec3.multiply(-1, Quat.getUp(this.bowProperties.rotation));
|
||||
var downOffset = Vec3.multiply(downVector, BOTTOM_NOTCH_OFFSET);
|
||||
var backOffset = Vec3.multiply(-0.1, Quat.getFront(this.bowProperties.rotation));
|
||||
|
||||
var topStringPosition = Vec3.sum(this.bowProperties.position, upOffset);
|
||||
this.topStringPosition = Vec3.sum(topStringPosition, backOffset);
|
||||
var bottomStringPosition = Vec3.sum(this.bowProperties.position, downOffset);
|
||||
this.bottomStringPosition = Vec3.sum(bottomStringPosition, backOffset);
|
||||
|
||||
var stringProps = Entities.getEntityProperties(this.stringID, ['position', 'rotation']);
|
||||
var handPositionLocal = Vec3.subtract(this.arrowRearPosition, stringProps.position);
|
||||
handPositionLocal = Vec3.multiplyQbyV(Quat.inverse(stringProps.rotation), handPositionLocal);
|
||||
|
||||
var linePoints = [
|
||||
{ x: 0, y: 0, z: 0 },
|
||||
handPositionLocal,
|
||||
{ x: 0, y: -1.2, z: 0 },
|
||||
];
|
||||
|
||||
Entities.editEntity(this.stringID, {
|
||||
linePoints: linePoints,
|
||||
});
|
||||
},
|
||||
|
||||
getNotchPosition: function(bowProperties) {
|
||||
var frontVector = Quat.getFront(bowProperties.rotation);
|
||||
var notchVectorForward = Vec3.multiply(frontVector, NOTCH_OFFSET_FORWARD);
|
||||
var upVector = Quat.getUp(bowProperties.rotation);
|
||||
var notchVectorUp = Vec3.multiply(upVector, NOTCH_OFFSET_UP);
|
||||
var notchPosition = Vec3.sum(bowProperties.position, notchVectorForward);
|
||||
notchPosition = Vec3.sum(notchPosition, notchVectorUp);
|
||||
return notchPosition;
|
||||
},
|
||||
|
||||
updateArrowPositionInNotch: function(shouldReleaseArrow, doHapticPulses) {
|
||||
//set the notch that the arrow should go through
|
||||
var notchPosition = this.getNotchPosition(this.bowProperties);
|
||||
//set the arrow rotation to be between the notch and other hand
|
||||
var stringHandPosition = this.getStringHandPosition();
|
||||
var handToNotch = Vec3.subtract(notchPosition, stringHandPosition);
|
||||
var arrowRotation = Quat.rotationBetween(Vec3.FRONT, handToNotch);
|
||||
|
||||
var backHand = this.hand === 'left' ? 1 : 0;
|
||||
var pullBackDistance = Vec3.length(handToNotch);
|
||||
// pulse as arrow is drawn
|
||||
if (doHapticPulses &&
|
||||
Math.abs(pullBackDistance - this.pullBackDistance) > DRAW_STRING_PULL_DELTA_HAPTIC_PULSE) {
|
||||
Controller.triggerHapticPulse(1, 20, backHand);
|
||||
this.pullBackDistance = pullBackDistance;
|
||||
}
|
||||
|
||||
if (pullBackDistance > DRAW_STRING_MAX_DRAW) {
|
||||
pullBackDistance = DRAW_STRING_MAX_DRAW;
|
||||
}
|
||||
|
||||
var handToNotchDistance = Vec3.length(handToNotch);
|
||||
var stringToNotchDistance = Math.max(MIN_ARROW_DISTANCE_FROM_BOW_REST, Math.min(MAX_ARROW_DISTANCE_FROM_BOW_REST, handToNotchDistance));
|
||||
var halfArrowVec = Vec3.multiply(Vec3.normalize(handToNotch), ARROW_DIMENSIONS.z / 2.0);
|
||||
var offset = Vec3.subtract(notchPosition, Vec3.multiply(Vec3.normalize(handToNotch), stringToNotchDistance - ARROW_DIMENSIONS.z / 2.0));
|
||||
|
||||
var arrowPosition = offset;
|
||||
|
||||
// Set arrow rear position
|
||||
var frontVector = Quat.getFront(arrowRotation);
|
||||
var frontOffset = Vec3.multiply(frontVector, -ARROW_TIP_OFFSET);
|
||||
var arrorRearPosition = Vec3.sum(arrowPosition, frontOffset);
|
||||
this.arrowRearPosition = arrorRearPosition;
|
||||
|
||||
//if we're not shooting, we're updating the arrow's orientation
|
||||
if (shouldReleaseArrow !== true) {
|
||||
Entities.editEntity(this.arrow, {
|
||||
position: arrowPosition,
|
||||
rotation: arrowRotation
|
||||
});
|
||||
} else {
|
||||
//shoot the arrow
|
||||
var arrowAge = Entities.getEntityProperties(this.arrow, ["age"]).age;
|
||||
|
||||
//scale the shot strength by the distance you've pulled the arrow back and set its release velocity to be
|
||||
// in the direction of the v
|
||||
var arrowForce = this.scaleArrowShotStrength(stringToNotchDistance);
|
||||
var handToNotchNorm = Vec3.normalize(handToNotch);
|
||||
|
||||
var releaseVelocity = Vec3.multiply(handToNotchNorm, arrowForce);
|
||||
|
||||
//make the arrow physical, give it gravity, a lifetime, and set our velocity
|
||||
var arrowProperties = {
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
collidesWith: "static,dynamic,otherAvatar", // workaround: not with kinematic --> no collision with bow
|
||||
velocity: releaseVelocity,
|
||||
parentID: NULL_UUID,
|
||||
gravity: ARROW_GRAVITY,
|
||||
lifetime: arrowAge + ARROW_LIFETIME,
|
||||
};
|
||||
|
||||
// add a particle effect to make the arrow easier to see as it flies
|
||||
var arrowParticleProperties = {
|
||||
accelerationSpread: { x: 0, y: 0, z: 0 },
|
||||
alpha: 1,
|
||||
alphaFinish: 0,
|
||||
alphaSpread: 0,
|
||||
alphaStart: 0.3,
|
||||
azimuthFinish: 3.1,
|
||||
azimuthStart: -3.14159,
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
colorFinish: { red: 255, green: 255, blue: 255 },
|
||||
colorSpread: { red: 0, green: 0, blue: 0 },
|
||||
colorStart: { red: 255, green: 255, blue: 255 },
|
||||
emitAcceleration: { x: 0, y: 0, z: 0 },
|
||||
emitDimensions: { x: 0, y: 0, z: 0 },
|
||||
emitOrientation: { x: -0.7, y: 0.0, z: 0.0, w: 0.7 },
|
||||
emitRate: 0.01,
|
||||
emitSpeed: 0,
|
||||
emitterShouldTrail: 0,
|
||||
isEmitting: 1,
|
||||
lifespan: ARROW_PARTICLE_LIFESPAN,
|
||||
lifetime: ARROW_PARTICLE_LIFESPAN + 1,
|
||||
maxParticles: 1000,
|
||||
name: 'arrow-particles',
|
||||
parentID: this.arrow,
|
||||
particleRadius: 0.132,
|
||||
polarFinish: 0,
|
||||
polarStart: 0,
|
||||
radiusFinish: 0.35,
|
||||
radiusSpread: 0,
|
||||
radiusStart: 0.132,
|
||||
speedSpread: 0,
|
||||
textures: Script.resolvePath('arrow-sparkle.png'),
|
||||
type: 'ParticleEffect'
|
||||
};
|
||||
|
||||
Entities.addEntity(arrowParticleProperties);
|
||||
|
||||
// actually shoot the arrow
|
||||
Entities.editEntity(this.arrow, arrowProperties);
|
||||
|
||||
// play the sound of a shooting arrow
|
||||
this.playShootArrowSound();
|
||||
|
||||
Entities.addAction("travel-oriented", this.arrow, {
|
||||
forward: { x: 0, y: 0, z: -1 },
|
||||
angularTimeScale: 0.1,
|
||||
tag: "arrow from hifi-bow",
|
||||
ttl: ARROW_LIFETIME
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
scaleArrowShotStrength: function(value) {
|
||||
var percentage = (value - MIN_ARROW_DISTANCE_FROM_BOW_REST)
|
||||
/ (MAX_ARROW_DISTANCE_FROM_BOW_REST - MIN_ARROW_DISTANCE_FROM_BOW_REST);
|
||||
return MIN_ARROW_SPEED + (percentage * (MAX_ARROW_SPEED - MIN_ARROW_SPEED)) ;
|
||||
},
|
||||
|
||||
playStringPullSound: function() {
|
||||
var audioProperties = {
|
||||
volume: 0.10,
|
||||
position: this.bowProperties.position
|
||||
};
|
||||
this.stringPullInjector = Audio.playSound(this.stringPullSound, audioProperties);
|
||||
},
|
||||
|
||||
playShootArrowSound: function(sound) {
|
||||
var audioProperties = {
|
||||
volume: 0.15,
|
||||
position: this.bowProperties.position
|
||||
};
|
||||
Audio.playSound(this.shootArrowSound, audioProperties);
|
||||
},
|
||||
|
||||
playArrowNotchSound: function() {
|
||||
var audioProperties = {
|
||||
volume: 0.15,
|
||||
position: this.bowProperties.position
|
||||
};
|
||||
Audio.playSound(this.arrowNotchSound, audioProperties);
|
||||
},
|
||||
|
||||
changeStringPullSoundVolume: function(pullBackDistance) {
|
||||
var audioProperties = {
|
||||
volume: this.scaleSoundVolume(pullBackDistance),
|
||||
position: this.bowProperties.position
|
||||
};
|
||||
|
||||
this.stringPullInjector.options = audioProperties;
|
||||
},
|
||||
|
||||
scaleSoundVolume: function(value) {
|
||||
var min1 = SHOT_SCALE.min1;
|
||||
var max1 = SHOT_SCALE.max1;
|
||||
var min2 = 0;
|
||||
var max2 = 0.2;
|
||||
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
|
||||
},
|
||||
|
||||
handleMessages: function(channel, message, sender) {
|
||||
if (sender !== MyAvatar.sessionUUID) {
|
||||
return;
|
||||
}
|
||||
if (channel !== 'Hifi-Object-Manipulation') {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var data = JSON.parse(message);
|
||||
var action = data.action;
|
||||
var hand = data.joint;
|
||||
var isBackHand = ((_this.hand == "left" && hand == "RightHand") ||
|
||||
(_this.hand == "right" && hand == "LeftHand"));
|
||||
if ((action == "equip" || action == "grab") && isBackHand) {
|
||||
_this.backHandBusy = true;
|
||||
}
|
||||
if (action == "release" && isBackHand) {
|
||||
_this.backHandBusy = false;
|
||||
}
|
||||
} catch (e) {
|
||||
print("WARNING: bow.js -- error parsing Hifi-Object-Manipulation message: " + message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var bow = new Bow();
|
||||
|
||||
Messages.subscribe('Hifi-Object-Manipulation');
|
||||
Messages.messageReceived.connect(bow.handleMessages);
|
||||
|
||||
return bow;
|
||||
});
|
44
unpublishedScripts/marketplace/shortbow/bow/bow.json
Normal file
44
unpublishedScripts/marketplace/shortbow/bow/bow.json
Normal file
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"Entities": [
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collisionsWillMove": 1,
|
||||
"compoundShapeURL": "http://mpassets.highfidelity.com/a9221d01-95eb-4b2e-85e5-d9e0970a7f51-v1/bow_collision_hull.obj",
|
||||
"created": "2017-02-14T18:54:38Z",
|
||||
"dimensions": {
|
||||
"x": 0.039999999105930328,
|
||||
"y": 1.2999999523162842,
|
||||
"z": 0.20000000298023224
|
||||
},
|
||||
"dynamic": 1,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": -9.8000001907348633,
|
||||
"z": 0
|
||||
},
|
||||
"id": "{73954924-2e18-4787-91a7-092c2afb6242}",
|
||||
"lastEdited": 1487098438422164,
|
||||
"lastEditedBy": "{d2da5e17-9125-414d-ac4e-cd7fba6c22f8}",
|
||||
"modelURL": "http://mpassets.highfidelity.com/a9221d01-95eb-4b2e-85e5-d9e0970a7f51-v1/bow-deadly.fbx",
|
||||
"name": "WG.Hifi-Bow",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"queryAACube": {
|
||||
"scale": 1.3159027099609375,
|
||||
"x": -0.65795135498046875,
|
||||
"y": -0.65795135498046875,
|
||||
"z": -0.65795135498046875
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.9717707633972168,
|
||||
"x": 0.15437555313110352,
|
||||
"y": -0.10472267866134644,
|
||||
"z": -0.14421302080154419
|
||||
},
|
||||
"script": "http://mpassets.highfidelity.com/a9221d01-95eb-4b2e-85e5-d9e0970a7f51-v1/bow.js",
|
||||
"shapeType": "compound",
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.0813,\"y\":0.0452,\"z\":0.0095},{\"x\":-0.3946,\"y\":-0.6604,\"z\":0.4748,\"w\":-0.4275}],\"LeftHand\":[{\"x\":-0.0881,\"y\":0.0259,\"z\":0.0159},{\"x\":0.4427,\"y\":-0.6519,\"z\":0.4592,\"w\":0.4099}]}}}"
|
||||
}
|
||||
],
|
||||
"Version": 67
|
||||
}
|
32
unpublishedScripts/marketplace/shortbow/bow/bow.svo.json
Normal file
32
unpublishedScripts/marketplace/shortbow/bow/bow.svo.json
Normal file
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"Entities": [ {
|
||||
"collisionsWillMove": 1,
|
||||
"compoundShapeURL": "http://hifi-content.s3.amazonaws.com/caitlyn/production/bow/bow_collision_hull.obj",
|
||||
"created": "2016-09-01T23:57:55Z",
|
||||
"dimensions": {
|
||||
"x": 0.039999999105930328,
|
||||
"y": 1.2999999523162842,
|
||||
"z": 0.20000000298023224
|
||||
},
|
||||
"dynamic": 1,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": -1,
|
||||
"z": 0
|
||||
},
|
||||
"modelURL": "http://hifi-content.s3.amazonaws.com/caitlyn/production/bow/bow-deadly.fbx",
|
||||
"name": "Hifi-Bow",
|
||||
"rotation": {
|
||||
"w": 0.9718012809753418,
|
||||
"x": 0.15440607070922852,
|
||||
"y": -0.10469216108322144,
|
||||
"z": -0.14418250322341919
|
||||
},
|
||||
"script": "http://hifi-content.s3.amazonaws.com/caitlyn/production/bow/bow.js",
|
||||
"shapeType": "compound",
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.0813,\"y\":0.0452,\"z\":0.0095},{\"x\":-0.3946,\"y\":-0.6604,\"z\":0.4748,\"w\":-0.4275}],\"LeftHand\":[{\"x\":-0.0881,\"y\":0.0259,\"z\":0.0159},{\"x\":0.4427,\"y\":-0.6519,\"z\":0.4592,\"w\":0.4099}]}}}"
|
||||
}
|
||||
],
|
||||
"Version": 57
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
v -0.016461 -0.431491 -0.033447
|
||||
v -0.007624 0.437384 -0.046243
|
||||
v 0.011984 -0.424659 -0.03691
|
||||
v 0.015514 0.425913 -0.028648
|
||||
v -0.010788 -0.421429 0.093711
|
||||
v 0.007135 -0.423115 0.098735
|
||||
v -0.010208 0.425558 0.096005
|
||||
v 0.006734 0.43913 0.088902
|
||||
|
||||
f 1 2 3
|
||||
f 3 2 4
|
||||
f 5 6 7
|
||||
f 7 6 8
|
||||
f 1 5 2
|
||||
f 2 5 7
|
||||
f 3 4 6
|
||||
f 6 4 8
|
||||
f 1 3 5
|
||||
f 5 3 6
|
||||
f 2 7 4
|
||||
f 4 7 8
|
BIN
unpublishedScripts/marketplace/shortbow/bow/notch.wav
Normal file
BIN
unpublishedScripts/marketplace/shortbow/bow/notch.wav
Normal file
Binary file not shown.
67
unpublishedScripts/marketplace/shortbow/bow/spawnBow.js
Normal file
67
unpublishedScripts/marketplace/shortbow/bow/spawnBow.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// Created by Ryan Huffman on 1/10/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
|
||||
var leftHandPosition = {
|
||||
"x": 0,
|
||||
"y": 0.0559,
|
||||
"z": 0.0159
|
||||
};
|
||||
var leftHandRotation = Quat.fromPitchYawRollDegrees(90, -90, 0);
|
||||
var rightHandPosition = Vec3.multiplyVbyV(leftHandPosition, { x: -1, y: 0, z: 0 });
|
||||
var rightHandRotation = Quat.fromPitchYawRollDegrees(90, 90, 0);
|
||||
|
||||
var userData = {
|
||||
"grabbableKey": {
|
||||
"grabbable": true
|
||||
},
|
||||
"wearable": {
|
||||
"joints": {
|
||||
"LeftHand": [
|
||||
leftHandPosition,
|
||||
leftHandRotation
|
||||
],
|
||||
"RightHand": [
|
||||
rightHandPosition,
|
||||
rightHandRotation
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var id = Entities.addEntity({
|
||||
"position": MyAvatar.position,
|
||||
"collisionsWillMove": 1,
|
||||
"compoundShapeURL": Script.resolvePath("bow_collision_hull.obj"),
|
||||
"created": "2016-09-01T23:57:55Z",
|
||||
"dimensions": {
|
||||
"x": 0.039999999105930328,
|
||||
"y": 1.2999999523162842,
|
||||
"z": 0.20000000298023224
|
||||
},
|
||||
"dynamic": 1,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": -9.8,
|
||||
"z": 0
|
||||
},
|
||||
"modelURL": Script.resolvePath("bow-deadly.fbx"),
|
||||
"name": "Hifi-Bow",
|
||||
"rotation": {
|
||||
"w": 0.9718012809753418,
|
||||
"x": 0.15440607070922852,
|
||||
"y": -0.10469216108322144,
|
||||
"z": -0.14418250322341919
|
||||
},
|
||||
"script": Script.resolvePath("bow.js"),
|
||||
"shapeType": "compound",
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.0813,\"y\":0.0452,\"z\":0.0095},{\"x\":-0.3946,\"y\":-0.6604,\"z\":0.4748,\"w\":-0.4275}],\"LeftHand\":[{\"x\":-0.0881,\"y\":0.0259,\"z\":0.0159},{\"x\":0.4427,\"y\":-0.6519,\"z\":0.4592,\"w\":0.4099}]}}}",
|
||||
"lifetime": 600
|
||||
});
|
||||
print("Created bow:", id);
|
61
unpublishedScripts/marketplace/shortbow/enemyClientEntity.js
Normal file
61
unpublishedScripts/marketplace/shortbow/enemyClientEntity.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// Created by Ryan Huffman on 1/10/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
/* globals utils */
|
||||
|
||||
(function() {
|
||||
Script.include('utils.js');
|
||||
|
||||
function Enemy() {
|
||||
}
|
||||
Enemy.prototype = {
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
|
||||
// To avoid sending extraneous messages and checking entities that we've already
|
||||
// seen, we keep track of which entities we've collided with previously.
|
||||
this.entityIDsThatHaveCollidedWithMe = [];
|
||||
|
||||
Script.addEventHandler(entityID, "collisionWithEntity", this.onCollide.bind(this));
|
||||
|
||||
var userData = Entities.getEntityProperties(this.entityID, 'userData').userData;
|
||||
var data = utils.parseJSON(userData);
|
||||
if (data !== undefined && data.gameChannel !== undefined) {
|
||||
this.gameChannel = data.gameChannel;
|
||||
} else {
|
||||
print("enemyEntity.js | ERROR: userData does not contain a game channel and/or team number");
|
||||
}
|
||||
},
|
||||
onCollide: function(entityA, entityB, collision) {
|
||||
if (this.entityIDsThatHaveCollidedWithMe.indexOf(entityB) > -1) {
|
||||
return;
|
||||
}
|
||||
this.entityIDsThatHaveCollidedWithMe.push(entityB);
|
||||
|
||||
var colliderName = Entities.getEntityProperties(entityB, 'name').name;
|
||||
|
||||
if (colliderName.indexOf("projectile") > -1) {
|
||||
Messages.sendMessage(this.gameChannel, JSON.stringify({
|
||||
type: "enemy-killed",
|
||||
entityID: this.entityID,
|
||||
position: Entities.getEntityProperties(this.entityID, 'position').position
|
||||
}));
|
||||
Entities.deleteEntity(this.entityID);
|
||||
} else if (colliderName.indexOf("GateCollider") > -1) {
|
||||
Messages.sendMessage(this.gameChannel, JSON.stringify({
|
||||
type: "enemy-escaped",
|
||||
entityID: this.entityID,
|
||||
position: Entities.getEntityProperties(this.entityID, 'position').position
|
||||
}));
|
||||
Entities.deleteEntity(this.entityID);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return new Enemy();
|
||||
});
|
41
unpublishedScripts/marketplace/shortbow/enemyServerEntity.js
Normal file
41
unpublishedScripts/marketplace/shortbow/enemyServerEntity.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Created by Ryan Huffman on 1/10/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
/* globals utils */
|
||||
|
||||
(function() {
|
||||
Script.include('utils.js');
|
||||
|
||||
function Enemy() {
|
||||
}
|
||||
Enemy.prototype = {
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
var userData = Entities.getEntityProperties(this.entityID, 'userData').userData;
|
||||
var data = utils.parseJSON(userData);
|
||||
if (data !== undefined && data.gameChannel !== undefined) {
|
||||
this.gameChannel = data.gameChannel;
|
||||
} else {
|
||||
print("enemyServerEntity.js | ERROR: userData does not contain a game channel and/or team number");
|
||||
}
|
||||
var self = this;
|
||||
this.heartbeatTimerID = Script.setInterval(function() {
|
||||
Messages.sendMessage(self.gameChannel, JSON.stringify({
|
||||
type: "enemy-heartbeat",
|
||||
entityID: self.entityID,
|
||||
position: Entities.getEntityProperties(self.entityID, 'position').position
|
||||
}));
|
||||
}, 1000);
|
||||
},
|
||||
unload: function() {
|
||||
Script.clearInterval(this.heartbeatTimerID);
|
||||
}
|
||||
};
|
||||
|
||||
return new Enemy();
|
||||
});
|
BIN
unpublishedScripts/marketplace/shortbow/models/Amber.fbx
Normal file
BIN
unpublishedScripts/marketplace/shortbow/models/Amber.fbx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
877
unpublishedScripts/marketplace/shortbow/shortbow.js
Normal file
877
unpublishedScripts/marketplace/shortbow/shortbow.js
Normal file
|
@ -0,0 +1,877 @@
|
|||
//
|
||||
// Created by Ryan Huffman on 1/10/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
/* globals SHORTBOW_ENTITIES:true */
|
||||
|
||||
// This is a copy of the data in shortbow.json, which is an export of the shortbow
|
||||
// scene.
|
||||
//
|
||||
// Because .json can't be Script.include'd directly, the contents are copied over
|
||||
// to here and exposed as a global variable.
|
||||
//
|
||||
|
||||
SHORTBOW_ENTITIES =
|
||||
{
|
||||
"Entities": [
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{02f39515-cab4-41d5-b315-5fb41613f844}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708750446,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -5.1684012413024902,
|
||||
"y": 0.54034698009490967,
|
||||
"z": -11.257695198059082
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": -1.3604279756546021,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"backgroundColor": {
|
||||
"blue": 65,
|
||||
"green": 78,
|
||||
"red": 82
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 2,
|
||||
"y": 0.69999998807907104,
|
||||
"z": 0.0099999997764825821
|
||||
},
|
||||
"id": "{3eae601e-3c6e-49ab-8f40-dedee32f7573}",
|
||||
"lastEdited": 1487894036038423,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"lineHeight": 0.5,
|
||||
"name": "SB.DisplayScore",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -8.0707607269287109,
|
||||
"y": 1.5265679359436035,
|
||||
"z": -9.5913219451904297
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 2.118985652923584,
|
||||
"x": -5.1109838485717773,
|
||||
"y": -1803.69189453125,
|
||||
"z": -26.774648666381836
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.70708787441253662,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.70708787441253662,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"text": "0",
|
||||
"type": "Text",
|
||||
"userData": "{\"displayType\":\"score\"}"
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.71920669078826904,
|
||||
"y": 3.3160061836242676,
|
||||
"z": 2.2217941284179688
|
||||
},
|
||||
"id": "{04288f77-64df-4323-ac38-9c1960a393a5}",
|
||||
"lastEdited": 1487893058314990,
|
||||
"lastEditedBy": "{fce8028a-4bac-43e8-96ff-4c7286ea4ab3}",
|
||||
"modelURL": "file:///c:/Users/ryanh/dev/hifi/unpublishedScripts/marketplace/shortbow/models/shortbow-button.fbx",
|
||||
"name": "SB.StartButton",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -9.8358345031738281,
|
||||
"y": 0.45674961805343628,
|
||||
"z": -13.044205665588379
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 4.0558013916015625,
|
||||
"x": -7.844393253326416,
|
||||
"y": -1805.730224609375,
|
||||
"z": -31.195960998535156
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": 1.52587890625e-05,
|
||||
"y": 1.52587890625e-05,
|
||||
"z": 1.52587890625e-05
|
||||
},
|
||||
"script": "file:///c:/Users/ryanh/dev/hifi/unpublishedScripts/marketplace/shortbow/startGameButtonClientEntity.js",
|
||||
"shapeType": "static-mesh",
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"wantsTrigger\":true}}"
|
||||
},
|
||||
{
|
||||
"backgroundColor": {
|
||||
"blue": 65,
|
||||
"green": 78,
|
||||
"red": 82
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 2,
|
||||
"y": 0.69999998807907104,
|
||||
"z": 0.0099999997764825821
|
||||
},
|
||||
"id": "{1196096f-bcc9-4b19-970d-605113474c1b}",
|
||||
"lastEdited": 1487894037900323,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"lineHeight": 0.5,
|
||||
"name": "SB.DisplayHighScore",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -8.0707607269287109,
|
||||
"y": 0.26189804077148438,
|
||||
"z": -9.5913219451904297
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 2.118985652923584,
|
||||
"x": -5.11102294921875,
|
||||
"y": -1804.95654296875,
|
||||
"z": -26.77461051940918
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.70708787441253662,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.70708787441253662,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"text": "0",
|
||||
"type": "Text",
|
||||
"userData": "{\"displayType\":\"highscore\"}"
|
||||
},
|
||||
{
|
||||
"backgroundColor": {
|
||||
"blue": 65,
|
||||
"green": 78,
|
||||
"red": 82
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 1.4120937585830688,
|
||||
"y": 0.71569448709487915,
|
||||
"z": 0.0099999997764825821
|
||||
},
|
||||
"id": "{293c294d-1df5-461e-82a3-66abee852d44}",
|
||||
"lastEdited": 1487894033695485,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"lineHeight": 0.5,
|
||||
"name": "SB.DisplayWave",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -8.0707607269287109,
|
||||
"y": 1.5265679359436035,
|
||||
"z": -7.2889409065246582
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 1.5831384658813477,
|
||||
"x": -4.8431310653686523,
|
||||
"y": -1803.4239501953125,
|
||||
"z": -24.204343795776367
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.70708787441253662,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.70708787441253662,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"text": "0",
|
||||
"type": "Text",
|
||||
"userData": "{\"displayType\":\"wave\"}"
|
||||
},
|
||||
{
|
||||
"backgroundColor": {
|
||||
"blue": 65,
|
||||
"green": 78,
|
||||
"red": 82
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 1.4120937585830688,
|
||||
"y": 0.71569448709487915,
|
||||
"z": 0.0099999997764825821
|
||||
},
|
||||
"id": "{379afa7b-c668-4c4e-b290-e5c37fb3440c}",
|
||||
"lastEdited": 1487893055310428,
|
||||
"lastEditedBy": "{fce8028a-4bac-43e8-96ff-4c7286ea4ab3}",
|
||||
"lineHeight": 0.5,
|
||||
"name": "SB.DisplayLives",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -8.0707607269287109,
|
||||
"y": 0.26189804077148438,
|
||||
"z": -7.2889409065246582
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 1.5831384658813477,
|
||||
"x": -4.8431692123413086,
|
||||
"y": -1804.6885986328125,
|
||||
"z": -24.204303741455078
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.70708787441253662,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.70708787441253662,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"text": "0",
|
||||
"type": "Text",
|
||||
"userData": "{\"displayType\":\"lives\"}"
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 171,
|
||||
"green": 50,
|
||||
"red": 62
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{760e81a1-a804-4f5e-9769-393d021fc8fe}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892440234633,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.EnemySpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -1.89238440990448,
|
||||
"y": -5.3368110656738281,
|
||||
"z": 11.512755393981934
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 1.9147146940231323,
|
||||
"y": -1809.7066650390625,
|
||||
"z": -4.8219971656799316
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 171,
|
||||
"green": 50,
|
||||
"red": 62
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{0a76d0ac-6353-467b-8edc-56417d5a987c}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892440235124,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.EnemySpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 3.6569130420684814,
|
||||
"y": -5.3365960121154785,
|
||||
"z": 10.01292610168457
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 7.4640579223632812,
|
||||
"y": -1809.7066650390625,
|
||||
"z": -6.3216567039489746
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 171,
|
||||
"green": 50,
|
||||
"red": 62
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{f8549c8a-e646-4feb-bbaf-70e7d5be755a}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892440235339,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.EnemySpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 8.8902750015258789,
|
||||
"y": -5.3364419937133789,
|
||||
"z": 10.195274353027344
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 12.697414398193359,
|
||||
"y": -1809.7066650390625,
|
||||
"z": -6.1391491889953613
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{f3aea4ae-4445-4a2d-8d61-e9fd72f04008}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708751269,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -2.5027251243591309,
|
||||
"y": 0.54042834043502808,
|
||||
"z": -11.257777214050293
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 1.3052481412887573,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{cc1ac907-124b-4372-8c4c-82d175546725}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708751135,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 2.7972855567932129,
|
||||
"y": 0.54059004783630371,
|
||||
"z": -11.257938385009766
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 6.6052589416503906,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{e25ce690-e267-4c51-80a0-f63a72474b8a}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708751527,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 0.17114110291004181,
|
||||
"y": 0.54050993919372559,
|
||||
"z": -11.257858276367188
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 3.979114294052124,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{91ee2285-38f8-4795-b6bc-7abc8dcde07c}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708750806,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 5.4656705856323242,
|
||||
"y": 0.54067152738571167,
|
||||
"z": -11.258020401000977
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 9.2736434936523438,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{d81e5fae-8a8d-4186-bbd2-0c3ae737b0f2}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892552671000,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 9.6099967956542969,
|
||||
"y": 0.64012420177459717,
|
||||
"z": -9.9802846908569336
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 13.417934417724609,
|
||||
"y": -1803.730712890625,
|
||||
"z": -26.314868927001953
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.22495110332965851,
|
||||
"x": -2.9734959753113799e-05,
|
||||
"y": 0.97437006235122681,
|
||||
"z": 2.9735869247815572e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{7056e21e-bce6-4c4b-bbca-36bea1dce303}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708750993,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 8.1799373626708984,
|
||||
"y": 0.54075431823730469,
|
||||
"z": -11.258102416992188
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 11.987911224365234,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 171,
|
||||
"green": 50,
|
||||
"red": 62
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{ed073620-e304-4b8e-b12a-5371b595bbf6}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892440234415,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.EnemySpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -2.3618791103363037,
|
||||
"y": -2.0691573619842529,
|
||||
"z": 11.254574775695801
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 1.4453276395797729,
|
||||
"y": -1806.43896484375,
|
||||
"z": -5.0802912712097168
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 171,
|
||||
"green": 50,
|
||||
"red": 62
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{32ed7820-c386-4da1-b676-7e63762861a3}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892440234854,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.EnemySpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 0.64757472276687622,
|
||||
"y": -2.5217375755310059,
|
||||
"z": 10.08248233795166
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 4.454803466796875,
|
||||
"y": -1806.8917236328125,
|
||||
"z": -6.2522788047790527
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 26.619264602661133,
|
||||
"y": 14.24090576171875,
|
||||
"z": 39.351066589355469
|
||||
},
|
||||
"id": "{d4c8f577-944d-4d50-ac85-e56387c0ef0a}",
|
||||
"lastEdited": 1487892440231278,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"modelURL": "file:///c:/Users/ryanh/dev/hifi/unpublishedScripts/marketplace/shortbow/models/shortbow-platform.fbx",
|
||||
"name": "SB.Platform",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 0.097909502685070038,
|
||||
"y": -1.0163799524307251,
|
||||
"z": 2.0321114063262939
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 49.597328186035156,
|
||||
"x": -20.681917190551758,
|
||||
"y": -1829.9739990234375,
|
||||
"z": -38.890060424804688
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shapeType": "static-mesh",
|
||||
"type": "Model"
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 23.341892242431641,
|
||||
"y": 12.223045349121094,
|
||||
"z": 32.012016296386719
|
||||
},
|
||||
"friction": 1,
|
||||
"id": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"lastEdited": 1487892440231832,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"modelURL": "file:///c:/Users/ryanh/dev/hifi/unpublishedScripts/marketplace/shortbow/models/shortbow-scoreboard.fbx",
|
||||
"name": "SB.Scoreboard",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"queryAACube": {
|
||||
"scale": 41.461017608642578,
|
||||
"x": -20.730508804321289,
|
||||
"y": -20.730508804321289,
|
||||
"z": -20.730508804321289
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"serverScripts": "file:///c:/Users/ryanh/dev/hifi/unpublishedScripts/marketplace/shortbow/shortbowServerEntity.js",
|
||||
"shapeType": "static-mesh",
|
||||
"type": "Model"
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 15.710711479187012,
|
||||
"y": 4.7783288955688477,
|
||||
"z": 1.6129581928253174
|
||||
},
|
||||
"id": "{84cdff6e-a68d-4bbf-8660-2d6a8c2f1fd0}",
|
||||
"lastEdited": 1487892440231522,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.GateCollider",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 0.31728419661521912,
|
||||
"y": -4.3002614974975586,
|
||||
"z": -12.531644821166992
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 16.50031852722168,
|
||||
"x": -3.913693904876709,
|
||||
"y": -1816.709716796875,
|
||||
"z": -36.905204772949219
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
}
|
||||
],
|
||||
"Version": 68
|
||||
};
|
||||
|
||||
// Add LocalPosition to entity data if parent properties are available
|
||||
var entities = SHORTBOW_ENTITIES.Entities;
|
||||
var entitiesByID = {};
|
||||
var i, entity;
|
||||
for (i = 0; i < entities.length; ++i) {
|
||||
entity = entities[i];
|
||||
entitiesByID[entity.id] = entity;
|
||||
}
|
||||
for (i = 0; i < entities.length; ++i) {
|
||||
entity = entities[i];
|
||||
if (entity.parentID !== undefined) {
|
||||
var parent = entitiesByID[entity.parentID];
|
||||
if (parent !== undefined) {
|
||||
entity.localPosition = Vec3.subtract(entity.position, parent.position);
|
||||
delete entity.position;
|
||||
}
|
||||
}
|
||||
}
|
840
unpublishedScripts/marketplace/shortbow/shortbow.json
Normal file
840
unpublishedScripts/marketplace/shortbow/shortbow.json
Normal file
|
@ -0,0 +1,840 @@
|
|||
{
|
||||
"Entities": [
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{02f39515-cab4-41d5-b315-5fb41613f844}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708750446,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -5.1684012413024902,
|
||||
"y": 0.54034698009490967,
|
||||
"z": -11.257695198059082
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": -1.3604279756546021,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"backgroundColor": {
|
||||
"blue": 65,
|
||||
"green": 78,
|
||||
"red": 82
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 2,
|
||||
"y": 0.69999998807907104,
|
||||
"z": 0.0099999997764825821
|
||||
},
|
||||
"id": "{3eae601e-3c6e-49ab-8f40-dedee32f7573}",
|
||||
"lastEdited": 1487894036038423,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"lineHeight": 0.5,
|
||||
"name": "SB.DisplayScore",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -8.0707607269287109,
|
||||
"y": 1.5265679359436035,
|
||||
"z": -9.5913219451904297
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 2.118985652923584,
|
||||
"x": -5.1109838485717773,
|
||||
"y": -1803.69189453125,
|
||||
"z": -26.774648666381836
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.70708787441253662,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.70708787441253662,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"text": "0",
|
||||
"type": "Text",
|
||||
"userData": "{\"displayType\":\"score\"}"
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.71920669078826904,
|
||||
"y": 3.3160061836242676,
|
||||
"z": 2.2217941284179688
|
||||
},
|
||||
"id": "{04288f77-64df-4323-ac38-9c1960a393a5}",
|
||||
"lastEdited": 1487893058314990,
|
||||
"lastEditedBy": "{fce8028a-4bac-43e8-96ff-4c7286ea4ab3}",
|
||||
"modelURL": "file:///c:/Users/ryanh/dev/hifi/unpublishedScripts/marketplace/shortbow/models/shortbow-button.fbx",
|
||||
"name": "SB.StartButton",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -9.8358345031738281,
|
||||
"y": 0.45674961805343628,
|
||||
"z": -13.044205665588379
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 4.0558013916015625,
|
||||
"x": -7.844393253326416,
|
||||
"y": -1805.730224609375,
|
||||
"z": -31.195960998535156
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": 1.52587890625e-05,
|
||||
"y": 1.52587890625e-05,
|
||||
"z": 1.52587890625e-05
|
||||
},
|
||||
"script": "file:///c:/Users/ryanh/dev/hifi/unpublishedScripts/marketplace/shortbow/startGameButtonClientEntity.js",
|
||||
"shapeType": "static-mesh",
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"wantsTrigger\":true}}"
|
||||
},
|
||||
{
|
||||
"backgroundColor": {
|
||||
"blue": 65,
|
||||
"green": 78,
|
||||
"red": 82
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 2,
|
||||
"y": 0.69999998807907104,
|
||||
"z": 0.0099999997764825821
|
||||
},
|
||||
"id": "{1196096f-bcc9-4b19-970d-605113474c1b}",
|
||||
"lastEdited": 1487894037900323,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"lineHeight": 0.5,
|
||||
"name": "SB.DisplayHighScore",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -8.0707607269287109,
|
||||
"y": 0.26189804077148438,
|
||||
"z": -9.5913219451904297
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 2.118985652923584,
|
||||
"x": -5.11102294921875,
|
||||
"y": -1804.95654296875,
|
||||
"z": -26.77461051940918
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.70708787441253662,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.70708787441253662,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"text": "0",
|
||||
"type": "Text",
|
||||
"userData": "{\"displayType\":\"highscore\"}"
|
||||
},
|
||||
{
|
||||
"backgroundColor": {
|
||||
"blue": 65,
|
||||
"green": 78,
|
||||
"red": 82
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 1.4120937585830688,
|
||||
"y": 0.71569448709487915,
|
||||
"z": 0.0099999997764825821
|
||||
},
|
||||
"id": "{293c294d-1df5-461e-82a3-66abee852d44}",
|
||||
"lastEdited": 1487894033695485,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"lineHeight": 0.5,
|
||||
"name": "SB.DisplayWave",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -8.0707607269287109,
|
||||
"y": 1.5265679359436035,
|
||||
"z": -7.2889409065246582
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 1.5831384658813477,
|
||||
"x": -4.8431310653686523,
|
||||
"y": -1803.4239501953125,
|
||||
"z": -24.204343795776367
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.70708787441253662,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.70708787441253662,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"text": "0",
|
||||
"type": "Text",
|
||||
"userData": "{\"displayType\":\"wave\"}"
|
||||
},
|
||||
{
|
||||
"backgroundColor": {
|
||||
"blue": 65,
|
||||
"green": 78,
|
||||
"red": 82
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 1.4120937585830688,
|
||||
"y": 0.71569448709487915,
|
||||
"z": 0.0099999997764825821
|
||||
},
|
||||
"id": "{379afa7b-c668-4c4e-b290-e5c37fb3440c}",
|
||||
"lastEdited": 1487893055310428,
|
||||
"lastEditedBy": "{fce8028a-4bac-43e8-96ff-4c7286ea4ab3}",
|
||||
"lineHeight": 0.5,
|
||||
"name": "SB.DisplayLives",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -8.0707607269287109,
|
||||
"y": 0.26189804077148438,
|
||||
"z": -7.2889409065246582
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 1.5831384658813477,
|
||||
"x": -4.8431692123413086,
|
||||
"y": -1804.6885986328125,
|
||||
"z": -24.204303741455078
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.70708787441253662,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": 0.70708787441253662,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"text": "0",
|
||||
"type": "Text",
|
||||
"userData": "{\"displayType\":\"lives\"}"
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 171,
|
||||
"green": 50,
|
||||
"red": 62
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{760e81a1-a804-4f5e-9769-393d021fc8fe}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892440234633,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.EnemySpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -1.89238440990448,
|
||||
"y": -5.3368110656738281,
|
||||
"z": 11.512755393981934
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 1.9147146940231323,
|
||||
"y": -1809.7066650390625,
|
||||
"z": -4.8219971656799316
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 171,
|
||||
"green": 50,
|
||||
"red": 62
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{0a76d0ac-6353-467b-8edc-56417d5a987c}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892440235124,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.EnemySpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 3.6569130420684814,
|
||||
"y": -5.3365960121154785,
|
||||
"z": 10.01292610168457
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 7.4640579223632812,
|
||||
"y": -1809.7066650390625,
|
||||
"z": -6.3216567039489746
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 171,
|
||||
"green": 50,
|
||||
"red": 62
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{f8549c8a-e646-4feb-bbaf-70e7d5be755a}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892440235339,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.EnemySpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 8.8902750015258789,
|
||||
"y": -5.3364419937133789,
|
||||
"z": 10.195274353027344
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 12.697414398193359,
|
||||
"y": -1809.7066650390625,
|
||||
"z": -6.1391491889953613
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{f3aea4ae-4445-4a2d-8d61-e9fd72f04008}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708751269,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -2.5027251243591309,
|
||||
"y": 0.54042834043502808,
|
||||
"z": -11.257777214050293
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 1.3052481412887573,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{cc1ac907-124b-4372-8c4c-82d175546725}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708751135,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 2.7972855567932129,
|
||||
"y": 0.54059004783630371,
|
||||
"z": -11.257938385009766
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 6.6052589416503906,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{e25ce690-e267-4c51-80a0-f63a72474b8a}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708751527,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 0.17114110291004181,
|
||||
"y": 0.54050993919372559,
|
||||
"z": -11.257858276367188
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 3.979114294052124,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{91ee2285-38f8-4795-b6bc-7abc8dcde07c}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708750806,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 5.4656705856323242,
|
||||
"y": 0.54067152738571167,
|
||||
"z": -11.258020401000977
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 9.2736434936523438,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{d81e5fae-8a8d-4186-bbd2-0c3ae737b0f2}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892552671000,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 9.6099967956542969,
|
||||
"y": 0.64012420177459717,
|
||||
"z": -9.9802846908569336
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 13.417934417724609,
|
||||
"y": -1803.730712890625,
|
||||
"z": -26.314868927001953
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.22495110332965851,
|
||||
"x": -2.9734959753113799e-05,
|
||||
"y": 0.97437006235122681,
|
||||
"z": 2.9735869247815572e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{7056e21e-bce6-4c4b-bbca-36bea1dce303}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892708750993,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.BowSpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 8.1799373626708984,
|
||||
"y": 0.54075431823730469,
|
||||
"z": -11.258102416992188
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 11.987911224365234,
|
||||
"y": -1803.830078125,
|
||||
"z": -27.592727661132812
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.17366324365139008,
|
||||
"x": 4.9033405957743526e-07,
|
||||
"y": -0.98480510711669922,
|
||||
"z": -2.9563087082351558e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 171,
|
||||
"green": 50,
|
||||
"red": 62
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{ed073620-e304-4b8e-b12a-5371b595bbf6}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892440234415,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.EnemySpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": -2.3618791103363037,
|
||||
"y": -2.0691573619842529,
|
||||
"z": 11.254574775695801
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 1.4453276395797729,
|
||||
"y": -1806.43896484375,
|
||||
"z": -5.0802912712097168
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"collisionless": 1,
|
||||
"color": {
|
||||
"blue": 171,
|
||||
"green": 50,
|
||||
"red": 62
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 0.24400754272937775,
|
||||
"y": 0.24400754272937775,
|
||||
"z": 0.24400754272937775
|
||||
},
|
||||
"id": "{32ed7820-c386-4da1-b676-7e63762861a3}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1487892440234854,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.EnemySpawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 0.64757472276687622,
|
||||
"y": -2.5217375755310059,
|
||||
"z": 10.08248233795166
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.42263346910476685,
|
||||
"x": 4.454803466796875,
|
||||
"y": -1806.8917236328125,
|
||||
"z": -6.2522788047790527
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 26.619264602661133,
|
||||
"y": 14.24090576171875,
|
||||
"z": 39.351066589355469
|
||||
},
|
||||
"id": "{d4c8f577-944d-4d50-ac85-e56387c0ef0a}",
|
||||
"lastEdited": 1487892440231278,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"modelURL": "file:///c:/Users/ryanh/dev/hifi/unpublishedScripts/marketplace/shortbow/models/shortbow-platform.fbx",
|
||||
"name": "SB.Platform",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 0.097909502685070038,
|
||||
"y": -1.0163799524307251,
|
||||
"z": 2.0321114063262939
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 49.597328186035156,
|
||||
"x": -20.681917190551758,
|
||||
"y": -1829.9739990234375,
|
||||
"z": -38.890060424804688
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shapeType": "static-mesh",
|
||||
"type": "Model"
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 23.341892242431641,
|
||||
"y": 12.223045349121094,
|
||||
"z": 32.012016296386719
|
||||
},
|
||||
"friction": 1,
|
||||
"id": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"lastEdited": 1487892440231832,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"modelURL": "file:///c:/Users/ryanh/dev/hifi/unpublishedScripts/marketplace/shortbow/models/shortbow-scoreboard.fbx",
|
||||
"name": "SB.Scoreboard",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"queryAACube": {
|
||||
"scale": 41.461017608642578,
|
||||
"x": -20.730508804321289,
|
||||
"y": -20.730508804321289,
|
||||
"z": -20.730508804321289
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"serverScripts": "file:///c:/Users/ryanh/dev/hifi/unpublishedScripts/marketplace/shortbow/shortbowServerEntity.js",
|
||||
"shapeType": "static-mesh",
|
||||
"type": "Model"
|
||||
},
|
||||
{
|
||||
"clientOnly": 0,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"created": "2017-02-23T23:28:32Z",
|
||||
"dimensions": {
|
||||
"x": 15.710711479187012,
|
||||
"y": 4.7783288955688477,
|
||||
"z": 1.6129581928253174
|
||||
},
|
||||
"id": "{84cdff6e-a68d-4bbf-8660-2d6a8c2f1fd0}",
|
||||
"lastEdited": 1487892440231522,
|
||||
"lastEditedBy": "{91f193dd-829a-4b33-ab27-e9a26160634a}",
|
||||
"name": "SB.GateCollider",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"parentID": "{0cd1f1f7-53b9-4c15-bf25-42c0760d16f0}",
|
||||
"position": {
|
||||
"x": 0.31728419661521912,
|
||||
"y": -4.3002614974975586,
|
||||
"z": -12.531644821166992
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 16.50031852722168,
|
||||
"x": -3.913693904876709,
|
||||
"y": -1816.709716796875,
|
||||
"z": -36.905204772949219
|
||||
},
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"visible": 0
|
||||
}
|
||||
],
|
||||
"Version": 68
|
||||
}
|
621
unpublishedScripts/marketplace/shortbow/shortbowGameManager.js
Normal file
621
unpublishedScripts/marketplace/shortbow/shortbowGameManager.js
Normal file
|
@ -0,0 +1,621 @@
|
|||
//
|
||||
// Created by Ryan Huffman on 1/10/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
/* globals ShortbowGameManager:true, utils */
|
||||
|
||||
Script.include('utils.js');
|
||||
|
||||
// +--------+ +-----------+ +-----------------+
|
||||
// | | | |<-----+ |
|
||||
// | IDLE +----->| PLAYING | | BETWEEN_WAVES |
|
||||
// | | | +----->| |
|
||||
// +--------+ +-----+-----+ +-----------------+
|
||||
// ^ |
|
||||
// | v
|
||||
// | +-------------+
|
||||
// | | |
|
||||
// +---------+ GAME_OVER |
|
||||
// | |
|
||||
// +-------------+
|
||||
var GAME_STATES = {
|
||||
IDLE: 0,
|
||||
PLAYING: 1,
|
||||
BETWEEN_WAVES: 2,
|
||||
GAME_OVER: 3
|
||||
};
|
||||
|
||||
// Load the sounds that we will be using in the game so they are ready to be
|
||||
// used when we need them.
|
||||
var BEGIN_BUILDING_SOUND = SoundCache.getSound(Script.resolvePath("sounds/gameOn.wav"));
|
||||
var GAME_OVER_SOUND = SoundCache.getSound(Script.resolvePath("sounds/gameOver.wav"));
|
||||
var WAVE_COMPLETE_SOUND = SoundCache.getSound(Script.resolvePath("sounds/waveComplete.wav"));
|
||||
var EXPLOSION_SOUND = SoundCache.getSound(Script.resolvePath("sounds/explosion.wav"));
|
||||
var TARGET_HIT_SOUND = SoundCache.getSound(Script.resolvePath("sounds/targetHit.wav"));
|
||||
var ESCAPE_SOUND = SoundCache.getSound(Script.resolvePath("sounds/escape.wav"));
|
||||
|
||||
const STARTING_NUMBER_OF_LIVES = 6;
|
||||
const ENEMIES_PER_WAVE_MULTIPLIER = 2;
|
||||
const POINTS_PER_KILL = 100;
|
||||
const ENEMY_SPEED = 3.0;
|
||||
|
||||
// Encode a set of key-value pairs into a param string. Does NOT do any URL escaping.
|
||||
function encodeURLParams(params) {
|
||||
var paramPairs = [];
|
||||
for (var key in params) {
|
||||
paramPairs.push(key + "=" + params[key]);
|
||||
}
|
||||
return paramPairs.join("&");
|
||||
}
|
||||
|
||||
function sendAndUpdateHighScore(entityID, score, wave, numPlayers, onResposeReceived) {
|
||||
const URL = 'https://script.google.com/macros/s/AKfycbwbjCm9mGd1d5BzfAHmVT_XKmWyUYRkjCEqDOKm1368oM8nqWni/exec';
|
||||
print("Sending high score");
|
||||
|
||||
const paramString = encodeURLParams({
|
||||
entityID: entityID,
|
||||
score: score,
|
||||
wave: wave,
|
||||
numPlayers: numPlayers
|
||||
});
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
request.onreadystatechange = function() {
|
||||
print("ready state: ", request.readyState, request.status, request.readyState === request.DONE, request.response);
|
||||
if (request.readyState === request.DONE && request.status === 200) {
|
||||
print("Got response for high score: ", request.response);
|
||||
var response = JSON.parse(request.responseText);
|
||||
if (response.highScore !== undefined) {
|
||||
onResposeReceived(response.highScore);
|
||||
}
|
||||
}
|
||||
};
|
||||
request.open('GET', URL + "?" + paramString);
|
||||
request.timeout = 10000;
|
||||
request.send();
|
||||
}
|
||||
|
||||
function findChildrenWithName(parentID, name) {
|
||||
var childrenIDs = Entities.getChildrenIDs(parentID);
|
||||
var matchingIDs = [];
|
||||
for (var i = 0; i < childrenIDs.length; ++i) {
|
||||
var id = childrenIDs[i];
|
||||
var childName = Entities.getEntityProperties(id, 'name').name;
|
||||
if (childName === name) {
|
||||
matchingIDs.push(id);
|
||||
}
|
||||
}
|
||||
return matchingIDs;
|
||||
}
|
||||
|
||||
function getPropertiesForEntities(entityIDs, desiredProperties) {
|
||||
var properties = [];
|
||||
for (var i = 0; i < entityIDs.length; ++i) {
|
||||
properties.push(Entities.getEntityProperties(entityIDs[i], desiredProperties));
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
var baseEnemyProperties = {
|
||||
"name": "SB.Enemy",
|
||||
"damping": 0,
|
||||
"linearDamping": 0,
|
||||
"angularDamping": 0,
|
||||
"acceleration": {
|
||||
"x": 0,
|
||||
"y": -9,
|
||||
"z": 0
|
||||
},
|
||||
"angularVelocity": {
|
||||
"x": -0.058330666273832321,
|
||||
"y": -0.77943277359008789,
|
||||
"z": -2.1163818836212158
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"collisionsWillMove": 1,
|
||||
"dimensions": {
|
||||
"x": 0.63503998517990112,
|
||||
"y": 0.63503998517990112,
|
||||
"z": 0.63503998517990112
|
||||
},
|
||||
"dynamic": 1,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": -15,
|
||||
"z": 0
|
||||
},
|
||||
"lifetime": 30,
|
||||
"id": "{ed8f7339-8bbd-4750-968e-c3ceb9d64721}",
|
||||
"modelURL": Script.resolvePath("models/Amber.fbx"),
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"queryAACube": {
|
||||
"scale": 1.0999215841293335,
|
||||
"x": -0.54996079206466675,
|
||||
"y": -0.54996079206466675,
|
||||
"z": -0.54996079206466675
|
||||
},
|
||||
"shapeType": "sphere",
|
||||
"type": "Model",
|
||||
"script": Script.resolvePath('enemyClientEntity.js'),
|
||||
"serverScripts": Script.resolvePath('enemyServerEntity.js')
|
||||
};
|
||||
|
||||
function searchForChildren(parentID, names, callback, timeoutMs) {
|
||||
// Map from name to entity ID for the children that have been found
|
||||
var foundEntities = {};
|
||||
for (var i = 0; i < names.length; ++i) {
|
||||
foundEntities[names[i]] = null;
|
||||
}
|
||||
|
||||
const CHECK_EVERY_MS = 500;
|
||||
const maxChecks = Math.ceil(timeoutMs / CHECK_EVERY_MS);
|
||||
|
||||
var check = 0;
|
||||
var intervalID = Script.setInterval(function() {
|
||||
check++;
|
||||
|
||||
var childrenIDs = Entities.getChildrenIDs(parentID);
|
||||
print("\tNumber of children:", childrenIDs.length);
|
||||
|
||||
for (var i = 0; i < childrenIDs.length; ++i) {
|
||||
print("\t\t" + i + ".", Entities.getEntityProperties(childrenIDs[i]).name);
|
||||
var id = childrenIDs[i];
|
||||
var name = Entities.getEntityProperties(id, 'name').name;
|
||||
var idx = names.indexOf(name);
|
||||
if (idx > -1) {
|
||||
foundEntities[name] = id;
|
||||
print(name, id);
|
||||
names.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (names.length === 0 || check >= maxChecks) {
|
||||
Script.clearInterval(intervalID);
|
||||
callback(foundEntities);
|
||||
}
|
||||
}, CHECK_EVERY_MS);
|
||||
}
|
||||
|
||||
ShortbowGameManager = function(rootEntityID, bowPositions, spawnPositions) {
|
||||
print("Starting game manager");
|
||||
var self = this;
|
||||
|
||||
this.gameState = GAME_STATES.IDLE;
|
||||
|
||||
this.rootEntityID = rootEntityID;
|
||||
this.bowPositions = bowPositions;
|
||||
this.rootPosition = null;
|
||||
this.spawnPositions = spawnPositions;
|
||||
|
||||
this.loadedChildren = false;
|
||||
|
||||
const START_BUTTON_NAME = 'SB.StartButton';
|
||||
const WAVE_DISPLAY_NAME = 'SB.DisplayWave';
|
||||
const SCORE_DISPLAY_NAME = 'SB.DisplayScore';
|
||||
const LIVES_DISPLAY_NAME = 'SB.DisplayLives';
|
||||
const HIGH_SCORE_DISPLAY_NAME = 'SB.DisplayHighScore';
|
||||
|
||||
const SEARCH_FOR_CHILDREN_TIMEOUT = 5000;
|
||||
|
||||
searchForChildren(rootEntityID, [
|
||||
START_BUTTON_NAME,
|
||||
WAVE_DISPLAY_NAME,
|
||||
SCORE_DISPLAY_NAME,
|
||||
LIVES_DISPLAY_NAME,
|
||||
HIGH_SCORE_DISPLAY_NAME
|
||||
], function(children) {
|
||||
self.loadedChildren = true;
|
||||
self.startButtonID = children[START_BUTTON_NAME];
|
||||
self.waveDisplayID = children[WAVE_DISPLAY_NAME];
|
||||
self.scoreDisplayID = children[SCORE_DISPLAY_NAME];
|
||||
self.livesDisplayID = children[LIVES_DISPLAY_NAME];
|
||||
self.highScoreDisplayID = children[HIGH_SCORE_DISPLAY_NAME];
|
||||
|
||||
sendAndUpdateHighScore(self.rootEntityID, self.score, self.waveNumber, 1, self.setHighScore.bind(self));
|
||||
|
||||
self.reset();
|
||||
}, SEARCH_FOR_CHILDREN_TIMEOUT);
|
||||
|
||||
// Gameplay state
|
||||
this.waveNumber = 0;
|
||||
this.livesLeft = STARTING_NUMBER_OF_LIVES;
|
||||
this.score = 0;
|
||||
this.nextWaveTimer = null;
|
||||
this.spawnEnemyTimers = [];
|
||||
this.remainingEnemies = [];
|
||||
this.bowIDs = [];
|
||||
|
||||
this.startButtonChannelName = 'button-' + this.rootEntityID;
|
||||
|
||||
// Entity client and server scripts will send messages to this channel
|
||||
this.commChannelName = "shortbow-" + this.rootEntityID;
|
||||
Messages.subscribe(this.commChannelName);
|
||||
Messages.messageReceived.connect(this, this.onReceivedMessage);
|
||||
print("Listening on: ", this.commChannelName);
|
||||
Messages.sendMessage(this.commChannelName, 'hi');
|
||||
};
|
||||
ShortbowGameManager.prototype = {
|
||||
reset: function() {
|
||||
Entities.editEntity(this.startButtonID, { visible: true });
|
||||
},
|
||||
cleanup: function() {
|
||||
Messages.unsubscribe(this.commChannelName);
|
||||
Messages.messageReceived.disconnect(this, this.onReceivedMessage);
|
||||
|
||||
if (this.checkEnemiesTimer) {
|
||||
Script.clearInterval(this.checkEnemiesTimer);
|
||||
this.checkEnemiesTimer = null;
|
||||
}
|
||||
|
||||
for (var i = this.bowIDs.length - 1; i >= 0; i--) {
|
||||
Entities.deleteEntity(this.bowIDs[i]);
|
||||
}
|
||||
this.bowIDs = [];
|
||||
for (i = 0; i < this.remainingEnemies.length; i++) {
|
||||
Entities.deleteEntity(this.remainingEnemies[i].id);
|
||||
}
|
||||
this.remainingEnemies = [];
|
||||
|
||||
this.gameState = GAME_STATES.IDLE;
|
||||
},
|
||||
startGame: function() {
|
||||
if (this.gameState !== GAME_STATES.IDLE) {
|
||||
print("shortbowGameManagerManager.js | Error, trying to start game when not in idle state");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.loadedChildren === false) {
|
||||
print('shortbowGameManager.js | Children have not loaded, not allowing game to start');
|
||||
return;
|
||||
}
|
||||
|
||||
print("Game started!!");
|
||||
|
||||
this.rootPosition = Entities.getEntityProperties(this.rootEntityID, 'position').position;
|
||||
|
||||
Entities.editEntity(this.startButtonID, { visible: false });
|
||||
|
||||
// Spawn bows
|
||||
var bowSpawnEntityIDs = findChildrenWithName(this.rootEntityID, 'SB.BowSpawn');
|
||||
var bowSpawnProperties = getPropertiesForEntities(bowSpawnEntityIDs, ['position', 'rotation']);
|
||||
for (var i = 0; i < bowSpawnProperties.length; ++i) {
|
||||
const props = bowSpawnProperties[i];
|
||||
Vec3.print("Creating bow: " + i, props.position);
|
||||
this.bowIDs.push(Entities.addEntity({
|
||||
"position": props.position,
|
||||
"rotation": props.rotation,
|
||||
"collisionsWillMove": 1,
|
||||
"compoundShapeURL": Script.resolvePath("bow/bow_collision_hull.obj"),
|
||||
"created": "2016-09-01T23:57:55Z",
|
||||
"dimensions": {
|
||||
"x": 0.039999999105930328,
|
||||
"y": 1.2999999523162842,
|
||||
"z": 0.20000000298023224
|
||||
},
|
||||
"dynamic": 1,
|
||||
"gravity": {
|
||||
"x": 0,
|
||||
"y": -9.8,
|
||||
"z": 0
|
||||
},
|
||||
"modelURL": Script.resolvePath("bow/bow-deadly.fbx"),
|
||||
"name": "WG.Hifi-Bow",
|
||||
"script": Script.resolvePath("bow/bow.js"),
|
||||
"shapeType": "compound",
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.0813,\"y\":0.0452,\"z\":0.0095},{\"x\":-0.3946,\"y\":-0.6604,\"z\":0.4748,\"w\":-0.4275}],\"LeftHand\":[{\"x\":-0.0881,\"y\":0.0259,\"z\":0.0159},{\"x\":0.4427,\"y\":-0.6519,\"z\":0.4592,\"w\":0.4099}]}}}"
|
||||
}));
|
||||
}
|
||||
|
||||
// Initialize game state
|
||||
this.waveNumber = 0;
|
||||
this.setScore(0);
|
||||
this.setLivesLeft(STARTING_NUMBER_OF_LIVES);
|
||||
|
||||
this.nextWaveTimer = Script.setTimeout(this.startNextWave.bind(this), 100);
|
||||
this.spawnEnemyTimers = [];
|
||||
this.checkEnemiesTimer = null;
|
||||
this.remainingEnemies = [];
|
||||
|
||||
// SpawnQueue is a list of enemies left to spawn. Each entry looks like:
|
||||
//
|
||||
// { spawnAt: 1000, position: { x: 0, y: 0, z: 0 } }
|
||||
//
|
||||
// where spawnAt is the number of millseconds after the start of the wave
|
||||
// to spawn the enemy. The list is sorted by spawnAt, ascending.
|
||||
this.spawnQueue = [];
|
||||
|
||||
this.gameState = GAME_STATES.BETWEEN_WAVES;
|
||||
|
||||
Audio.playSound(BEGIN_BUILDING_SOUND, {
|
||||
volume: 1.0,
|
||||
position: this.rootPosition
|
||||
});
|
||||
},
|
||||
startNextWave: function() {
|
||||
if (this.gameState !== GAME_STATES.BETWEEN_WAVES) {
|
||||
return;
|
||||
}
|
||||
|
||||
print("Starting next wave");
|
||||
this.gameState = GAME_STATES.PLAYING;
|
||||
this.waveNumber++;
|
||||
this.remainingEnemies= [];
|
||||
this.spawnQueue = [];
|
||||
this.spawnStartTime = Date.now();
|
||||
|
||||
Entities.editEntity(this.waveDisplayID, { text: this.waveNumber});
|
||||
|
||||
var numberOfEnemiesLeftToSpawn = this.waveNumber * ENEMIES_PER_WAVE_MULTIPLIER;
|
||||
var delayBetweenSpawns = 2000 / Math.max(1, Math.log(this.waveNumber));
|
||||
var currentDelay = 2000;
|
||||
|
||||
print("Number of enemies:", numberOfEnemiesLeftToSpawn);
|
||||
this.checkEnemiesTimer = Script.setInterval(this.checkEnemies.bind(this), 100);
|
||||
|
||||
var enemySpawnEntityIDs = findChildrenWithName(this.rootEntityID, 'SB.EnemySpawn');
|
||||
var enemySpawnProperties = getPropertiesForEntities(enemySpawnEntityIDs, ['position', 'rotation']);
|
||||
|
||||
for (var i = 0; i < numberOfEnemiesLeftToSpawn; ++i) {
|
||||
print("Adding enemy");
|
||||
var idx = Math.floor(Math.random() * enemySpawnProperties.length);
|
||||
var props = enemySpawnProperties[idx];
|
||||
this.spawnQueue.push({
|
||||
spawnAt: currentDelay,
|
||||
position: props.position,
|
||||
rotation: props.rotation,
|
||||
velocity: Vec3.multiply(ENEMY_SPEED, Quat.getFront(props.rotation))
|
||||
|
||||
});
|
||||
currentDelay += delayBetweenSpawns;
|
||||
}
|
||||
|
||||
print("Starting wave", this.waveNumber);
|
||||
|
||||
},
|
||||
checkWaveComplete: function() {
|
||||
if (this.gameState !== GAME_STATES.PLAYING) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.spawnQueue.length === 0 && this.remainingEnemies.length === 0) {
|
||||
this.gameState = GAME_STATES.BETWEEN_WAVES;
|
||||
Script.setTimeout(this.startNextWave.bind(this), 5000);
|
||||
|
||||
Script.clearInterval(this.checkEnemiesTimer);
|
||||
this.checkEnemiesTimer = null;
|
||||
|
||||
// Play after 1.5s to let other sounds finish playing
|
||||
var self = this;
|
||||
Script.setTimeout(function() {
|
||||
Audio.playSound(WAVE_COMPLETE_SOUND, {
|
||||
volume: 1.0,
|
||||
position: self.rootPosition
|
||||
});
|
||||
}, 1500);
|
||||
}
|
||||
},
|
||||
setHighScore: function(highScore) {
|
||||
print("Setting high score to:", this.highScoreDisplayID, highScore);
|
||||
Entities.editEntity(this.highScoreDisplayID, { text: highScore });
|
||||
},
|
||||
setLivesLeft: function(lives) {
|
||||
lives = Math.max(0, lives);
|
||||
this.livesLeft = lives;
|
||||
Entities.editEntity(this.livesDisplayID, { text: this.livesLeft });
|
||||
},
|
||||
setScore: function(score) {
|
||||
this.score = score;
|
||||
Entities.editEntity(this.scoreDisplayID, { text: this.score });
|
||||
},
|
||||
checkEnemies: function() {
|
||||
if (this.gameState !== GAME_STATES.PLAYING) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the spawn queueu to see if there are any enemies that need to
|
||||
// be spawned
|
||||
var waveElapsedTime = Date.now() - this.spawnStartTime;
|
||||
while (this.spawnQueue.length > 0 && waveElapsedTime > this.spawnQueue[0].spawnAt) {
|
||||
baseEnemyProperties.position = this.spawnQueue[0].position;
|
||||
baseEnemyProperties.rotation = this.spawnQueue[0].rotation;
|
||||
baseEnemyProperties.velocity= this.spawnQueue[0].velocity;
|
||||
|
||||
baseEnemyProperties.userData = JSON.stringify({
|
||||
gameChannel: this.commChannelName,
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
});
|
||||
|
||||
var entityID = Entities.addEntity(baseEnemyProperties);
|
||||
this.remainingEnemies.push({
|
||||
id: entityID,
|
||||
lastKnownPosition: baseEnemyProperties.position,
|
||||
lastHeartbeat: Date.now()
|
||||
});
|
||||
this.spawnQueue.splice(0, 1);
|
||||
Script.setTimeout(function() {
|
||||
const JUMP_SPEED = 5.0;
|
||||
var velocity = Entities.getEntityProperties(entityID, 'velocity').velocity;
|
||||
velocity.y += JUMP_SPEED;
|
||||
Entities.editEntity(entityID, { velocity: velocity });
|
||||
|
||||
}, 500 + Math.random() * 4000);
|
||||
}
|
||||
|
||||
// Check the list of remaining enemies to see if any are too far away
|
||||
// or haven't been heard from in awhile - if so, delete them.
|
||||
var enemiesEscaped = false;
|
||||
const MAX_UNHEARD_TIME_BEFORE_DESTROYING_ENTITY_MS = 5000;
|
||||
const MAX_DISTANCE_FROM_GAME_BEFORE_DESTROYING_ENTITY = 200;
|
||||
for (var i = this.remainingEnemies.length - 1; i >= 0; --i) {
|
||||
var enemy = this.remainingEnemies[i];
|
||||
var timeSinceLastHeartbeat = Date.now() - enemy.lastHeartbeat;
|
||||
var distance = Vec3.distance(enemy.lastKnownPosition, this.rootPosition);
|
||||
if (timeSinceLastHeartbeat > MAX_UNHEARD_TIME_BEFORE_DESTROYING_ENTITY_MS
|
||||
|| distance > MAX_DISTANCE_FROM_GAME_BEFORE_DESTROYING_ENTITY) {
|
||||
|
||||
print("EXPIRING: ", enemy.id);
|
||||
Entities.deleteEntity(enemy.id);
|
||||
this.remainingEnemies.splice(i, 1);
|
||||
Audio.playSound(TARGET_HIT_SOUND, {
|
||||
volume: 1.0,
|
||||
position: this.rootPosition
|
||||
});
|
||||
this.setScore(this.score + POINTS_PER_KILL);
|
||||
enemiesEscaped = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (enemiesEscaped) {
|
||||
this.checkWaveComplete();
|
||||
}
|
||||
},
|
||||
endGame: function() {
|
||||
if (this.gameState !== GAME_STATES.PLAYING) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
Script.setTimeout(function() {
|
||||
Audio.playSound(GAME_OVER_SOUND, {
|
||||
volume: 1.0,
|
||||
position: self.rootPosition
|
||||
});
|
||||
}, 1500);
|
||||
|
||||
this.gameState = GAME_STATES.GAME_OVER;
|
||||
print("GAME OVER");
|
||||
|
||||
// Update high score
|
||||
sendAndUpdateHighScore(this.rootEntityID, this.score, this.waveNumber, 1, this.setHighScore.bind(this));
|
||||
|
||||
// Cleanup
|
||||
Script.clearTimeout(this.nextWaveTimer);
|
||||
this.nextWaveTimer = null;
|
||||
var i;
|
||||
for (i = 0; i < this.spawnEnemyTimers.length; ++i) {
|
||||
Script.clearTimeout(this.spawnEnemyTimers[i]);
|
||||
}
|
||||
this.spawnEnemyTimers = [];
|
||||
|
||||
Script.clearInterval(this.checkEnemiesTimer);
|
||||
this.checkEnemiesTimer = null;
|
||||
|
||||
|
||||
for (i = this.bowIDs.length - 1; i >= 0; i--) {
|
||||
var id = this.bowIDs[i];
|
||||
print("Checking bow: ", id);
|
||||
var userData = utils.parseJSON(Entities.getEntityProperties(id, 'userData').userData);
|
||||
var bowIsHeld = userData.grabKey !== undefined && userData.grabKey !== undefined && userData.grabKey.refCount > 0;
|
||||
print("Held: ", bowIsHeld);
|
||||
if (!bowIsHeld) {
|
||||
Entities.deleteEntity(id);
|
||||
this.bowIDs.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < this.remainingEnemies.length; i++) {
|
||||
Entities.deleteEntity(this.remainingEnemies[i].id);
|
||||
}
|
||||
this.remainingEnemies = [];
|
||||
|
||||
// Wait a short time before showing the start button so that any current sounds
|
||||
// can finish playing.
|
||||
const WAIT_TO_REENABLE_GAME_TIMEOUT_MS = 3000;
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(this.startButtonID, { visible: true });
|
||||
this.gameState = GAME_STATES.IDLE;
|
||||
}.bind(this), WAIT_TO_REENABLE_GAME_TIMEOUT_MS);
|
||||
},
|
||||
onReceivedMessage: function(channel, messageJSON, senderID) {
|
||||
if (channel === this.commChannelName) {
|
||||
var message = utils.parseJSON(messageJSON);
|
||||
if (message === undefined) {
|
||||
print("shortbowGameManager.js | Received non-json message:", JSON.stringify(messageJSON));
|
||||
return;
|
||||
}
|
||||
switch (message.type) {
|
||||
case 'start-game':
|
||||
this.startGame();
|
||||
break;
|
||||
case 'enemy-killed':
|
||||
this.onEnemyKilled(message.entityID, message.position);
|
||||
break;
|
||||
case 'enemy-escaped':
|
||||
this.onEnemyEscaped(message.entityID);
|
||||
break;
|
||||
case 'enemy-heartbeat':
|
||||
this.onEnemyHeartbeat(message.entityID, message.position);
|
||||
break;
|
||||
default:
|
||||
print("shortbowGameManager.js | Ignoring unknown message type: ", message.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
onEnemyKilled: function(entityID, position) {
|
||||
if (this.gameState !== GAME_STATES.PLAYING) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = this.remainingEnemies.length - 1; i >= 0; --i) {
|
||||
var enemy = this.remainingEnemies[i];
|
||||
if (enemy.id === entityID) {
|
||||
this.remainingEnemies.splice(i, 1);
|
||||
Audio.playSound(TARGET_HIT_SOUND, {
|
||||
volume: 1.0,
|
||||
position: this.rootPosition
|
||||
});
|
||||
|
||||
// Update score
|
||||
this.setScore(this.score + POINTS_PER_KILL);
|
||||
print("SCORE: ", this.score);
|
||||
|
||||
this.checkWaveComplete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
onEnemyEscaped: function(entityID, position) {
|
||||
if (this.gameState !== GAME_STATES.PLAYING) {
|
||||
return;
|
||||
}
|
||||
|
||||
var enemiesEscaped = false;
|
||||
for (var i = this.remainingEnemies.length - 1; i >= 0; --i) {
|
||||
var enemy = this.remainingEnemies[i];
|
||||
if (enemy.id === entityID) {
|
||||
Entities.deleteEntity(enemy.id);
|
||||
this.remainingEnemies.splice(i, 1);
|
||||
this.setLivesLeft(this.livesLeft - 1);
|
||||
Audio.playSound(ESCAPE_SOUND, {
|
||||
volume: 1.0,
|
||||
position: this.rootPosition
|
||||
});
|
||||
enemiesEscaped = true;
|
||||
}
|
||||
}
|
||||
if (this.livesLeft <= 0) {
|
||||
this.endGame();
|
||||
} else if (enemiesEscaped) {
|
||||
this.checkWaveComplete();
|
||||
}
|
||||
},
|
||||
onEnemyHeartbeat: function(entityID, position) {
|
||||
for (var i = 0; i < this.remainingEnemies.length; i++) {
|
||||
var enemy = this.remainingEnemies[i];
|
||||
if (enemy.id === entityID) {
|
||||
enemy.lastHeartbeat = Date.now();
|
||||
enemy.lastKnownPosition = position;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// Created by Ryan Huffman on 1/10/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
/* globals TEMPLATES:true, SHORTBOW_ENTITIES, ShortbowGameManager */
|
||||
|
||||
(function() {
|
||||
Script.include('utils.js');
|
||||
Script.include('shortbow.js');
|
||||
Script.include('shortbowGameManager.js');
|
||||
|
||||
TEMPLATES = SHORTBOW_ENTITIES.Entities;
|
||||
|
||||
this.entityID = null;
|
||||
var gameManager = null;
|
||||
this.preload = function(entityID) {
|
||||
this.entityID = entityID;
|
||||
|
||||
var bowPositions = [];
|
||||
var spawnPositions = [];
|
||||
for (var i = 0; i < TEMPLATES.length; ++i) {
|
||||
var template = TEMPLATES[i];
|
||||
if (template.name === "SB.BowSpawn") {
|
||||
bowPositions.push(template.localPosition);
|
||||
} else if (template.name === "SB.EnemySpawn") {
|
||||
spawnPositions.push(template.localPosition);
|
||||
}
|
||||
}
|
||||
|
||||
gameManager = new ShortbowGameManager(this.entityID, bowPositions, spawnPositions);
|
||||
};
|
||||
this.unload = function() {
|
||||
if (gameManager) {
|
||||
gameManager.cleanup();
|
||||
gameManager = null;
|
||||
}
|
||||
};
|
||||
});
|
BIN
unpublishedScripts/marketplace/shortbow/sounds/escape.wav
Normal file
BIN
unpublishedScripts/marketplace/shortbow/sounds/escape.wav
Normal file
Binary file not shown.
BIN
unpublishedScripts/marketplace/shortbow/sounds/explosion.wav
Normal file
BIN
unpublishedScripts/marketplace/shortbow/sounds/explosion.wav
Normal file
Binary file not shown.
BIN
unpublishedScripts/marketplace/shortbow/sounds/fight.wav
Normal file
BIN
unpublishedScripts/marketplace/shortbow/sounds/fight.wav
Normal file
Binary file not shown.
BIN
unpublishedScripts/marketplace/shortbow/sounds/gameOn.wav
Normal file
BIN
unpublishedScripts/marketplace/shortbow/sounds/gameOn.wav
Normal file
Binary file not shown.
BIN
unpublishedScripts/marketplace/shortbow/sounds/gameOver.wav
Normal file
BIN
unpublishedScripts/marketplace/shortbow/sounds/gameOver.wav
Normal file
Binary file not shown.
Binary file not shown.
BIN
unpublishedScripts/marketplace/shortbow/sounds/spawn.wav
Normal file
BIN
unpublishedScripts/marketplace/shortbow/sounds/spawn.wav
Normal file
Binary file not shown.
BIN
unpublishedScripts/marketplace/shortbow/sounds/targetHit.wav
Normal file
BIN
unpublishedScripts/marketplace/shortbow/sounds/targetHit.wav
Normal file
Binary file not shown.
Binary file not shown.
BIN
unpublishedScripts/marketplace/shortbow/sounds/waveComplete.wav
Normal file
BIN
unpublishedScripts/marketplace/shortbow/sounds/waveComplete.wav
Normal file
Binary file not shown.
210
unpublishedScripts/marketplace/shortbow/spawnShortbow.js
Normal file
210
unpublishedScripts/marketplace/shortbow/spawnShortbow.js
Normal file
|
@ -0,0 +1,210 @@
|
|||
//
|
||||
// Created by Ryan Huffman on 1/10/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
/* globals utils, SHORTBOW_ENTITIES, TEMPLATES:true */
|
||||
|
||||
Script.include('utils.js');
|
||||
Script.include('shortbow.js');
|
||||
Script.include('shortbowGameManager.js');
|
||||
TEMPLATES = SHORTBOW_ENTITIES.Entities;
|
||||
|
||||
// Merge two objects into a new object. If a key name appears in both a and b,
|
||||
// the value in a will be used.
|
||||
//
|
||||
// @param {object} a
|
||||
// @param {object} b
|
||||
// @returns {object} The new object
|
||||
function mergeObjects(a, b) {
|
||||
var obj = {};
|
||||
var key;
|
||||
for (key in b) {
|
||||
obj[key] = b[key];
|
||||
}
|
||||
for (key in a) {
|
||||
obj[key] = a[key];
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Spawn an entity from a template.
|
||||
//
|
||||
// The overrides can be used to override or add properties in the template. For instance,
|
||||
// it's common to override the `position` property so that you can set the position
|
||||
// of the entity to be spawned.
|
||||
//
|
||||
// @param {string} templateName The name of the template to spawn
|
||||
// @param {object} overrides An object containing properties that will override
|
||||
// any properties set in the template.
|
||||
function spawnTemplate(templateName, overrides) {
|
||||
var template = getTemplate(templateName);
|
||||
if (template === null) {
|
||||
print("ERROR, unknown template name:", templateName);
|
||||
return null;
|
||||
}
|
||||
print("Spawning: ", templateName);
|
||||
var properties = mergeObjects(overrides, template);
|
||||
return Entities.addEntity(properties);
|
||||
}
|
||||
|
||||
function spawnTemplates(templateName, overrides) {
|
||||
var templates = getTemplates(templateName);
|
||||
if (template.length === 0) {
|
||||
print("ERROR, unknown template name:", templateName);
|
||||
return [];
|
||||
}
|
||||
|
||||
var spawnedEntities = [];
|
||||
for (var i = 0; i < templates.length; ++i) {
|
||||
print("Spawning: ", templateName);
|
||||
var properties = mergeObjects(overrides, templates[i]);
|
||||
spawnedEntities.push(Entities.addEntity(properties));
|
||||
}
|
||||
return spawnedEntities;
|
||||
}
|
||||
|
||||
// TEMPLATES contains a dictionary of different named entity templates. An entity
|
||||
// template is just a list of properties.
|
||||
//
|
||||
// @param name Name of the template to get
|
||||
// @return {object} The matching template, or null if not found
|
||||
function getTemplate(name) {
|
||||
for (var i = 0; i < TEMPLATES.length; ++i) {
|
||||
if (TEMPLATES[i].name === name) {
|
||||
return TEMPLATES[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function getTemplates(name) {
|
||||
var templates = [];
|
||||
for (var i = 0; i < TEMPLATES.length; ++i) {
|
||||
if (TEMPLATES[i].name === name) {
|
||||
templates.push(TEMPLATES[i]);
|
||||
}
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
|
||||
|
||||
// Cleanup Shortbow template data
|
||||
for (var i = 0; i < TEMPLATES.length; ++i) {
|
||||
var template = TEMPLATES[i];
|
||||
|
||||
// Fixup model url
|
||||
if (template.type === "Model") {
|
||||
var urlParts = template.modelURL.split("/");
|
||||
var filename = urlParts[urlParts.length - 1];
|
||||
var newURL = Script.resolvePath("models/" + filename);
|
||||
print("Updated url", template.modelURL, "to", newURL);
|
||||
template.modelURL = newURL;
|
||||
}
|
||||
}
|
||||
|
||||
var entityIDs = [];
|
||||
|
||||
var scoreboardID = null;
|
||||
var buttonID = null;
|
||||
var waveDisplayID = null;
|
||||
var scoreDisplayID = null;
|
||||
var highScoreDisplayID = null;
|
||||
var livesDisplayID = null;
|
||||
var platformID = null;
|
||||
function createLocalGame() {
|
||||
var rootPosition = utils.findSurfaceBelowPosition(MyAvatar.position);
|
||||
rootPosition.y += 6.11;
|
||||
|
||||
scoreboardID = spawnTemplate("SB.Scoreboard", {
|
||||
position: rootPosition
|
||||
});
|
||||
entityIDs.push(scoreboardID);
|
||||
|
||||
// Create start button
|
||||
buttonID = spawnTemplate("SB.StartButton", {
|
||||
parentID: scoreboardID,
|
||||
script: Script.resolvePath("startGameButtonClientEntity.js"),
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
wantsTrigger: true
|
||||
}
|
||||
})
|
||||
});
|
||||
entityIDs.push(buttonID);
|
||||
|
||||
|
||||
waveDisplayID = spawnTemplate("SB.DisplayWave", {
|
||||
parentID: scoreboardID,
|
||||
userData: JSON.stringify({
|
||||
displayType: "wave"
|
||||
})
|
||||
});
|
||||
entityIDs.push(waveDisplayID);
|
||||
|
||||
scoreDisplayID = spawnTemplate("SB.DisplayScore", {
|
||||
parentID: scoreboardID,
|
||||
userData: JSON.stringify({
|
||||
displayType: "score"
|
||||
})
|
||||
});
|
||||
entityIDs.push(scoreDisplayID);
|
||||
|
||||
livesDisplayID = spawnTemplate("SB.DisplayLives", {
|
||||
parentID: scoreboardID,
|
||||
userData: JSON.stringify({
|
||||
displayType: "lives"
|
||||
})
|
||||
});
|
||||
entityIDs.push(livesDisplayID);
|
||||
|
||||
highScoreDisplayID = spawnTemplate("SB.DisplayHighScore", {
|
||||
parentID: scoreboardID,
|
||||
userData: JSON.stringify({
|
||||
displayType: "highscore"
|
||||
})
|
||||
});
|
||||
entityIDs.push(highScoreDisplayID);
|
||||
|
||||
platformID = spawnTemplate("SB.Platform", {
|
||||
parentID: scoreboardID
|
||||
});
|
||||
entityIDs.push(platformID);
|
||||
|
||||
spawnTemplate("SB.GateCollider", {
|
||||
parentID: scoreboardID,
|
||||
visible: false
|
||||
});
|
||||
entityIDs.push(platformID);
|
||||
|
||||
Entities.editEntity(scoreboardID, {
|
||||
serverScripts: Script.resolvePath('shortbowServerEntity.js')
|
||||
});
|
||||
|
||||
spawnTemplates("SB.BowSpawn", {
|
||||
parentID: scoreboardID,
|
||||
visible: false
|
||||
});
|
||||
spawnTemplates("SB.EnemySpawn", {
|
||||
parentID: scoreboardID,
|
||||
visible: false
|
||||
});
|
||||
|
||||
var bowPositions = [];
|
||||
var spawnPositions = [];
|
||||
for (var i = 0; i < TEMPLATES.length; ++i) {
|
||||
var template = TEMPLATES[i];
|
||||
|
||||
if (template.name === "SB.BowSpawn") {
|
||||
bowPositions.push(Vec3.sum(rootPosition, template.localPosition));
|
||||
Vec3.print("Pushing bow position", Vec3.sum(rootPosition, template.localPosition));
|
||||
} else if (template.name === "SB.EnemySpawn") {
|
||||
spawnPositions.push(Vec3.sum(rootPosition, template.localPosition));
|
||||
Vec3.print("Pushing spawnposition", Vec3.sum(rootPosition, template.localPosition));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createLocalGame();
|
||||
Script.stop();
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Created by Ryan Huffman on 1/10/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
/* globals utils */
|
||||
|
||||
(function() {
|
||||
Script.include('utils.js');
|
||||
|
||||
function StartButton() {
|
||||
}
|
||||
StartButton.prototype = {
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
this.commChannel = "shortbow-" + Entities.getEntityProperties(entityID, 'parentID').parentID;
|
||||
Script.addEventHandler(entityID, "collisionWithEntity", this.onCollide.bind(this));
|
||||
},
|
||||
signalAC: function() {
|
||||
Messages.sendMessage(this.commChannel, JSON.stringify({
|
||||
type: 'start-game'
|
||||
}));
|
||||
},
|
||||
onCollide: function(entityA, entityB, collision) {
|
||||
var colliderName = Entities.getEntityProperties(entityB, 'name').name;
|
||||
|
||||
if (colliderName.indexOf("projectile") > -1) {
|
||||
this.signalAC();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
StartButton.prototype.startNearTrigger = StartButton.prototype.signalAC;
|
||||
StartButton.prototype.startFarTrigger = StartButton.prototype.signalAC;
|
||||
StartButton.prototype.clickDownOnEntity = StartButton.prototype.signalAC;
|
||||
|
||||
return new StartButton();
|
||||
});
|
57
unpublishedScripts/marketplace/shortbow/utils.js
Normal file
57
unpublishedScripts/marketplace/shortbow/utils.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// Created by Ryan Huffman on 1/10/2017
|
||||
// Copyright 2017 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
|
||||
//
|
||||
|
||||
/* globals utils:true */
|
||||
|
||||
if (!Function.prototype.bind) {
|
||||
Function.prototype.bind = function(oThis) {
|
||||
if (typeof this !== 'function') {
|
||||
// closest thing possible to the ECMAScript 5
|
||||
// internal IsCallable function
|
||||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
||||
}
|
||||
|
||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||
fToBind = this,
|
||||
NOP = function() {},
|
||||
fBound = function() {
|
||||
return fToBind.apply(this instanceof NOP
|
||||
? this
|
||||
: oThis,
|
||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
|
||||
if (this.prototype) {
|
||||
// Function.prototype doesn't have a prototype property
|
||||
NOP.prototype = this.prototype;
|
||||
}
|
||||
fBound.prototype = new NOP();
|
||||
|
||||
return fBound;
|
||||
};
|
||||
}
|
||||
|
||||
utils = {
|
||||
parseJSON: function(json) {
|
||||
try {
|
||||
return JSON.parse(json);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
findSurfaceBelowPosition: function(pos) {
|
||||
var result = Entities.findRayIntersection({
|
||||
origin: pos,
|
||||
direction: { x: 0.0, y: -1.0, z: 0.0 }
|
||||
}, true);
|
||||
if (result.intersects) {
|
||||
return result.intersection;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
};
|
Loading…
Reference in a new issue