mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 20:35:17 +02:00
Merge pull request #9809 from Menithal/21201
WL#21201 Snap-together Magnetic blocks
This commit is contained in:
commit
6ded937b25
3 changed files with 223 additions and 0 deletions
BIN
scripts/system/assets/sounds/entitySnap.wav
Normal file
BIN
scripts/system/assets/sounds/entitySnap.wav
Normal file
Binary file not shown.
151
scripts/tutorials/entity_scripts/magneticBlock.js
Normal file
151
scripts/tutorials/entity_scripts/magneticBlock.js
Normal file
|
@ -0,0 +1,151 @@
|
|||
//
|
||||
// magneticBlock.js
|
||||
//
|
||||
// Created by Matti Lahtinen 4/3/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
|
||||
//
|
||||
// Makes the entity the script is bound to connect to nearby, similarly sized entities, like a magnet.
|
||||
|
||||
(function() {
|
||||
var SNAPSOUND_SOURCE = SoundCache.getSound(Script.resolvePath("../../system/assets/sounds/entitySnap.wav?xrs"));
|
||||
var RANGE_MULTIPLER = 1.5;
|
||||
var MAX_SCALE = 2;
|
||||
var MIN_SCALE = 0.5;
|
||||
|
||||
// Helper for detecting nearby objects near entityProperties, with the scale calculated by the dimensions of the object.
|
||||
function findEntitiesInRange(entityProperties) {
|
||||
var dimensions = entityProperties.dimensions;
|
||||
// Average of the dimensions instead of full value.
|
||||
return Entities.findEntities(entityProperties.position,
|
||||
((dimensions.x + dimensions.y + dimensions.z) / 3) * RANGE_MULTIPLER);
|
||||
}
|
||||
|
||||
function getNearestValidEntityProperties(releasedProperties) {
|
||||
var entities = findEntitiesInRange(releasedProperties);
|
||||
var nearestEntity = null;
|
||||
var nearest = Number.MAX_VALUE - 1;
|
||||
var releaseSize = Vec3.length(releasedProperties.dimensions);
|
||||
entities.forEach(function(entityId) {
|
||||
if (entityId !== releasedProperties.id) {
|
||||
var entity = Entities.getEntityProperties(entityId, ['position', 'rotation', 'dimensions']);
|
||||
var distance = Vec3.distance(releasedProperties.position, entity.position);
|
||||
var scale = releaseSize / Vec3.length(entity.dimensions);
|
||||
|
||||
if (distance < nearest && (scale >= MIN_SCALE && scale <= MAX_SCALE)) {
|
||||
nearestEntity = entity;
|
||||
nearest = distance;
|
||||
}
|
||||
}
|
||||
});
|
||||
return nearestEntity;
|
||||
}
|
||||
// Create the 'class'
|
||||
function MagneticBlock() {}
|
||||
// Bind pre-emptive events
|
||||
MagneticBlock.prototype = {
|
||||
/*
|
||||
When script is bound to an entity, preload is the first callback called with the entityID.
|
||||
It will behave as the constructor
|
||||
*/
|
||||
preload: function(id) {
|
||||
/*
|
||||
We will now override any existing userdata with the grabbable property.
|
||||
Only retrieving userData
|
||||
*/
|
||||
var entityProperties = Entities.getEntityProperties(id, ['userData']);
|
||||
var userData = {
|
||||
grabbableKey: {}
|
||||
};
|
||||
// Check if existing userData field exists.
|
||||
if (entityProperties.userData && entityProperties.userData.length > 0) {
|
||||
try {
|
||||
userData = JSON.parse(entityProperties.userData);
|
||||
if (!userData.grabbableKey) {
|
||||
userData.grabbableKey = {}; // If by random change there is no grabbableKey in the userData.
|
||||
}
|
||||
} catch (e) {
|
||||
// if user data is not valid json, we will simply overwrite it.
|
||||
}
|
||||
}
|
||||
// Object must be triggerable inorder to bind releaseGrabEvent
|
||||
userData.grabbableKey.grabbable = true;
|
||||
|
||||
// Apply the new properties to entity of id
|
||||
Entities.editEntity(id, {
|
||||
userData: JSON.stringify(userData)
|
||||
});
|
||||
Script.scriptEnding.connect(function() {
|
||||
Script.removeEventHandler(id, "releaseGrab", this.releaseGrab);
|
||||
});
|
||||
},
|
||||
releaseGrab: function(entityId) {
|
||||
// Release grab is called with entityId,
|
||||
var released = Entities.getEntityProperties(entityId, ["position", "rotation", "dimensions"]);
|
||||
var target = getNearestValidEntityProperties(released);
|
||||
if (target !== null) {
|
||||
// We found nearest, now lets do the snap calculations
|
||||
// Plays the snap sound between the two objects.
|
||||
Audio.playSound(SNAPSOUND_SOURCE, {
|
||||
volume: 1,
|
||||
position: Vec3.mix(target.position, released.position, 0.5)
|
||||
});
|
||||
// Check Nearest Axis
|
||||
var difference = Vec3.subtract(released.position, target.position);
|
||||
var relativeDifference = Vec3.multiplyQbyV(Quat.inverse(target.rotation), difference);
|
||||
|
||||
var abs = {
|
||||
x: Math.abs(relativeDifference.x),
|
||||
y: Math.abs(relativeDifference.y),
|
||||
z: Math.abs(relativeDifference.z)
|
||||
};
|
||||
// Check what value is greater. and lock down to that axis.
|
||||
var newRelative = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
if (abs.x >= abs.y && abs.x >= abs.z) {
|
||||
newRelative.x = target.dimensions.x / 2 + released.dimensions.x / 2;
|
||||
if (relativeDifference.x < 0) {
|
||||
newRelative.x = -newRelative.x;
|
||||
}
|
||||
} else if (abs.y >= abs.x && abs.y >= abs.z) {
|
||||
newRelative.y = target.dimensions.y / 2 + released.dimensions.y / 2;
|
||||
if (relativeDifference.y < 0) {
|
||||
newRelative.y = -newRelative.y;
|
||||
}
|
||||
} else if (abs.z >= abs.x && abs.z >= abs.y) {
|
||||
newRelative.z = target.dimensions.z / 2 + released.dimensions.z / 2;
|
||||
if (relativeDifference.z < 0) {
|
||||
newRelative.z = -newRelative.z;
|
||||
}
|
||||
}
|
||||
// Can be expanded upon to work in nearest 90 degree rotation as well, but was not in spec.
|
||||
var newPosition = Vec3.multiplyQbyV(target.rotation, newRelative);
|
||||
Entities.editEntity(entityId, {
|
||||
// Script relies on the registrationPoint being at the very center of the object. Thus override.
|
||||
registrationPoint: {
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
z: 0.5
|
||||
},
|
||||
rotation: target.rotation,
|
||||
position: Vec3.sum(target.position, newPosition)
|
||||
});
|
||||
// Script relies on the registrationPoint being at the very center of the object. Thus override.
|
||||
Entities.editEntity(target.id, {
|
||||
registrationPoint: {
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
z: 0.5
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
return new MagneticBlock();
|
||||
});
|
72
scripts/tutorials/makeBlocks.js
Normal file
72
scripts/tutorials/makeBlocks.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// makeBlocks.js
|
||||
//
|
||||
// Created by Matti Lahtinen 4/3/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
|
||||
//
|
||||
// Creates multiple "magnetic" blocks with random colors that users clones of and snap together.
|
||||
|
||||
|
||||
(function() {
|
||||
var MAX_RGB_COMPONENT_VALUE = 256 / 2; // Limit the values to half the maximum.
|
||||
var MIN_COLOR_VALUE = 127;
|
||||
var SIZE = 0.3;
|
||||
var LIFETIME = 600;
|
||||
var VERTICAL_OFFSET = -0.25;
|
||||
var ROWS = 3;
|
||||
var COLUMNS = 3;
|
||||
// Random Pastel Generator based on Piper's script
|
||||
function newColor() {
|
||||
return {
|
||||
red: randomPastelRGBComponent(),
|
||||
green: randomPastelRGBComponent(),
|
||||
blue: randomPastelRGBComponent()
|
||||
};
|
||||
}
|
||||
// Helper functions.
|
||||
function randomPastelRGBComponent() {
|
||||
return Math.floor(Math.random() * MAX_RGB_COMPONENT_VALUE) + MIN_COLOR_VALUE;
|
||||
}
|
||||
|
||||
var SCRIPT_URL = Script.resolvePath("./entity_scripts/magneticBlock.js");
|
||||
|
||||
var frontVector = Quat.getFront(MyAvatar.orientation);
|
||||
frontVector.y += VERTICAL_OFFSET;
|
||||
for (var x = 0; x < COLUMNS; x++) {
|
||||
for (var y = 0; y < ROWS; y++) {
|
||||
|
||||
var frontOffset = {
|
||||
x: 0,
|
||||
y: SIZE * y + SIZE,
|
||||
z: SIZE * x + SIZE
|
||||
};
|
||||
|
||||
Entities.addEntity({
|
||||
type: "Box",
|
||||
name: "MagneticBlock-" + y + '-' + x,
|
||||
dimensions: {
|
||||
x: SIZE,
|
||||
y: SIZE,
|
||||
z: SIZE
|
||||
},
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
cloneable: true,
|
||||
grabbable: true,
|
||||
cloneLifetime: LIFETIME,
|
||||
cloneLimit: 9999
|
||||
}
|
||||
}),
|
||||
position: Vec3.sum(MyAvatar.position, Vec3.sum(frontOffset, frontVector)),
|
||||
color: newColor(),
|
||||
script: SCRIPT_URL
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Script.stop();
|
||||
})();
|
Loading…
Reference in a new issue