overte-lubosz/script-archive/vrShop/cart/shopCartEntityScript.js
2016-04-26 11:18:22 -07:00

324 lines
No EOL
14 KiB
JavaScript

// shopCartEntityScript.js
//
// This script makes the cart follow the avatar who picks it and manage interations with items (store and delete them) and with cash register (send the item prices)
// 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");
Script.include(utilitiesScript);
Script.include(overlayManagerScript);
var COMFORT_ARM_LENGTH = 0.5;
var CART_REGISTER_CHANNEL = "Hifi-vrShop-Register";
var PENETRATION_THRESHOLD = 0.2;
var _this;
var cartIsMine = false;
var originalY = 0;
var itemsID = [];
var scaleFactor = 0.7; //TODO: The scale factor will dipend on the number of items in the cart. We would resize even the items already present.
var cartTargetPosition;
var singlePrices = [];
var singlePriceTagsAreShowing = false;
var collidedItemID = 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)
ShopCart = function() {
_this = this;
};
function update(deltaTime) {
_this.followAvatar();
if (Controller.getValue(Controller.Standard.RightPrimaryThumb)) {
_this.resetCart();
_this.computeAndSendTotalPrice();
}
};
function receivingMessage(channel, message, senderID) {
if (senderID === MyAvatar.sessionUUID && channel == CART_REGISTER_CHANNEL) {
var messageObj = JSON.parse(message);
if (messageObj.senderEntity != _this.entityID) {
print("--------------- cart received message");
//Receiving this message means that the register wants the total price
_this.computeAndSendTotalPrice();
}
}
};
ShopCart.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;
//get the owner ID from user data and compare to the mine
//so the update will be connected just for the owner
var ownerObj = getEntityCustomData('ownerKey', this.entityID, null);
if (ownerObj.ownerID === MyAvatar.sessionUUID) {
cartIsMine = true;
cartTargetPosition = Entities.getEntityProperties(_this.entityID).position; //useful if the entity script is assigned manually
Script.update.connect(update);
Messages.subscribe(CART_REGISTER_CHANNEL);
Messages.messageReceived.connect(receivingMessage);
}
},
//update cart's target position. It will be at the right of the avatar as long as he moves
followAvatar: function() {
if (Vec3.length(MyAvatar.getVelocity()) > 0.1) {
var radius = (Entities.getEntityProperties(_this.entityID).dimensions.x) / 2 + COMFORT_ARM_LENGTH;
var properY = MyAvatar.position.y + ((MyAvatar.getHeadPosition().y - MyAvatar.position.y) / 2);
var targetPositionPrecomputing = {x: MyAvatar.position.x, y: properY, z: MyAvatar.position.z};
cartTargetPosition = Vec3.sum(targetPositionPrecomputing, Vec3.multiply(Quat.getRight(MyAvatar.orientation), radius));
}
var cartPosition = Entities.getEntityProperties(_this.entityID).position;
var positionDifference = Vec3.subtract(cartTargetPosition, cartPosition);
if (Vec3.length(positionDifference) > 0.1) {
//give to the cart the proper velocity and make it ignore for collision
Entities.editEntity(_this.entityID, { velocity: positionDifference });
Entities.editEntity(_this.entityID, { ignoreForCollisions: true });
if (collidedItemID != null) {
Entities.callEntityMethod(collidedItemID, 'setCartOverlayNotVisible', null);
collidedItemID = null;
}
} else if (Vec3.length(positionDifference) > 0.01) {
//give to the cart the proper velocity and make it NOT ignore for collision
Entities.editEntity(_this.entityID, { velocity: positionDifference });
Entities.editEntity(_this.entityID, { ignoreForCollisions: false });
} else if (Vec3.length(positionDifference) > 0) {
//set the position to be at the right of MyAvatar and make it NOT ignore for collision
Entities.editEntity(_this.entityID, { position: cartTargetPosition });
positionDifference = Vec3.subtract(cartTargetPosition, cartPosition);
Entities.editEntity(_this.entityID, { velocity: positionDifference });
Entities.editEntity(_this.entityID, { ignoreForCollisions: false });
}
},
// delete all items stored into the cart
resetCart: function () {
//print("RESET CART - USER DATA: " + Entities.getEntityProperties(_this.entityID).userData);
if (itemsID.length != 0) {
if (singlePriceTagsAreShowing) {
_this.singlePriceOff();
}
for (var i=0; i < itemsID.length; i++) {
Entities.deleteEntity(itemsID[i]);
}
// Clear the userData field for the cart
Entities.editEntity(this.entityID, { userData: ""});
setEntityCustomData('ownerKey', this.entityID, {
ownerID: MyAvatar.sessionUUID
});
setEntityCustomData('grabbableKey', this.entityID, {
grabbable: false
});
itemsID = [];
}
},
//delete the item pointed by dataArray (data.id) from the cart because it's been grabbed from there
refreshCartContent: function (entityID, dataArray) {
var data = JSON.parse(dataArray[0]);
for (var i=0; i < itemsID.length; i++) {
if(itemsID[i] == data.id) {
itemsID.splice(i, 1);
//if the price tags are showing we have to remove also the proper tag
if (singlePriceTagsAreShowing) {
singlePrices[i].destroy();
singlePrices.splice(i, 1);
}
}
}
_this.computeAndSendTotalPrice();
},
//show the prices on each item into the cart
singlePriceOn: function () {
//create an array of text3D which follows the structure of the itemsID array. Each text3D is like the 'Store the item!' one
var i = 0;
itemsID.forEach( function(itemID) {
singlePrices[i] = new OverlayPanel({
anchorPositionBinding: { entity: itemID },
offsetPosition: { x: 0, y: 0.15, z: 0 },
isFacingAvatar: true,
});
var textPrice = new Text3DOverlay({
text: "" + getEntityCustomData('infoKey', itemID, null).price + " $",
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: true
});
singlePrices[i].addChild(textPrice);
i++;
});
singlePriceTagsAreShowing = true;
},
singlePriceOff: function () {
//destroy or make invisible the text3D, or both
singlePrices.forEach(function(panel) {
panel.destroy();
});
singlePrices = [];
singlePriceTagsAreShowing = false;
},
//Send to the register the total price for all the items in the cart
computeAndSendTotalPrice: function () {
var totalPrice = 0;
itemsID.forEach( function(itemID) {
var infoObj = getEntityCustomData('infoKey', itemID, null);
if(infoObj != null) {
totalPrice += infoObj.price;
}
});
var messageObj = {senderEntity: _this.entityID, totalPrice: totalPrice};
Messages.sendMessage(CART_REGISTER_CHANNEL, JSON.stringify(messageObj));
},
//dataArray stores the ID of the item which has to be stored into the cart
//this entity method is invoked by shopItemEntityScript.js
doSomething: function (entityID, dataArray) {
collidedItemID = null;
var data = JSON.parse(dataArray[0]);
var itemOwnerObj = getEntityCustomData('ownerKey', data.id, null);
var cartOwnerObj = getEntityCustomData('ownerKey', this.entityID, null);
if (cartOwnerObj == null) {
//print("The cart doesn't have a owner.");
Entities.deleteEntity(data.id);
}
if (itemOwnerObj.ownerID === cartOwnerObj.ownerID) {
// TODO if itemsQuantity == fullCart resize all the items present in the cart and change the scaleFactor for this and next insert
print("Going to put item in the cart!");
var itemsQuantity = itemsID.length;
itemsID[itemsQuantity] = data.id;
var oldDimension = Entities.getEntityProperties(data.id).dimensions;
Entities.editEntity(data.id, { dimensions: Vec3.multiply(oldDimension, scaleFactor) });
Entities.editEntity(data.id, { velocity: {x: 0.0, y: 0.0, z: 0.0} });
// parent item to the cart
Entities.editEntity(data.id, { parentID: this.entityID });
itemsQuantity = itemsID.length;
setEntityCustomData('statusKey', data.id, {
status: "inCart"
});
_this.computeAndSendTotalPrice();
//if the single price tags are showing we have to put a tag also in the new item
if (singlePriceTagsAreShowing) {
singlePrices[itemsQuantity-1] = new OverlayPanel({
anchorPositionBinding: { entity: data.id },
offsetPosition: { x: 0, y: 0.15, z: 0 },
isFacingAvatar: true,
});
var textPrice = new Text3DOverlay({
text: "" + getEntityCustomData('infoKey', data.id, null).price + " $",
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: true
});
singlePrices[itemsQuantity-1].addChild(textPrice);
}
} else {
print("Not your cart!");
Entities.deleteEntity(data.id);
}
},
//detect when the item enters or leave the cart while it's grabbed
collisionWithEntity: function(myID, otherID, collisionInfo) {
var penetrationValue = Vec3.length(collisionInfo.penetration);
var cartOwnerObj = getEntityCustomData('ownerKey', myID, null);
var itemOwnerObj = getEntityCustomData('ownerKey', otherID, null);
if (penetrationValue > PENETRATION_THRESHOLD && collidedItemID === null) {
if (itemOwnerObj != null && itemOwnerObj.ownerID === cartOwnerObj.ownerID) {
Entities.callEntityMethod(otherID, 'setCartOverlayVisible', null);
collidedItemID = otherID;
}
} else if (penetrationValue < PENETRATION_THRESHOLD && collidedItemID !== null) {
if (itemOwnerObj != null && itemOwnerObj.ownerID === cartOwnerObj.ownerID) {
Entities.callEntityMethod(otherID, 'setCartOverlayNotVisible', null);
collidedItemID = null;
}
}
},
unload: function (entityID) {
print("UNLOAD CART");
if(cartIsMine){
Script.update.disconnect(update);
_this.resetCart(); //useful if the script is reloaded manually
//Entities.deleteEntity(_this.entityID); //comment for manual reload
Messages.unsubscribe(CART_REGISTER_CHANNEL);
Messages.messageReceived.disconnect(receivingMessage);
}
}
};
// entity scripts always need to return a newly constructed object of our type
return new ShopCart();
})