@smoud/tiny
Version:
Fast and tiny JavaScript library for HTML5 game and playable ads creation.
313 lines (232 loc) • 8.57 kB
JavaScript
import { BaseObject2D } from './BaseObject2D';
import { identityMatrix } from '../math/Mat3';
import { Rectangle, EmptyRectangle } from '../math/shapes/Rectangle';
var Object2D = function () {
BaseObject2D.call(this);
this.children = [];
this._bounds = new Rectangle(0, 0, 1, 1);
this._currentBounds = null;
this._mask = null;
};
Object2D.prototype = Object.create(BaseObject2D.prototype);
Object2D.prototype.constructor = Object2D;
// Object.defineProperty(Object2D.prototype, 'inputEnabled', {
// get: function() {
// return (this.input && this.input.enabled)
// },
// set: function(value) {
// if (value) {
// if (this.input === null) {
// this.input = {enabled: true, parent: this}
// Tiny.EventTarget.mixin(this.input)
// } else
// this.input.enabled = true
// } else {
// this.input !== null && (this.input.enabled = false)
// }
// }
// });
Object.defineProperty(Object2D.prototype, 'width', {
get: function () {
return this.scale.x * this.getLocalBounds().width;
},
set: function (value) {
var width = this.getLocalBounds().width;
if (width !== 0) {
this.scale.x = value / width;
} else {
this.scale.x = 1;
}
this._width = value;
}
});
Object.defineProperty(Object2D.prototype, 'height', {
get: function () {
return this.scale.y * this.getLocalBounds().height;
},
set: function (value) {
var height = this.getLocalBounds().height;
if (height !== 0) {
this.scale.y = value / height;
} else {
this.scale.y = 1;
}
this._height = value;
}
});
Object.defineProperty(Object2D.prototype, 'mask', {
get: function () {
return this._mask;
},
set: function (value) {
if (this._mask) this._mask.isMask = false;
this._mask = value;
if (this._mask) this._mask.isMask = true;
}
});
Object2D.prototype.destroy = function () {
var i = this.children.length;
while (i--) {
this.children[i].destroy();
}
this.children = [];
BaseObject2D.prototype.destroy.call(this);
this._bounds = null;
this._currentBounds = null;
this._mask = null;
if (this.input) this.input.system.remove(this);
};
Object2D.prototype.add = function (child) {
return this.addChildAt(child, this.children.length);
};
Object2D.prototype.addChildAt = function (child, index) {
if (index >= 0 && index <= this.children.length) {
if (child.parent) {
child.parent.remove(child);
}
child.parent = this;
if (this.game) child.game = this.game;
this.children.splice(index, 0, child);
return child;
} else {
throw new Error(
child + 'addChildAt: The index ' + index + ' supplied is out of bounds ' + this.children.length
);
}
};
Object2D.prototype.swapChildren = function (child, child2) {
if (child === child2) {
return;
}
var index1 = this.getChildIndex(child);
var index2 = this.getChildIndex(child2);
if (index1 < 0 || index2 < 0) {
throw new Error('swapChildren: Both the supplied Objects must be a child of the caller.');
}
this.children[index1] = child2;
this.children[index2] = child;
};
Object2D.prototype.getChildIndex = function (child) {
var index = this.children.indexOf(child);
if (index === -1) {
throw new Error('The supplied Object must be a child of the caller');
}
return index;
};
Object2D.prototype.setChildIndex = function (child, index) {
if (index < 0 || index >= this.children.length) {
throw new Error('The supplied index is out of bounds');
}
var currentIndex = this.getChildIndex(child);
this.children.splice(currentIndex, 1); //remove from old position
this.children.splice(index, 0, child); //add at new position
};
Object2D.prototype.getChildAt = function (index) {
if (index < 0 || index >= this.children.length) {
throw new Error(
'getChildAt: Supplied index ' +
index +
' does not exist in the child list, or the supplied Object must be a child of the caller'
);
}
return this.children[index];
};
Object2D.prototype.remove = function (child) {
var index = this.children.indexOf(child);
if (index === -1) return;
return this.removeChildAt(index);
};
Object2D.prototype.removeChildAt = function (index) {
var child = this.getChildAt(index);
child.parent = undefined;
this.children.splice(index, 1);
return child;
};
Object2D.prototype.updateTransform = function () {
if (!this.visible) return;
this.displayObjectUpdateTransform();
if (this._cacheAsBitmap) return;
for (var i = 0, j = this.children.length; i < j; i++) {
this.children[i].updateTransform();
}
};
// performance increase to avoid using call.. (10x faster)
Object2D.prototype.displayObjectContainerUpdateTransform = Object2D.prototype.updateTransform;
Object2D.prototype.getBounds = function () {
if (this.children.length === 0) return EmptyRectangle;
if (this._cachedSprite) return this._cachedSprite.getBounds();
// TODO the bounds have already been calculated this render session so return what we have
var minX = Infinity;
var minY = Infinity;
var maxX = -Infinity;
var maxY = -Infinity;
var childBounds;
var childMaxX;
var childMaxY;
var childVisible = false;
for (var i = 0, j = this.children.length; i < j; i++) {
var child = this.children[i];
if (!child.visible) continue;
childVisible = true;
childBounds = this.children[i].getBounds();
minX = minX < childBounds.x ? minX : childBounds.x;
minY = minY < childBounds.y ? minY : childBounds.y;
childMaxX = childBounds.width + childBounds.x;
childMaxY = childBounds.height + childBounds.y;
maxX = maxX > childMaxX ? maxX : childMaxX;
maxY = maxY > childMaxY ? maxY : childMaxY;
}
if (!childVisible) return EmptyRectangle;
var bounds = this._bounds;
bounds.x = minX;
bounds.y = minY;
bounds.width = maxX - minX;
bounds.height = maxY - minY;
// TODO: store a reference so that if this function gets called again in the render cycle we do not have to recalculate
//this._currentBounds = bounds;
return bounds;
};
Object2D.prototype.getLocalBounds = function () {
var matrixCache = this.worldTransform;
this.worldTransform = identityMatrix;
for (var i = 0, j = this.children.length; i < j; i++) {
this.children[i].updateTransform();
}
var bounds = this.getBounds();
this.worldTransform = matrixCache;
return bounds;
};
Object2D.prototype.render = function (renderSession) {
if (!this.visible || this.alpha <= 0) return;
if (this._cacheAsBitmap) {
this._renderCachedSprite(renderSession);
return;
}
var i, j;
if (this._mask || this._filters) {
// push filter first as we need to ensure the stencil buffer is correct for any masking
if (this._filters) {
renderSession.spriteBatch.flush();
renderSession.filterManager.pushFilter(this._filterBlock);
}
if (this._mask) {
renderSession.spriteBatch.stop();
renderSession.maskManager.pushMask(this.mask, renderSession);
renderSession.spriteBatch.start();
}
// simple render children!
for (i = 0, j = this.children.length; i < j; i++) {
this.children[i].render(renderSession);
}
renderSession.spriteBatch.stop();
if (this._mask) renderSession.maskManager.popMask(this._mask, renderSession);
if (this._filters) renderSession.filterManager.popFilter();
renderSession.spriteBatch.start();
} else {
// simple render children!
for (i = 0, j = this.children.length; i < j; i++) {
this.children[i].render(renderSession);
}
}
};
export { Object2D };