overte-JulianGro/script-archive/vrShop/item/shopItemEntityScript.js
2016-04-26 11:18:22 -07:00

389 lines
No EOL
17 KiB
JavaScript

// shopItemEntityScript.js
//
// This script makes the shop items react properly to the grab (see shopItemGrab.js) and gives it the capability to interact with the shop environment (inspection entity and cart)
// The first time the item is grabbed a copy of itself is created on the shelf.
// If the item isn't held by the user it can be inInspect or inCart, otherwise it's destroyed
// The start and release grab methods handle the creation of the item copy, UI, inspection entity
// If the item is released into a valid zone, the doSomething() method of that zone is called and the item sends its ID
// Created by Alessandro Signa and Edgar Pironti on 01/13/2016
// 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
//
(function() {
var utilitiesScript = Script.resolvePath("../../libraries/utils.js");
var overlayManagerScript = Script.resolvePath("../../libraries/overlayManager.js");
var inspectEntityScript = Script.resolvePath("../inspect/shopInspectEntityScript.js");
Script.include(utilitiesScript);
Script.include(overlayManagerScript);
var RED_IMAGE_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/inspRED.png";
var GREEN_IMAGE_URL = "https://dl.dropboxusercontent.com/u/14127429/FBX/VRshop/inspGREEN.png";
var MIN_DIMENSION_THRESHOLD = null;
var MAX_DIMENSION_THRESHOLD = null;
var PENETRATION_THRESHOLD = 0.2;
var MAPPING_NAME = "controllerMapping_Inspection";
var SHOPPING_CART_NAME = "Shopping cart";
var _this;
var onShelf = true;
var inspecting = false;
var inCart = false;
var overlayInspectRed = true;
var zoneID = null;
var newPosition;
var originalDimensions = null;
var deltaLX = 0;
var deltaLY = 0;
var deltaRX = 0;
var deltaRY = 0;
var inspectingEntity = null;
var inspectPanel = null;
var background = null;
var textCart = null;
var cartID = null;
// this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
// our this object, so we can access it in cases where we're called without a this (like in the case of various global signals)
ItemEntity = function() {
_this = this;
};
function update(deltaTime) {
if(inspecting){
_this.orientationPositionUpdate();
}
};
ItemEntity.prototype = {
// preload() will be called when the entity has become visible (or known) to the interface
// it gives us a chance to set our local JavaScript object up. In this case it means:
// * remembering our entityID, so we can access it in cases where we're called without an entityID
// * connecting to the update signal so we can check our grabbed state
preload: function(entityID) {
this.entityID = entityID;
print("PRELOAD: " + Entities.getEntityProperties(this.entityID).name + " " + entityID + " at:");
Vec3.print(Entities.getEntityProperties(this.entityID).name, Entities.getEntityProperties(this.entityID).position);
Script.update.connect(update);
MIN_DIMENSION_THRESHOLD = Vec3.length(Entities.getEntityProperties(this.entityID).dimensions)/2;
MAX_DIMENSION_THRESHOLD = Vec3.length(Entities.getEntityProperties(this.entityID).dimensions)*2;
},
//create a rectangle red or green do guide the user in putting the item in the inspection area
createInspectOverlay: function (entityBindID) {
inspectPanel = new OverlayPanel({
anchorPositionBinding: { entity: entityBindID },
anchorRotationBinding: { entity: entityBindID },
isFacingAvatar: false
});
background = new Image3DOverlay({
url: RED_IMAGE_URL,
dimensions: {
x: 0.6,
y: 0.6,
},
isFacingAvatar: false,
alpha: 1,
ignoreRayIntersection: false,
offsetPosition: {
x: 0,
y: 0,
z: 0
},
emissive: true,
});
inspectPanel.addChild(background);
},
//add an overlay on the item grabbed by the customer to give him the feedback if the item is inside the bounding box of the cart
createCartOverlay: function (entityBindID) {
cartPanel = new OverlayPanel({
anchorPositionBinding: { entity: entityBindID },
offsetPosition: { x: 0, y: 0.2, z: 0.1 },
isFacingAvatar: true,
});
var entityProperties = Entities.getEntityProperties(entityBindID);
var userDataObj = JSON.parse(entityProperties.userData);
var availabilityNumber = userDataObj.infoKey.availability;
textCart = new Text3DOverlay({
text: availabilityNumber > 0 ? "Store the item!" : "Not available!",
isFacingAvatar: false,
alpha: 1.0,
ignoreRayIntersection: true,
dimensions: { x: 0, y: 0 },
backgroundColor: { red: 255, green: 255, blue: 255 },
color: { red: 0, green: 0, blue: 0 },
topMargin: 0.00625,
leftMargin: 0.00625,
bottomMargin: 0.1,
rightMargin: 0.00625,
lineHeight: 0.02,
alpha: 1,
backgroundAlpha: 0.3,
visible: false
});
cartPanel.addChild(textCart);
},
setCartOverlayVisible: function () {
textCart.visible = true;
},
setCartOverlayNotVisible: function () {
textCart.visible = false;
},
changeOverlayColor: function () {
if (overlayInspectRed) {
//print ("Change color of overlay to green");
overlayInspectRed = false;
background.url = GREEN_IMAGE_URL;
} else {
//print ("Change color of overlay to red");
overlayInspectRed = true;
background.url = RED_IMAGE_URL;
}
},
//What is done by this methos changes acoordingly to the previous state of the item - onShelf , inCart, inInspect
startNearGrab: function () {
//we have to distinguish if the user who is grabbing has a cart or not
//if he does it is a buyer, otherwise he probably want to do a review
var thisItemPosition = Entities.getEntityProperties(_this.entityID).position;
// if onShelf is true, this is the first grab
if (onShelf === true) {
var foundEntities = Entities.findEntities(thisItemPosition, 5);
foundEntities.forEach( function (foundEntityID) {
var entityName = Entities.getEntityProperties(foundEntityID).name;
if (entityName == SHOPPING_CART_NAME) {
var cartOwnerID = getEntityCustomData('ownerKey', foundEntityID, null).ownerID;
if (cartOwnerID == MyAvatar.sessionUUID) {
cartID = foundEntityID;
}
}
});
// Create a copy of this entity if it is the first grab
print("creating a copy of the grabbed dentity");
var entityProperties = Entities.getEntityProperties(_this.entityID);
var entityOnShelf = Entities.addEntity({
type: entityProperties.type,
name: entityProperties.name,
position: thisItemPosition,
dimensions: entityProperties.dimensions,
rotation: entityProperties.rotation,
collisionsWillMove: false,
ignoreForCollisions: true,
modelURL: entityProperties.modelURL,
shapeType: entityProperties.shapeType,
originalTextures: entityProperties.originalTextures,
script: entityProperties.script,
userData: entityProperties.userData
});
var tempUserDataObj = JSON.parse(entityProperties.userData);
var availabilityNumber = tempUserDataObj.infoKey.availability;
if (availabilityNumber > 0 && cartID) {
tempUserDataObj.infoKey.availability = tempUserDataObj.infoKey.availability - 1;
setEntityCustomData('infoKey', entityOnShelf, tempUserDataObj.infoKey);
}
setEntityCustomData('statusKey', _this.entityID, {
status: "inHand"
});
onShelf = false;
setEntityCustomData('ownerKey', _this.entityID, {
ownerID: MyAvatar.sessionUUID
});
originalDimensions = entityProperties.dimensions;
}
//if cartID is defined the user is a buyer
if (cartID) {
// Everytime we grab, we create the inspectEntity and the inspectAreaOverlay in front of the avatar
if(!inspecting) {
inspectingEntity = Entities.addEntity({
type: "Box",
name: "inspectionEntity",
dimensions: {x: 0.5, y: 0.5, z: 0.5},
collisionsWillMove: false,
ignoreForCollisions: false,
visible: false,
script: inspectEntityScript,
userData: JSON.stringify({
ownerKey: {
ownerID: MyAvatar.sessionUUID
},
itemKey: {
itemID: _this.entityID
},
grabbableKey: {
grabbable: false
}
})
});
}
Entities.editEntity(_this.entityID, { ignoreForCollisions: false });
_this.createInspectOverlay(inspectingEntity);
_this.createCartOverlay(_this.entityID);
if (inspecting === true) {
inspecting = false;
Entities.editEntity(_this.entityID, { dimensions: originalDimensions });
Controller.disableMapping(MAPPING_NAME);
setEntityCustomData('statusKey', _this.entityID, {
status: "inHand"
});
} else if (inCart === true) {
inCart = false;
Entities.editEntity(_this.entityID, { dimensions: originalDimensions });
setEntityCustomData('statusKey', _this.entityID, {
status: "inHand"
});
var dataJSON = {
id: _this.entityID
};
var dataArray = [JSON.stringify(dataJSON)];
Entities.callEntityMethod(zoneID, 'refreshCartContent', dataArray);
}
}
},
continueNearGrab: function () {
},
//Every time the item is released I have to check what's the role of the user and where the release happens
releaseGrab: function () {
//if cart ID is not defined destroy the item whatever the zone is because the user is a reviewer
if (!cartID) {
Entities.deleteEntity(this.entityID);
return;
}
Entities.editEntity(_this.entityID, { ignoreForCollisions: true });
// Destroy overlay
inspectPanel.destroy();
cartPanel.destroy();
inspectPanel = cartPanel = null;
if (zoneID !== null) {
var dataJSON = {
id: _this.entityID
};
var dataArray = [JSON.stringify(dataJSON)];
Entities.callEntityMethod(zoneID, 'doSomething', dataArray);
var statusObj = getEntityCustomData('statusKey', _this.entityID, null);
//There are two known zones where the relase can happen: inspecting area and cart
if (statusObj.status == "inInspect") {
inspecting = true;
var mapping = Controller.newMapping(MAPPING_NAME);
mapping.from(Controller.Standard.LX).to(function (value) {
deltaLX = value;
});
mapping.from(Controller.Standard.LY).to(function (value) {
deltaLY = value;
});
mapping.from(Controller.Standard.RX).to(function (value) {
deltaRX = value;
});
mapping.from(Controller.Standard.RY).to(function (value) {
deltaRY = value;
});
Controller.enableMapping(MAPPING_NAME);
} else if (statusObj.status == "inCart") {
Entities.deleteEntity(inspectingEntity);
inspectingEntity = null;
var entityProperties = Entities.getEntityProperties(this.entityID);
var userDataObj = JSON.parse(entityProperties.userData);
var availabilityNumber = userDataObj.infoKey.availability;
//if the item is no more available, destroy it
if (availabilityNumber == 0) {
Entities.deleteEntity(this.entityID);
}
print("inCart is TRUE");
inCart = true;
} else { // any other zone
//print("------------zoneID is something");
Entities.deleteEntity(inspectingEntity);
inspectingEntity = null;
}
} else { // ZoneID is null, released somewhere that is not a zone.
//print("------------zoneID is null");
Entities.deleteEntity(inspectingEntity);
inspectingEntity = null;
Entities.deleteEntity(this.entityID);
}
},
//Analysing the collisions we can define the value of zoneID
collisionWithEntity: function(myID, otherID, collisionInfo) {
var penetrationValue = Vec3.length(collisionInfo.penetration);
if (penetrationValue > PENETRATION_THRESHOLD && zoneID === null) {
zoneID = otherID;
print("Item IN: " + Entities.getEntityProperties(zoneID).name);
} else if (penetrationValue < PENETRATION_THRESHOLD && zoneID !== null && otherID == zoneID) {
print("Item OUT: " + Entities.getEntityProperties(zoneID).name);
zoneID = null;
}
},
//this method handles the rotation and scale of the item while in inspect and also guarantees to keep the item in the proper position. It's done every update
orientationPositionUpdate: function() {
//position
var inspectingEntityPosition = Entities.getEntityProperties(inspectingEntity).position; //at this time inspectingEntity is a valid entity
var inspectingEntityRotation = Entities.getEntityProperties(inspectingEntity).rotation;
newPosition = Vec3.sum(inspectingEntityPosition, Vec3.multiply(Quat.getFront(inspectingEntityRotation), -0.2)); //put the item near to the face of the user
Entities.editEntity(_this.entityID, { position: newPosition });
//orientation
var newRotation = Quat.multiply(Entities.getEntityProperties(_this.entityID).rotation, Quat.fromPitchYawRollDegrees(deltaRY*10, deltaRX*10, 0))
Entities.editEntity(_this.entityID, { rotation: newRotation });
//zoom
var oldDimension = Entities.getEntityProperties(_this.entityID).dimensions;
var scaleFactor = (deltaLY * 0.1) + 1;
if (!((Vec3.length(oldDimension) < MIN_DIMENSION_THRESHOLD && scaleFactor < 1) || (Vec3.length(oldDimension) > MAX_DIMENSION_THRESHOLD && scaleFactor > 1))) {
var newDimension = Vec3.multiply(oldDimension, scaleFactor);
Entities.editEntity(_this.entityID, { dimensions: newDimension });
}
},
unload: function (entityID) {
Script.update.disconnect(update);
}
};
// entity scripts always need to return a newly constructed object of our type
return new ItemEntity();
})