Skip to content

Commit 28ef310

Browse files
committed
throttle just the physics body scale update
1 parent c70b3f3 commit 28ef310

File tree

6 files changed

+113
-36
lines changed

6 files changed

+113
-36
lines changed

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,11 +514,21 @@ Makes and entity rescale while grabbed by both controllers as they are moved clo
514514
| endButtons | Which button events to accept to end stretch | `[]` |
515515
| usePhysics | Whether to update physics body shapes with scale changes, 'ifavailable' or 'never' | 'ifavailable' |
516516
| invert | Reverse the direction of scaling in relation to controller movement | `false` |
517+
| phyicsUpdateRate | Milliseconds between each update to the physics bodies of a stretched entity | 100 |
517518

518519
The default for `startButtons` and `endButtons` is to accept any button
519520
recognized by `super-hands` `stretchStartButtons` and `stretchEndButtons`.
520521

521-
There is no CANNON api method for updating physics body scale, but `stretchable` will manually rescale basic shapes. Currently rescalable shapes are: box and sphere.
522+
There is no CANNON API method for updating physics body scale, but `stretchable`
523+
will manually rescale shapes and offsets for stretched entity body and
524+
all descendent entity bodies.
525+
This update is throttled and will occur no more than once every
526+
`physicsUpdateRate` milliseconds to improve performance. Set this to a smaller
527+
number to increase the physics simulation fidelity.
528+
Currently rescalable shapes are: box and sphere. At present, this rescaling
529+
is only possible on when using the `'local'` physics driver. If using another
530+
driver, setting `usePhysics: never` will avoid errors but also cause
531+
loss of sync between stretched entities' appearance and behavior.
522532

523533
#### States
524534

dist/super-hands.js

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,7 +1323,8 @@ const buttonCore = require('./prototypes/buttons-proto.js');
13231323
AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
13241324
schema: {
13251325
usePhysics: { default: 'ifavailable' },
1326-
invert: { default: false }
1326+
invert: { default: false },
1327+
physicsUpdateRate: { default: 100 }
13271328
},
13281329
init: function () {
13291330
this.STRETCHED_STATE = 'stretched';
@@ -1341,11 +1342,11 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
13411342

13421343
this.el.addEventListener(this.STRETCH_EVENT, this.start);
13431344
this.el.addEventListener(this.UNSTRETCH_EVENT, this.end);
1344-
1345-
this.tick = AFRAME.utils.throttleTick(this._tick, 33, this);
13461345
},
1347-
update: function (oldDat) {},
1348-
_tick: function () {
1346+
update: function (oldDat) {
1347+
this.updateBodies = AFRAME.utils.throttleTick(this._updateBodies, this.data.physicsUpdateRate, this);
1348+
},
1349+
tick: function (time, timeDelta) {
13491350
if (!this.stretched) {
13501351
return;
13511352
}
@@ -1358,15 +1359,14 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
13581359
deltaStretch = Math.pow(currentStretch / this.previousStretch, this.data.invert ? -1 : 1);
13591360
}
13601361
this.previousStretch = currentStretch;
1362+
if (this.previousPhysicsStretch == null) {
1363+
// establish correct baseline even if throttled function isn't called
1364+
this.previousPhysicsStretch = currentStretch;
1365+
}
13611366
this.scale.multiplyScalar(deltaStretch);
13621367
this.el.setAttribute('scale', this.scale);
1363-
// force scale update for all nested physics bodies
1364-
if (this.el.body && this.data.usePhysics !== 'never') {
1365-
for (let c of this.el.children) {
1366-
this.stretchBody(c, deltaStretch);
1367-
}
1368-
this.stretchBody(this.el, deltaStretch);
1369-
}
1368+
// scale update for all nested physics bodies (throttled)
1369+
this.updateBodies(time, timeDelta);
13701370
},
13711371
remove: function () {
13721372
this.el.removeEventListener(this.STRETCH_EVENT, this.start);
@@ -1380,6 +1380,7 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
13801380
if (this.stretchers.length === 2) {
13811381
this.stretched = true;
13821382
this.previousStretch = null;
1383+
this.previousPhysicsStretch = null;
13831384
this.el.addState(this.STRETCHED_STATE);
13841385
}
13851386
if (evt.preventDefault) {
@@ -1395,11 +1396,31 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
13951396
this.stretchers.splice(stretcherIndex, 1);
13961397
this.stretched = false;
13971398
this.el.removeState(this.STRETCHED_STATE);
1399+
// override throttle to push last stretch to physics bodies
1400+
this._updateBodies();
13981401
}
13991402
if (evt.preventDefault) {
14001403
evt.preventDefault();
14011404
}
14021405
},
1406+
_updateBodies: function () {
1407+
if (!this.el.body || this.data.usePhysics === 'never') {
1408+
return;
1409+
}
1410+
const currentStretch = this.previousStretch; // last visible geometry stretch
1411+
let deltaStretch = 1;
1412+
if (this.previousPhysicsStretch !== null && currentStretch > 0) {
1413+
deltaStretch = Math.pow(currentStretch / this.previousPhysicsStretch, this.data.invert ? -1 : 1);
1414+
}
1415+
this.previousPhysicsStretch = currentStretch;
1416+
if (deltaStretch === 1) {
1417+
return;
1418+
}
1419+
for (let c of this.el.children) {
1420+
this.stretchBody(c, deltaStretch);
1421+
}
1422+
this.stretchBody(this.el, deltaStretch);
1423+
},
14031424
stretchBody: function (el, deltaStretch) {
14041425
if (!el.body) {
14051426
return;

dist/super-hands.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/build.js

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2774,7 +2774,8 @@ const buttonCore = require('./prototypes/buttons-proto.js');
27742774
AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
27752775
schema: {
27762776
usePhysics: { default: 'ifavailable' },
2777-
invert: { default: false }
2777+
invert: { default: false },
2778+
physicsUpdateRate: { default: 100 }
27782779
},
27792780
init: function () {
27802781
this.STRETCHED_STATE = 'stretched';
@@ -2792,11 +2793,11 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
27922793

27932794
this.el.addEventListener(this.STRETCH_EVENT, this.start);
27942795
this.el.addEventListener(this.UNSTRETCH_EVENT, this.end);
2795-
2796-
this.tick = AFRAME.utils.throttleTick(this._tick, 33, this);
27972796
},
2798-
update: function (oldDat) {},
2799-
_tick: function () {
2797+
update: function (oldDat) {
2798+
this.updateBodies = AFRAME.utils.throttleTick(this._updateBodies, this.data.physicsUpdateRate, this);
2799+
},
2800+
tick: function (time, timeDelta) {
28002801
if (!this.stretched) {
28012802
return;
28022803
}
@@ -2809,15 +2810,14 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
28092810
deltaStretch = Math.pow(currentStretch / this.previousStretch, this.data.invert ? -1 : 1);
28102811
}
28112812
this.previousStretch = currentStretch;
2813+
if (this.previousPhysicsStretch == null) {
2814+
// establish correct baseline even if throttled function isn't called
2815+
this.previousPhysicsStretch = currentStretch;
2816+
}
28122817
this.scale.multiplyScalar(deltaStretch);
28132818
this.el.setAttribute('scale', this.scale);
2814-
// force scale update for all nested physics bodies
2815-
if (this.el.body && this.data.usePhysics !== 'never') {
2816-
for (let c of this.el.children) {
2817-
this.stretchBody(c, deltaStretch);
2818-
}
2819-
this.stretchBody(this.el, deltaStretch);
2820-
}
2819+
// scale update for all nested physics bodies (throttled)
2820+
this.updateBodies(time, timeDelta);
28212821
},
28222822
remove: function () {
28232823
this.el.removeEventListener(this.STRETCH_EVENT, this.start);
@@ -2831,6 +2831,7 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
28312831
if (this.stretchers.length === 2) {
28322832
this.stretched = true;
28332833
this.previousStretch = null;
2834+
this.previousPhysicsStretch = null;
28342835
this.el.addState(this.STRETCHED_STATE);
28352836
}
28362837
if (evt.preventDefault) {
@@ -2846,11 +2847,31 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
28462847
this.stretchers.splice(stretcherIndex, 1);
28472848
this.stretched = false;
28482849
this.el.removeState(this.STRETCHED_STATE);
2850+
// override throttle to push last stretch to physics bodies
2851+
this._updateBodies();
28492852
}
28502853
if (evt.preventDefault) {
28512854
evt.preventDefault();
28522855
}
28532856
},
2857+
_updateBodies: function () {
2858+
if (!this.el.body || this.data.usePhysics === 'never') {
2859+
return;
2860+
}
2861+
const currentStretch = this.previousStretch; // last visible geometry stretch
2862+
let deltaStretch = 1;
2863+
if (this.previousPhysicsStretch !== null && currentStretch > 0) {
2864+
deltaStretch = Math.pow(currentStretch / this.previousPhysicsStretch, this.data.invert ? -1 : 1);
2865+
}
2866+
this.previousPhysicsStretch = currentStretch;
2867+
if (deltaStretch === 1) {
2868+
return;
2869+
}
2870+
for (let c of this.el.children) {
2871+
this.stretchBody(c, deltaStretch);
2872+
}
2873+
this.stretchBody(this.el, deltaStretch);
2874+
},
28542875
stretchBody: function (el, deltaStretch) {
28552876
if (!el.body) {
28562877
return;

machinima_tests/super_hands/progressive-controls-machinima.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const machinima = require('aframe-machinima-testing')
44

55
suite('progressive-controls touch interactions', function () {
66
setup(function (done) {
7+
this.timeout(0)
78
machinima.setupScene('progressive-hands.html')
89
this.scene = document.querySelector('a-scene')
910
this.scene.addEventListener('loaded', e => {

reaction_components/stretchable.js

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const buttonCore = require('./prototypes/buttons-proto.js')
44
AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
55
schema: {
66
usePhysics: {default: 'ifavailable'},
7-
invert: {default: false}
7+
invert: {default: false},
8+
physicsUpdateRate: {default: 100}
89
},
910
init: function () {
1011
this.STRETCHED_STATE = 'stretched'
@@ -22,13 +23,15 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
2223

2324
this.el.addEventListener(this.STRETCH_EVENT, this.start)
2425
this.el.addEventListener(this.UNSTRETCH_EVENT, this.end)
25-
26-
this.tick = AFRAME.utils.throttleTick(this._tick, 33, this)
2726
},
2827
update: function (oldDat) {
29-
28+
this.updateBodies = AFRAME.utils.throttleTick(
29+
this._updateBodies,
30+
this.data.physicsUpdateRate,
31+
this
32+
)
3033
},
31-
_tick: function () {
34+
tick: function (time, timeDelta) {
3235
if (!this.stretched) { return }
3336
this.scale.copy(this.el.getAttribute('scale'))
3437
this.handPos.copy(this.stretchers[0].getAttribute('position'))
@@ -44,13 +47,14 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
4447
)
4548
}
4649
this.previousStretch = currentStretch
50+
if (this.previousPhysicsStretch == null) {
51+
// establish correct baseline even if throttled function isn't called
52+
this.previousPhysicsStretch = currentStretch
53+
}
4754
this.scale.multiplyScalar(deltaStretch)
4855
this.el.setAttribute('scale', this.scale)
49-
// force scale update for all nested physics bodies
50-
if (this.el.body && this.data.usePhysics !== 'never') {
51-
for (let c of this.el.children) { this.stretchBody(c, deltaStretch) }
52-
this.stretchBody(this.el, deltaStretch)
53-
}
56+
// scale update for all nested physics bodies (throttled)
57+
this.updateBodies(time, timeDelta)
5458
},
5559
remove: function () {
5660
this.el.removeEventListener(this.STRETCH_EVENT, this.start)
@@ -65,6 +69,7 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
6569
if (this.stretchers.length === 2) {
6670
this.stretched = true
6771
this.previousStretch = null
72+
this.previousPhysicsStretch = null
6873
this.el.addState(this.STRETCHED_STATE)
6974
}
7075
if (evt.preventDefault) { evt.preventDefault() } // gesture accepted
@@ -76,9 +81,28 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
7681
this.stretchers.splice(stretcherIndex, 1)
7782
this.stretched = false
7883
this.el.removeState(this.STRETCHED_STATE)
84+
// override throttle to push last stretch to physics bodies
85+
this._updateBodies()
7986
}
8087
if (evt.preventDefault) { evt.preventDefault() }
8188
},
89+
_updateBodies: function () {
90+
if (!this.el.body || this.data.usePhysics === 'never') { return }
91+
const currentStretch = this.previousStretch // last visible geometry stretch
92+
let deltaStretch = 1
93+
if (this.previousPhysicsStretch !== null && currentStretch > 0) {
94+
deltaStretch = Math.pow(
95+
currentStretch / this.previousPhysicsStretch,
96+
(this.data.invert)
97+
? -1
98+
: 1
99+
)
100+
}
101+
this.previousPhysicsStretch = currentStretch
102+
if (deltaStretch === 1) { return }
103+
for (let c of this.el.children) { this.stretchBody(c, deltaStretch) }
104+
this.stretchBody(this.el, deltaStretch)
105+
},
82106
stretchBody: function (el, deltaStretch) {
83107
if (!el.body) { return }
84108
let physicsShape

0 commit comments

Comments
 (0)