overte-JulianGro/scripts/developer/tests/dynamics/dynamicsTests.js
2017-04-30 12:23:34 -07:00

759 lines
28 KiB
JavaScript

//
// dynamicsTests.js
// scripts/developer/tests/dynamics/
//
// Created by Seth Alves 2017-4-30
// 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
//
"use strict";
/* global Entities, Script, Tablet, MyAvatar, Vec3 */
(function() { // BEGIN LOCAL_SCOPE
var DYNAMICS_TESTS_URL = Script.resolvePath("dynamics-tests.html");
var DEFAULT_LIFETIME = 120; // seconds
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
var button = tablet.addButton({
icon: Script.resolvePath("dynamicsTests.svg"),
text: "Dynamics",
sortOrder: 15
});
function coneTwistAndSpringLeverTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: -0.5, z: -2}));
var lifetime = params.lifetime;
var baseID = Entities.addEntity({
name: "cone-twist test -- base",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: 0.5, y: 0.2, z: 0.5 },
position: Vec3.sum(pos, { x: 0, y: 0, z:0 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
var leverID = Entities.addEntity({
name: "cone-twist test -- lever",
type: "Box",
color: { blue: 128, green: 100, red: 200 },
dimensions: { x: 0.05, y: 1, z: 0.05 },
position: Vec3.sum(pos, { x: 0, y: 0.7, z:0 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addEntity({
name: "cone-twist test -- handle",
type: "Box",
color: { blue: 30, green: 100, red: 200 },
dimensions: { x: 0.1, y: 0.08, z: 0.08 },
position: Vec3.sum(pos, { x: 0, y: 0.7 + 0.5, z:0 }),
dynamic: false,
collisionless: true,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
parentID: leverID,
userData: "{ \"grabbableKey\": { \"grabbable\": false } }"
});
Entities.addAction("cone-twist", baseID, {
pivot: { x: 0, y: 0.2, z: 0 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: leverID,
otherPivot: { x: 0, y: -0.55, z: 0 },
otherAxis: { x: 0, y: 1, z: 0 },
swingSpan1: Math.PI / 4,
swingSpan2: Math.PI / 4,
twistSpan: Math.PI / 2,
tag: "cone-twist test"
});
Entities.addAction("spring", leverID, {
targetRotation: { x: 0, y: 0, z: 0, w: 1 },
angularTimeScale: 0.2,
tag: "cone-twist test spring"
});
Entities.editEntity(baseID, { gravity: { x: 0, y: -5, z: 0 } });
}
function doorVSWorldTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var doorID = Entities.addEntity({
name: "door test",
type: "Box",
color: { blue: 128, green: 20, red: 20 },
dimensions: { x: 1.0, y: 2, z: 0.1 },
position: pos,
dynamic: true,
collisionless: false,
lifetime: lifetime,
gravity: { x: 0, y: 0, z: 0 },
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", doorID, {
pivot: { x: -0.5, y: 0, z: 0 },
axis: { x: 0, y: 1, z: 0 },
low: 0,
high: Math.PI,
tag: "door hinge test"
});
}
function hingeChainTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var offset = 0.28;
var prevEntityID = null;
for (var i = 0; i < 5; i++) {
var newID = Entities.addEntity({
name: "hinge test " + i,
type: "Box",
color: { blue: 128, green: 40 * i, red: 20 },
dimensions: { x: 0.2, y: 0.2, z: 0.1 },
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
dynamic: true,
collisionless: false,
lifetime: lifetime,
gravity: { x: 0, y: 0, z: 0 },
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
if (prevEntityID) {
Entities.addAction("hinge", prevEntityID, {
pivot: { x: 0, y: offset / 2, z: 0 },
axis: { x: 1, y: 0, z: 0 },
otherEntityID: newID,
otherPivot: { x: 0, y: -offset / 2, z: 0 },
otherAxis: { x: 1, y: 0, z: 0 },
tag: "A/B hinge test " + i
});
}
prevEntityID = newID;
}
}
function sliderVSWorldTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var sliderEntityID = Entities.addEntity({
name: "slider test",
type: "Box",
color: { blue: 128, green: 20, red: 20 },
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
position: pos,
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("slider", sliderEntityID, {
point: { x: -0.5, y: 0, z: 0 },
axis: { x: 0, y: 1, z: 0 },
linearLow: 0,
linearHigh: 0.6,
tag: "slider test"
});
}
function sliderChainTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var offset = 0.28;
var prevEntityID = null;
for (var i = 0; i < 7; i++) {
var newID = Entities.addEntity({
name: "hinge test " + i,
type: "Box",
color: { blue: 128, green: 40 * i, red: 20 },
dimensions: { x: 0.2, y: 0.1, z: 0.2 },
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
if (prevEntityID) {
Entities.addAction("slider", prevEntityID, {
point: { x: 0, y: 0, z: 0 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: newID,
otherPoint: { x: 0, y: -offset / 2, z: 0 },
otherAxis: { x: 0, y: 1, z: 0 },
linearLow: 0,
linearHigh: 0.6,
tag: "A/B slider test " + i
});
}
prevEntityID = newID;
}
}
function ballSocketBetweenTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var offset = 0.2;
var diameter = offset - 0.01;
var prevEntityID = null;
for (var i = 0; i < 7; i++) {
var newID = Entities.addEntity({
name: "ball and socket test " + i,
type: "Sphere",
color: { blue: 128, green: 40 * i, red: 20 },
dimensions: { x: diameter, y: diameter, z: diameter },
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
dynamic: true,
collisionless: false,
lifetime: lifetime,
gravity: { x: 0, y: 0, z: 0 },
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
if (prevEntityID) {
Entities.addAction("ball-socket", prevEntityID, {
pivot: { x: 0, y: offset / 2, z: 0 },
otherEntityID: newID,
otherPivot: { x: 0, y: -offset / 2, z: 0 },
tag: "A/B ball-and-socket test " + i
});
}
prevEntityID = newID;
}
}
function ballSocketCoincidentTest(params) {
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
var lifetime = params.lifetime;
var offset = 0.2;
var diameter = offset - 0.01;
var prevEntityID = null;
for (var i = 0; i < 7; i++) {
var newID = Entities.addEntity({
name: "ball and socket test " + i,
type: "Sphere",
color: { blue: 128, green: 40 * i, red: 20 },
dimensions: { x: diameter, y: diameter, z: diameter },
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
dynamic: true,
collisionless: false,
lifetime: lifetime,
gravity: { x: 0, y: 0, z: 0 },
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
if (prevEntityID) {
Entities.addAction("ball-socket", prevEntityID, {
pivot: { x: 0, y: 0, z: 0 },
otherEntityID: newID,
otherPivot: { x: 0, y: offset, z: 0 },
tag: "A/B ball-and-socket test " + i
});
}
prevEntityID = newID;
}
}
function ragdollTest(params) {
var scale = 1.6;
var lifetime = 120;
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 1.0, z: -2}));
var neckLength = scale * 0.05;
var shoulderGap = scale * 0.1;
var elbowGap = scale * 0.06;
var hipGap = scale * 0.07;
var kneeGap = scale * 0.08;
var ankleGap = scale * 0.06;
var ankleMin = 0;
var ankleMax = Math.PI / 4;
var headSize = scale * 0.2;
var bodyHeight = scale * 0.4;
var bodyWidth = scale * 0.3;
var bodyDepth = scale * 0.2;
var upperArmThickness = scale * 0.05;
var upperArmLength = scale * 0.2;
var lowerArmThickness = scale * 0.05;
var lowerArmLength = scale * 0.2;
var legLength = scale * 0.3;
var legThickness = scale * 0.08;
var shinLength = scale * 0.2;
var shinThickness = scale * 0.06;
var footLength = scale * 0.2;
var footThickness = scale * 0.03;
var footWidth = scale * 0.08;
//
// body
//
var bodyID = Entities.addEntity({
name: "ragdoll body",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: bodyDepth, y: bodyHeight, z: bodyWidth },
position: Vec3.sum(pos, { x: 0, y: scale * 0.0, z:0 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
//
// head
//
var headID = Entities.addEntity({
name: "ragdoll head",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: headSize, y: headSize, z: headSize },
position: Vec3.sum(pos, { x: 0, y: bodyHeight / 2 + headSize / 2 + neckLength, z:0 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0.5, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("spring", headID, {
targetRotation: { x: 0, y: 0, z: 0, w: 1 },
angularTimeScale: 2.0,
otherID: bodyID,
tag: "cone-twist test spring"
});
var noseID = Entities.addEntity({
name: "ragdoll nose",
type: "Box",
color: { blue: 128, green: 100, red: 100 },
dimensions: { x: headSize / 5, y: headSize / 5, z: headSize / 5 },
localPosition: { x: headSize / 2 + headSize / 10, y: 0, z: 0 },
dynamic: false,
collisionless: true,
lifetime: lifetime,
parentID: headID,
userData: "{ \"grabbableKey\": { \"grabbable\": false } }"
});
Entities.addAction("cone-twist", headID, {
pivot: { x: 0, y: -headSize / 2 - neckLength / 2, z: 0 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: bodyID,
otherPivot: { x: 0, y: bodyHeight / 2 + neckLength / 2, z: 0 },
otherAxis: { x: 0, y: 1, z: 0 },
swingSpan1: Math.PI / 4,
swingSpan2: Math.PI / 4,
twistSpan: Math.PI / 2,
tag: "ragdoll neck joint"
});
//
// right upper arm
//
var rightUpperArmID = Entities.addEntity({
name: "ragdoll right arm",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: upperArmThickness, y: upperArmThickness, z: upperArmLength },
position: Vec3.sum(pos, { x: 0,
y: bodyHeight / 2 + upperArmThickness / 2,
z: bodyWidth / 2 + shoulderGap + upperArmLength / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("cone-twist", bodyID, {
pivot: { x: 0, y: bodyHeight / 2 + upperArmThickness / 2, z: bodyWidth / 2 + shoulderGap / 2 },
axis: { x: 0, y: 0, z: 1 },
otherEntityID: rightUpperArmID,
otherPivot: { x: 0, y: 0, z: -upperArmLength / 2 - shoulderGap / 2 },
otherAxis: { x: 0, y: 0, z: 1 },
swingSpan1: Math.PI / 2,
swingSpan2: Math.PI / 2,
twistSpan: 0,
tag: "ragdoll right shoulder joint"
});
//
// left upper arm
//
var leftUpperArmID = Entities.addEntity({
name: "ragdoll left arm",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: upperArmThickness, y: upperArmThickness, z: upperArmLength },
position: Vec3.sum(pos, { x: 0,
y: bodyHeight / 2 + upperArmThickness / 2,
z: -bodyWidth / 2 - shoulderGap - upperArmLength / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("cone-twist", bodyID, {
pivot: { x: 0, y: bodyHeight / 2 + upperArmThickness / 2, z: -bodyWidth / 2 - shoulderGap / 2 },
axis: { x: 0, y: 0, z: -1 },
otherEntityID: leftUpperArmID,
otherPivot: { x: 0, y: 0, z: upperArmLength / 2 + shoulderGap / 2 },
otherAxis: { x: 0, y: 0, z: -1 },
swingSpan1: Math.PI / 2,
swingSpan2: Math.PI / 2,
twistSpan: 0,
tag: "ragdoll left shoulder joint"
});
//
// right lower arm
//
var rightLowerArmID = Entities.addEntity({
name: "ragdoll right lower arm",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: lowerArmThickness, y: lowerArmThickness, z: lowerArmLength },
position: Vec3.sum(pos, { x: 0,
y: bodyHeight / 2 - upperArmThickness / 2,
z: bodyWidth / 2 + shoulderGap + upperArmLength + elbowGap + lowerArmLength / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -1, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", rightLowerArmID, {
pivot: { x: 0, y: 0, z: -lowerArmLength / 2 - elbowGap / 2 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: rightUpperArmID,
otherPivot: { x: 0, y: 0, z: upperArmLength / 2 + elbowGap / 2 },
otherAxis: { x: 0, y: 1, z: 0 },
low: Math.PI / -2,
high: 0,
tag: "ragdoll right elbow joint"
});
//
// left lower arm
//
var leftLowerArmID = Entities.addEntity({
name: "ragdoll left lower arm",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: lowerArmThickness, y: lowerArmThickness, z: lowerArmLength },
position: Vec3.sum(pos, { x: 0,
y: bodyHeight / 2 - upperArmThickness / 2,
z: -bodyWidth / 2 - shoulderGap - upperArmLength - elbowGap - lowerArmLength / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -1, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", leftLowerArmID, {
pivot: { x: 0, y: 0, z: lowerArmLength / 2 + elbowGap / 2 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: leftUpperArmID,
otherPivot: { x: 0, y: 0, z: -upperArmLength / 2 - elbowGap / 2 },
otherAxis: { x: 0, y: 1, z: 0 },
low: 0,
high: Math.PI / 2,
tag: "ragdoll left elbow joint"
});
//
// right leg
//
var rightLegID = Entities.addEntity({
name: "ragdoll right arm",
type: "Box",
color: { blue: 20, green: 200, red: 20 },
dimensions: { x: legThickness, y: legLength, z: legThickness },
position: Vec3.sum(pos, { x: 0, y: -bodyHeight / 2 - hipGap - legLength / 2, z: bodyWidth / 2 - legThickness / 2 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("cone-twist", rightLegID, {
pivot: { x: 0, y: legLength / 2 + hipGap / 2, z: 0 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: bodyID,
otherPivot: { x: 0, y: -bodyHeight / 2 - hipGap / 2, z: bodyWidth / 2 - legThickness / 2 },
otherAxis: Vec3.normalize({ x: -1, y: 1, z: 0 }),
swingSpan1: Math.PI / 4,
swingSpan2: Math.PI / 4,
twistSpan: 0,
tag: "ragdoll right hip joint"
});
//
// left leg
//
var leftLegID = Entities.addEntity({
name: "ragdoll left arm",
type: "Box",
color: { blue: 20, green: 200, red: 20 },
dimensions: { x: legThickness, y: legLength, z: legThickness },
position: Vec3.sum(pos, { x: 0, y: -bodyHeight / 2 - hipGap - legLength / 2, z: -bodyWidth / 2 + legThickness / 2 }),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: 0, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("cone-twist", leftLegID, {
pivot: { x: 0, y: legLength / 2 + hipGap / 2, z: 0 },
axis: { x: 0, y: 1, z: 0 },
otherEntityID: bodyID,
otherPivot: { x: 0, y: -bodyHeight / 2 - hipGap / 2, z: -bodyWidth / 2 + legThickness / 2 },
otherAxis: Vec3.normalize({ x: -1, y: 1, z: 0 }),
swingSpan1: Math.PI / 4,
swingSpan2: Math.PI / 4,
twistSpan: 0,
tag: "ragdoll left hip joint"
});
//
// right shin
//
var rightShinID = Entities.addEntity({
name: "ragdoll right shin",
type: "Box",
color: { blue: 20, green: 200, red: 20 },
dimensions: { x: shinThickness, y: shinLength, z: shinThickness },
position: Vec3.sum(pos, { x: 0,
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength / 2,
z: bodyWidth / 2 - legThickness / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -2, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", rightShinID, {
pivot: { x: 0, y: shinLength / 2 + kneeGap / 2, z: 0 },
axis: { x: 0, y: 0, z: 1 },
otherEntityID: rightLegID,
otherPivot: { x: 0, y: -legLength / 2 - kneeGap / 2, z: 0 },
otherAxis: { x: 0, y: 0, z: 1 },
low: 0,
high: Math.PI / 2,
tag: "ragdoll right knee joint"
});
//
// left shin
//
var leftShinID = Entities.addEntity({
name: "ragdoll left shin",
type: "Box",
color: { blue: 20, green: 200, red: 20 },
dimensions: { x: shinThickness, y: shinLength, z: shinThickness },
position: Vec3.sum(pos, { x: 0,
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength / 2,
z: -bodyWidth / 2 + legThickness / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -2, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", leftShinID, {
pivot: { x: 0, y: shinLength / 2 + kneeGap / 2, z: 0 },
axis: { x: 0, y: 0, z: 1 },
otherEntityID: leftLegID,
otherPivot: { x: 0, y: -legLength / 2 - kneeGap / 2, z: 0 },
otherAxis: { x: 0, y: 0, z: 1 },
low: 0,
high: Math.PI / 2,
tag: "ragdoll left knee joint"
});
//
// right foot
//
var rightFootID = Entities.addEntity({
name: "ragdoll right foot",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: footLength, y: footThickness, z: footWidth },
position: Vec3.sum(pos, { x: -shinThickness / 2 + footLength / 2,
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength - ankleGap - footThickness / 2,
z: bodyWidth / 2 - legThickness / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -5, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", rightFootID, {
pivot: { x: -footLength / 2 + shinThickness / 2, y: ankleGap / 2, z: 0 },
axis: { x: 0, y: 0, z: 1 },
otherEntityID: rightShinID,
otherPivot: { x: 0, y: -shinLength / 2 - ankleGap / 2, z: 0 },
otherAxis: { x: 0, y: 0, z: 1 },
low: ankleMin,
high: ankleMax,
tag: "ragdoll right ankle joint"
});
//
// left foot
//
var leftFootID = Entities.addEntity({
name: "ragdoll left foot",
type: "Box",
color: { blue: 128, green: 100, red: 20 },
dimensions: { x: footLength, y: footThickness, z: footWidth },
position: Vec3.sum(pos, { x: -shinThickness / 2 + footLength / 2,
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength - ankleGap - footThickness / 2,
z: bodyWidth / 2 - legThickness / 2
}),
dynamic: true,
collisionless: false,
gravity: { x: 0, y: -5, z: 0 },
lifetime: lifetime,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.addAction("hinge", leftFootID, {
pivot: { x: -footLength / 2 + shinThickness / 2, y: ankleGap / 2, z: 0 },
axis: { x: 0, y: 0, z: 1 },
otherEntityID: leftShinID,
otherPivot: { x: 0, y: -shinLength / 2 - ankleGap / 2, z: 0 },
otherAxis: { x: 0, y: 0, z: 1 },
low: ankleMin,
high: ankleMax,
tag: "ragdoll left ankle joint"
});
}
function onWebEventReceived(eventString) {
print("received web event: " + JSON.stringify(eventString));
if (typeof eventString === "string") {
var event;
try {
event = JSON.parse(eventString);
} catch(e) {
return;
}
if (event["dynamics-tests-command"]) {
var commandToFunctionMap = {
"cone-twist-and-spring-lever-test": coneTwistAndSpringLeverTest,
"door-vs-world-test": doorVSWorldTest,
"hinge-chain-test": hingeChainTest,
"slider-vs-world-test": sliderVSWorldTest,
"slider-chain-test": sliderChainTest,
"ball-socket-between-test": ballSocketBetweenTest,
"ball-socket-coincident-test": ballSocketCoincidentTest,
"ragdoll-test": ragdollTest
};
var cmd = event["dynamics-tests-command"];
if (commandToFunctionMap.hasOwnProperty(cmd)) {
var func = commandToFunctionMap[cmd];
func(event);
}
}
}
}
var onDynamicsTestsScreen = false;
var shouldActivateButton = false;
function onClicked() {
if (onDynamicsTestsScreen) {
tablet.gotoHomeScreen();
} else {
shouldActivateButton = true;
tablet.gotoWebScreen(DYNAMICS_TESTS_URL +
"?lifetime=" + DEFAULT_LIFETIME.toString()
);
onDynamicsTestsScreen = true;
}
}
function onScreenChanged() {
// for toolbar mode: change button to active when window is first openend, false otherwise.
button.editProperties({isActive: shouldActivateButton});
shouldActivateButton = false;
onDynamicsTestsScreen = shouldActivateButton;
}
function cleanup() {
button.clicked.disconnect(onClicked);
tablet.removeButton(button);
}
button.clicked.connect(onClicked);
tablet.webEventReceived.connect(onWebEventReceived);
tablet.screenChanged.connect(onScreenChanged);
Script.scriptEnding.connect(cleanup);
}()); // END LOCAL_SCOPE