(function(){ this.FIRST_TILE = null; // Global position of the first tile (1a) this.TILE_SIZE = null; // Size of one tile this.wantDebug = false; this.active = false; this.entityID = null; this.properties = null; this.boardID = null; this.boardUserData = null; this.sound = null; this.startingTile = null; this.pieces = new Array(); // All callbacks start by updating the properties this.updateProperties = function(entityID) { // Piece ID if (this.entityID === null) { this.entityID = entityID; } // Piece Properties this.properties = Entities.getEntityProperties(this.entityID); // Board ID if (this.boardID === null) { // Read user data string and update boardID var userData = JSON.parse(this.properties.userData); this.boardID = userData.boardID; } // Board User Data this.updateUserData(); } // Get an entity's user data this.getEntityUserData = function(entityID) { var properties = Entities.getEntityProperties(entityID); if (properties && properties.userData){ return JSON.parse(properties.userData); } else { print("No user data found."); return null; } } // Updates user data related objects this.updateUserData = function() { // Get board's user data if (this.boardID !== null) { this.boardUserData = this.getEntityUserData(this.boardID); if (!(this.boardUserData && this.boardUserData.firstTile && this.boardUserData.tileSize)) { print("Incomplete boardUserData " + this.boardID); } else { this.FIRST_TILE = this.boardUserData.firstTile; this.TILE_SIZE = this.boardUserData.tileSize; this.active = true; } } else { print("Missing boardID:" + JSON.stringify(this.boardID)); } } // Returns whether pos is inside the grid or not this.isOutsideGrid = function(pos) { return !(pos.i >= 0 && pos.j >= 0 && pos.i < 8 && pos.j < 8); } // Returns the tile coordinate this.getIndexPosition = function(position) { var halfTile = this.TILE_SIZE / 2.0; var corner = Vec3.sum(this.FIRST_TILE, { x: -halfTile, y: 0.0, z: -halfTile }); var relative = Vec3.subtract(position, corner); return { i: Math.floor(relative.x / this.TILE_SIZE), j: Math.floor(relative.z / this.TILE_SIZE) } } // Returns the world position this.getAbsolutePosition = function(pos, halfHeight) { var relative = { x: pos.i * this.TILE_SIZE, y: halfHeight, z: pos.j * this.TILE_SIZE } return Vec3.sum(this.FIRST_TILE, relative); } // Pr, Vr are respectively the Ray's Point of origin and Vector director // Pp, Np are respectively the Plane's Point of origin and Normal vector this.rayPlaneIntersection = function(Pr, Vr, Pp, Np) { var d = -Vec3.dot(Pp, Np); var t = -(Vec3.dot(Pr, Np) + d) / Vec3.dot(Vr, Np); return Vec3.sum(Pr, Vec3.multiply(t, Vr)); } // Download sound if needed this.maybeDownloadSound = function() { if (this.sound === null) { this.sound = SoundCache.getSound("http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav"); } } // Play drop sound this.playSound = function() { if (this.sound && this.sound.downloaded) { Audio.playSound(this.sound, { position: this.properties.position }); } } // updates the piece position based on mouse input this.updatePosition = function(mouseEvent) { var pickRay = Camera.computePickRay(mouseEvent.x, mouseEvent.y) var upVector = { x: 0, y: 1, z: 0 }; var intersection = this.rayPlaneIntersection(pickRay.origin, pickRay.direction, this.properties.position, upVector); // if piece outside grid then send it back to the starting tile if (this.isOutsideGrid(this.getIndexPosition(intersection))) { intersection = this.getAbsolutePosition(this.startingTile, this.properties.dimensions.y / 2.0); } Entities.editEntity(this.entityID, { position: intersection }); } // Snap piece to the center of the tile it is on this.snapToGrid = function() { var pos = this.getIndexPosition(this.properties.position); var finalPos = this.getAbsolutePosition((this.isOutsideGrid(pos)) ? this.startingTile : pos, this.properties.dimensions.y / 2.0); Entities.editEntity(this.entityID, { position: finalPos }); } this.moveDeadPiece = function() { var myPos = this.getIndexPosition(this.properties.position); var others = Entities.findEntities(this.properties.position, this.properties.dimensions.y); for (var i = 0; i < others.length; i++) { var pieceID = others[i]; if (pieceID != this.entityID) { var properties = Entities.getEntityProperties(pieceID); var isWhite = properties.modelURL.search("White") !== -1; var type = (properties.modelURL.search("King") !== -1) ? 4 : (properties.modelURL.search("Queen") !== -1) ? 3 : (properties.modelURL.search("Rook") !== -1) ? 2 : (properties.modelURL.search("Knight") !== -1) ? 1 : (properties.modelURL.search("Bishop") !== -1) ? 0 : (properties.modelURL.search("Pawn") !== -1) ? -1 : -2; var piecePos = this.getIndexPosition(properties.position); if (myPos.i === piecePos.i && myPos.j === piecePos.j && type !== -2) { var position = this.getAbsolutePosition((isWhite) ? { i: type, j: -1 } : { i: 7 - type, j: 8 }, properties.dimensions.y / 2.0); Entities.editEntity(pieceID, { position: position }); break; } } } } this.grab = function(mouseEvent) { if (this.active) { this.startingTile = this.getIndexPosition(this.properties.position); this.updatePosition(mouseEvent); } } this.move = function(mouseEvent) { if (this.active) { this.updatePosition(mouseEvent); } } this.release = function(mouseEvent) { if (this.active) { this.updatePosition(mouseEvent); this.snapToGrid(); this.moveDeadPiece(); this.playSound(); } } this.preload = function(entityID) { this.updateProperties(entityID); // All callbacks start by updating the properties this.maybeDownloadSound(); } this.clickDownOnEntity = function(entityID, mouseEvent) { this.preload(entityID); // TODO : remove this.updateProperties(entityID); // All callbacks start by updating the properties this.grab(mouseEvent); }; this.holdingClickOnEntity = function(entityID, mouseEvent) { this.updateProperties(entityID); // All callbacks start by updating the properties this.move(mouseEvent); }; this.clickReleaseOnEntity = function(entityID, mouseEvent) { this.updateProperties(entityID); // All callbacks start by updating the properties this.release(mouseEvent); }; })