mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-03-14 01:09:51 -04:00
Merge pull request #1982 from VernierST/extensions/gdx-for-freefall-and-tilt
GDX-FOR better freefall algorithm and different tilt options
This commit is contained in:
commit
9dd8e9398a
1 changed files with 93 additions and 74 deletions
|
@ -68,6 +68,12 @@ const FACING_THRESHOLD = 9;
|
|||
*/
|
||||
const FREEFALL_THRESHOLD = 0.5;
|
||||
|
||||
/**
|
||||
* Factor used to account for influence of rotation during freefall.
|
||||
* @type {number}
|
||||
*/
|
||||
const FREEFALL_ROTATION_FACTOR = 0.3;
|
||||
|
||||
/**
|
||||
* Acceleration due to gravity, in m/s^2.
|
||||
* @type {number}
|
||||
|
@ -269,29 +275,15 @@ class GdxFor {
|
|||
return this._sensors.force;
|
||||
}
|
||||
|
||||
getTiltX () {
|
||||
let x = this.getAccelerationX();
|
||||
let y = this.getAccelerationY();
|
||||
let z = this.getAccelerationZ();
|
||||
|
||||
let xSign = 1;
|
||||
let ySign = 1;
|
||||
let zSign = 1;
|
||||
|
||||
if (x < 0.0) {
|
||||
x *= -1.0; xSign = -1;
|
||||
}
|
||||
if (y < 0.0) {
|
||||
y *= -1.0; ySign = -1;
|
||||
}
|
||||
if (z < 0.0) {
|
||||
z *= -1.0; zSign = -1;
|
||||
}
|
||||
getTiltFrontBack (back = false) {
|
||||
const x = this.getAccelerationX();
|
||||
const y = this.getAccelerationY();
|
||||
const z = this.getAccelerationZ();
|
||||
|
||||
// Compute the yz unit vector
|
||||
const y2 = y * y;
|
||||
const z2 = z * z;
|
||||
const x2 = x * x;
|
||||
let value = z2 + x2;
|
||||
let value = y2 + z2;
|
||||
value = Math.sqrt(value);
|
||||
|
||||
// For sufficiently small zy vector values we are essentially at 90 degrees.
|
||||
|
@ -299,46 +291,28 @@ class GdxFor {
|
|||
// The snap factor was derived through observation -- just enough to
|
||||
// still allow single degree steps up to 90 (..., 87, 88, 89, 90).
|
||||
if (value < 0.35) {
|
||||
value = 90;
|
||||
value = (x < 0) ? 90 : -90;
|
||||
} else {
|
||||
// Compute the x-axis angle
|
||||
value = y / value;
|
||||
value = x / value;
|
||||
value = Math.atan(value);
|
||||
value *= 57.2957795; // convert from rad to deg
|
||||
value = MathUtil.radToDeg(value) * -1;
|
||||
}
|
||||
// Manage the sign of the result
|
||||
let xzSign = xSign;
|
||||
if (z > x) xzSign = zSign;
|
||||
if (xzSign === -1) value = 180.0 - value;
|
||||
value *= ySign;
|
||||
// Round the result to the nearest degree
|
||||
value += 0.5;
|
||||
|
||||
// Back is the inverse of front
|
||||
if (back) value *= -1;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
getTiltY () {
|
||||
let x = this.getAccelerationX();
|
||||
let y = this.getAccelerationY();
|
||||
let z = this.getAccelerationZ();
|
||||
|
||||
let xSign = 1;
|
||||
let ySign = 1;
|
||||
let zSign = 1;
|
||||
|
||||
if (x < 0.0) {
|
||||
x *= -1.0; xSign = -1;
|
||||
}
|
||||
if (y < 0.0) {
|
||||
y *= -1.0; ySign = -1;
|
||||
}
|
||||
if (z < 0.0) {
|
||||
z *= -1.0; zSign = -1;
|
||||
}
|
||||
getTiltLeftRight (right = false) {
|
||||
const x = this.getAccelerationX();
|
||||
const y = this.getAccelerationY();
|
||||
const z = this.getAccelerationZ();
|
||||
|
||||
// Compute the yz unit vector
|
||||
const x2 = x * x;
|
||||
const z2 = z * z;
|
||||
const y2 = y * y;
|
||||
let value = z2 + y2;
|
||||
let value = x2 + z2;
|
||||
value = Math.sqrt(value);
|
||||
|
||||
// For sufficiently small zy vector values we are essentially at 90 degrees.
|
||||
|
@ -346,20 +320,16 @@ class GdxFor {
|
|||
// The snap factor was derived through observation -- just enough to
|
||||
// still allow single degree steps up to 90 (..., 87, 88, 89, 90).
|
||||
if (value < 0.35) {
|
||||
value = 90;
|
||||
value = (y < 0) ? 90 : -90;
|
||||
} else {
|
||||
// Compute the x-axis angle
|
||||
value = x / value;
|
||||
value = y / value;
|
||||
value = Math.atan(value);
|
||||
value *= 57.2957795; // convert from rad to deg
|
||||
value = MathUtil.radToDeg(value) * -1;
|
||||
}
|
||||
// Manage the sign of the result
|
||||
let yzSign = ySign;
|
||||
if (z > y) yzSign = zSign;
|
||||
if (yzSign === -1) value = 180.0 - value;
|
||||
value *= xSign;
|
||||
// Round the result to the nearest degree
|
||||
value += 0.5;
|
||||
|
||||
// Right is the inverse of left
|
||||
if (right) value *= -1;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -415,8 +385,10 @@ const GestureValues = {
|
|||
* @enum {string}
|
||||
*/
|
||||
const TiltAxisValues = {
|
||||
X: 'x',
|
||||
Y: 'y'
|
||||
FRONT: 'front',
|
||||
BACK: 'back',
|
||||
LEFT: 'left',
|
||||
RIGHT: 'right'
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -479,12 +451,36 @@ class Scratch3GdxForBlocks {
|
|||
get TILT_MENU () {
|
||||
return [
|
||||
{
|
||||
text: 'x',
|
||||
value: TiltAxisValues.X
|
||||
text: formatMessage({
|
||||
id: 'gdxfor.tiltDirectionMenu.front',
|
||||
default: 'front',
|
||||
description: 'label for front element in tilt direction picker for gdxfor extension'
|
||||
}),
|
||||
value: TiltAxisValues.FRONT
|
||||
},
|
||||
{
|
||||
text: 'y',
|
||||
value: TiltAxisValues.Y
|
||||
text: formatMessage({
|
||||
id: 'gdxfor.tiltDirectionMenu.back',
|
||||
default: 'back',
|
||||
description: 'label for back element in tilt direction picker for gdxfor extension'
|
||||
}),
|
||||
value: TiltAxisValues.BACK
|
||||
},
|
||||
{
|
||||
text: formatMessage({
|
||||
id: 'gdxfor.tiltDirectionMenu.left',
|
||||
default: 'left',
|
||||
description: 'label for left element in tilt direction picker for gdxfor extension'
|
||||
}),
|
||||
value: TiltAxisValues.LEFT
|
||||
},
|
||||
{
|
||||
text: formatMessage({
|
||||
id: 'gdxfor.tiltDirectionMenu.right',
|
||||
default: 'right',
|
||||
description: 'label for right element in tilt direction picker for gdxfor extension'
|
||||
}),
|
||||
value: TiltAxisValues.RIGHT
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -639,7 +635,7 @@ class Scratch3GdxForBlocks {
|
|||
TILT: {
|
||||
type: ArgumentType.STRING,
|
||||
menu: 'tiltOptions',
|
||||
defaultValue: TiltAxisValues.X
|
||||
defaultValue: TiltAxisValues.FRONT
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -745,10 +741,14 @@ class Scratch3GdxForBlocks {
|
|||
|
||||
getTilt (args) {
|
||||
switch (args.TILT) {
|
||||
case TiltAxisValues.X:
|
||||
return Math.round(this._peripheral.getTiltX());
|
||||
case TiltAxisValues.Y:
|
||||
return Math.round(this._peripheral.getTiltY());
|
||||
case TiltAxisValues.FRONT:
|
||||
return Math.round(this._peripheral.getTiltFrontBack(false));
|
||||
case TiltAxisValues.BACK:
|
||||
return Math.round(this._peripheral.getTiltFrontBack(true));
|
||||
case TiltAxisValues.LEFT:
|
||||
return Math.round(this._peripheral.getTiltLeftRight(false));
|
||||
case TiltAxisValues.RIGHT:
|
||||
return Math.round(this._peripheral.getTiltLeftRight(true));
|
||||
default:
|
||||
log.warn(`Unknown direction in getTilt: ${args.TILT}`);
|
||||
}
|
||||
|
@ -802,6 +802,14 @@ class Scratch3GdxForBlocks {
|
|||
return this.accelMagnitude() - GRAVITY;
|
||||
}
|
||||
|
||||
spinMagnitude () {
|
||||
return this.magnitude(
|
||||
this._peripheral.getSpinSpeedX(),
|
||||
this._peripheral.getSpinSpeedY(),
|
||||
this._peripheral.getSpinSpeedZ()
|
||||
);
|
||||
}
|
||||
|
||||
isFacing (args) {
|
||||
switch (args.FACING) {
|
||||
case FaceValues.UP:
|
||||
|
@ -814,7 +822,18 @@ class Scratch3GdxForBlocks {
|
|||
}
|
||||
|
||||
isFreeFalling () {
|
||||
return this.accelMagnitude() < FREEFALL_THRESHOLD;
|
||||
const accelMag = this.accelMagnitude();
|
||||
const spinMag = this.spinMagnitude();
|
||||
|
||||
// We want to account for rotation during freefall,
|
||||
// so we tack on a an estimated "rotational effect"
|
||||
// The FREEFALL_ROTATION_FACTOR const is used to both scale the
|
||||
// gyro measurements and convert them to radians/second.
|
||||
// So, we compare our accel magnitude against:
|
||||
// FREEFALL_THRESHOLD + (some_scaled_magnitude_of_rotation).
|
||||
const ffThresh = FREEFALL_THRESHOLD + (FREEFALL_ROTATION_FACTOR * spinMag);
|
||||
|
||||
return accelMag < ffThresh;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue