Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/components/pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ sceneEl.components.pool__enemy.returnEntity(el);

| Property | Description | Default Value |
|----------|---------------------------------------------------------------------------------------|---------------|
| container | Selector to store pooled entities. Defaults to the scene. | '' |
| dynamic | Grow the pool automatically if more entities are requested after reaching the `size`. | false |
| mixin | Mixin required to initialize the entities of the pool. | '' |
| size | Number of preallocated entities in the pool. | 0 |
Expand Down
46 changes: 29 additions & 17 deletions src/components/scene/pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@ var registerComponent = require('../../core/component').registerComponent;
var warn = debug('components:pool:warn');

/**
* Pool component.
* A pool of entities that will be reused.
* It avoids creating and destroying the same kind of entities
* in dynamic scenes. It will help reduce GC pauses. Useful for example
* in a game where you want to reuse enemies entities.
* Pool component to reuse entities.
* Avoids creating and destroying the same kind of entities.
* Helps reduce GC pauses. For example in a game to reuse enemies entities.
*
* @member {array} availableEls - Available entities in the pool.
* @member {array} usedEls - Entities of the pool in use.
*
*/
module.exports.Component = registerComponent('pool', {
schema: {
container: {default: ''},
mixin: {default: ''},
size: {default: 0},
dynamic: {default: false}
Expand All @@ -25,10 +23,22 @@ module.exports.Component = registerComponent('pool', {

initPool: function () {
var i;
var mixin = this.data.mixin;
if (!mixin) { return; }

this.availableEls = [];
this.usedEls = [];

if (!this.data.mixin) {
warn('No mixin provided for pool component.');
}

if (this.data.container) {
this.container = document.querySelector(this.data.container);
if (!this.container) {
warn('Container ' + this.data.container + ' not found.');
}
}
this.container = this.container || this.el;

for (i = 0; i < this.data.size; ++i) {
this.createEntity();
}
Expand All @@ -45,17 +55,18 @@ module.exports.Component = registerComponent('pool', {
* Add a new entity to the list of available entities.
*/
createEntity: function () {
var el = document.createElement('a-entity');
var el;
el = document.createElement('a-entity');
el.play = this.wrapPlay(el.play);
el.setAttribute('mixin', this.data.mixin);
el.setAttribute('visible', false);
this.el.appendChild(el);
this.container.appendChild(el);
this.availableEls.push(el);
},

/**
* Play wrapper for pooled entities. When pausing and playing
* a scene we don't want to play the entities that are not in use
* Play wrapper for pooled entities. When pausing and playing a scene, don't want to play
* entities that are not in use.
*/
wrapPlay: function (playMethod) {
var usedEls = this.usedEls;
Expand All @@ -66,17 +77,17 @@ module.exports.Component = registerComponent('pool', {
},

/**
* Used to request one of the available entities of the pool
* Used to request one of the available entities of the pool.
*/
requestEntity: function () {
var el;
if (this.availableEls.length === 0) {
if (this.data.dynamic === false) {
warn('Requested entity from empty pool ' + this.name);
warn('Requested entity from empty pool: ' + this.name);
return;
} else {
warn('Requested entity from empty pool. This pool is dynamic' +
'and will resize automatically. You might want to increase its initial size' + this.name);
warn('Requested entity from empty pool. This pool is dynamic and will resize ' +
'automatically. You might want to increase its initial size: ' + this.name);
}
this.createEntity();
}
Expand All @@ -87,7 +98,7 @@ module.exports.Component = registerComponent('pool', {
},

/**
* Used to return a used entity to the pool
* Used to return a used entity to the pool.
*/
returnEntity: function (el) {
var index = this.usedEls.indexOf(el);
Expand All @@ -99,5 +110,6 @@ module.exports.Component = registerComponent('pool', {
this.availableEls.push(el);
el.setAttribute('visible', false);
el.pause();
return el;
}
});
21 changes: 21 additions & 0 deletions tests/components/scene/pool.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ suite('pool', function () {
var sceneEl = this.sceneEl = el.parentNode;
sceneEl.setAttribute('pool', 'mixin: test; size: 1');
helpers.mixinFactory('test', {material: 'color: red'}, sceneEl);
if (sceneEl.hasLoaded) { done(); return; }
sceneEl.addEventListener('loaded', function () { done(); });
});

Expand All @@ -18,6 +19,26 @@ suite('pool', function () {
assert.equal(sceneEl.querySelectorAll('[material]').length, 1);
});

test('can specify container', function (done) {
var container;
var sceneEl = this.sceneEl;
var poolComponent = sceneEl.components.pool;

container = document.createElement('a-entity');
container.setAttribute('id', 'foo');
sceneEl.appendChild(container);

setTimeout(() => {
sceneEl.setAttribute('pool__foo', 'mixin: test; size: 1; container: #foo');
setTimeout(() => {
assert.equal(poolComponent.availableEls.length, 1);
assert.equal(poolComponent.usedEls.length, 0);
assert.equal(container.querySelectorAll('[material]').length, 1);
done();
});
});
});

suite('requestEntity', function () {
test('can request an available entity', function () {
var sceneEl = this.sceneEl;
Expand Down