/* global platypus */
import {Container} from 'pixi.js';
import Data from '../Data.js';
import Interactive from './Interactive.js';
import createComponentClass from '../factory.js';
export default (function () {
return createComponentClass(/** @lends platypus.components.HandlerRender.prototype */{
id: "HandlerRender",
properties: {
/**
* Defines whether the entity will respond to touch and click events. Setting this value will create an Interactive component on this entity with these properties. For example:
*
* "interactive": {
* "hover": false,
* "hitArea": {
* "x": 10,
* "y": 10,
* "width": 40,
* "height": 40
* }
* }
*
* @property interactive
* @type Boolean|Object
* @default false
*/
interactive: false
},
publicProperties: {
/**
* This is the container holding all children's disply objects for this layer. It's an available property on the layer entity.
*
* @property worldContainer
* @type PIXI.Container
* @default null
*/
worldContainer: null,
/**
* A multiplier that alters the speed at which the game is running. This is achieved by scaling the delta time in each tick.
* Defaults to 1. Values < 1 will slow down the rendering, > 1 will speed it up.
*
* @property timeMultiplier
* @type number
* @default 1
*/
timeMultiplier: 1
},
/**
* A component that handles updating the render components on entities that are rendering via PIXI. Calls 'handle-render on children entities every tick. Also initializes handlers for mouse events on the layer level.
*
* @memberof platypus.components
* @uses platypus.Component
* @constructs
* @listens platypus.Entity#child-entity-added
* @listens platypus.Entity#load
* @listens platypus.Entity#pause-render
* @listens platypus.Entity#render-update
* @listens platypus.Entity#set-parent-render-container
* @listens platypus.Entity#tick
* @listens platypus.Entity#unpause-render
* @fires platypus.Entity#handle-render-load
* @fires platypus.Entity#handle-render
* @fires platypus.Entity#input-on
* @fires platypus.Entity#render-paused
* @fires platypus.Entity#render-unpaused
* @fires platypus.Entity#render-world
*/
initialize: function () {
let definition = null;
this.worldContainer = this.worldContainer || new Container();
this.worldContainer.sortableChildren = true;
this.worldContainer.name = '';
if (this.interactive) {
definition = Data.setUp(
'container', this.worldContainer,
'hitArea', this.interactive.hitArea,
'hover', this.interactive.hover,
'relativeToSelf', true
);
this.owner.addComponent(new Interactive(this.owner, definition));
definition.recycle();
}
this.renderMessage = Data.setUp(
'delta', 0,
'container', this.worldContainer,
'tick', null
);
},
events: {
"load": function () {
/**
* Once the entity is loaded, this component triggers "render-world" to notify other components about the entities' display container.
*
* @event platypus.Entity#render-world
* @param data {Object}
* @param data.world {PIXI.Container} Contains entities to be rendered.
*/
this.owner.triggerEvent('render-world', {
world: this.worldContainer
});
/**
* This event is triggered once HandlerRender is ready to handle interactivity.
*
* @event platypus.Entity#input-on
*/
this.owner.triggerEvent('input-on');
},
"child-entity-added": function (entity) {
if (entity.container) {
this.setParentRenderContainer(entity, entity.renderParent);
}
/**
* Triggered on an entity added to the parent.
*
* @event platypus.Entity#handle-render-load
* @param data {Object}
* @param data.delta {Number} The delta time for this tick.
* @param data.container {PIXI.Container} The display Container the entities display objects should be added to.
*/
entity.triggerEvent('handle-render-load', this.renderMessage);
},
"pause-render": function (timeData) {
if (timeData && timeData.time) {
this.paused = timeData.time;
} else {
this.paused = -1;
}
if (this.owner.triggerEventOnChildren) {
/**
* Notifies children entities that rendering updates have been paused.
*
* @event platypus.Entity#render-paused
*/
this.owner.triggerEventOnChildren('render-paused');
}
},
"unpause-render": function () {
this.paused = 0;
if (this.owner.triggerEventOnChildren) {
/**
* Notifies children entities that rendering updates have been unpaused.
*
* @event platypus.Entity#render-unpaused
*/
this.owner.triggerEventOnChildren('render-unpaused');
}
},
"tick": function (tick) {
if (this.paused > 0) {
this.paused -= tick.delta;
if (this.paused <= 0) {
this.paused = 0;
}
}
if (!this.paused) {
this.renderUpdate(tick);
}
},
"render-update": function (tick) {
this.renderUpdate(tick);
},
"set-parent-render-container": function (entity, container) {
this.setParentRenderContainer(entity, container);
}
},
methods: {
renderUpdate: function (tick) {
const message = this.renderMessage;
message.gameDelta = (tick && tick.delta) || 0;
message.delta = message.gameDelta * this.timeMultiplier;
message.tick = tick;
/**
* Triggered every tick on owner and its children entities.
*
* @event platypus.Entity#handle-render
* @param data {Object}
* @param data.delta {Number} The delta time for this tick as manipulated by the timeMultiplier.
* @param data.gameDelta {Number} The delta time for this tick. Unmanipulated by the timeMultiplier. Use for components that should always run according to actual time.
* @param data.container {PIXI.Container} The display Container the entities display objects should be added to.
* @param data.tick {Object} Tick object from "tick" event.
*/
this.owner.triggerEvent('handle-render', message);
if (this.owner.triggerEventOnChildren) {
this.owner.triggerEventOnChildren('handle-render', message);
}
},
setParentRenderContainer: function (entity, newContainer) {
let container = null;
entity.removeFromParentContainer();
if (!newContainer) {
container = this.worldContainer;
} else if (typeof newContainer === "string") {
const otherEntity = this.owner.getEntityById(newContainer);
if (otherEntity) {
container = otherEntity.container;
} else {
//Didn't find group.
platypus.debug.warn("Trying to add to non-existent entity, added to World container instead.");
container = this.worldContainer;
}
} else if (newContainer instanceof Container) {
container = newContainer;
} else {
container = newContainer.container;
}
entity.addToParentContainer(container);
},
destroy: function () {
this.worldContainer = null;
this.renderMessage.recycle();
this.renderMessage = null;
}
}
});
}());