import {Container, Graphics} from 'pixi.js';
import {arrayCache} from '../utils/array.js';
import config from 'config';
import createComponentClass from '../factory.js';
const
collisionColors = {},
createCollisionColor = function (collisionType) {
let
r = collisionType.charCodeAt(0) || 0,
g = collisionType.charCodeAt(1) || 0,
b = collisionType.charCodeAt(2) || 0,
min = 0,
max = 0;
min = Math.min(r, g, b);
r -= min;
g -= min;
b -= min;
max = Math.max(r, g, b, 1);
r = (0xCC * r / max) >> 0;
g = (0xCC * g / max) >> 0;
b = (0xCC * b / max) >> 0;
return (r << 8) + (g << 4) + b;
};
export default (function () {
var createShape = function (shape, color, left, top, width, height, z, outline) {
var newShape = new Graphics().beginFill(color, 0.1);
if (outline) {
newShape.lineStyle(outline, color);
}
switch (shape) {
case 'rectangle':
newShape.drawRect(left, top, width, height);
break;
case 'circle':
newShape.drawCircle(0, 0, width);
break;
}
newShape.z = z;
return newShape;
},
standardizeColor = function (color) {
if (typeof color === 'string') {
return parseInt(color.replace('#', ''), 16);
} else {
return color;
}
};
return createComponentClass(/** @lends platypus.components.RenderDebug.prototype */{
id: 'RenderDebug',
properties: {
/**
* The color to use to highlight an entity's AABB. For example, use `"#ffffff"` or `0xffffff` to set as white.
*
* @property aabbColor
* @type Number|String
* @default 0xff88ff
*/
aabbColor: 0xff88ff,
/**
* The color to use to highlight an entity's collision shape. For example, use `"#ffffff"` or `0xffffff` to set as white. Will generate a color based on the collision type if not specified.
*
* @property collisionColor
* @type Number|String
* @default 0
*/
collisionColor: 0,
/**
* The color to use to highlight the AABB for a group of entities attached to this entity. For example, use `"#ffffff"` or `0xffffff` to set as white.
*
* @property groupColor
* @type Number|String
* @default 0x00ff00
*/
groupColor: 0x00ff00,
/**
* The color to use to highlight an entity. This property is only used if there is no `CollisionBasic` component attached to the entity: this component uses the entity's `width` and `height` properties if defined. For example, use `"#ffffff"` or `0xffffff` to set as white.
*
* @property renderColor
* @type Number|String
* @default 0x0000ff
*/
renderColor: 0x0000ff,
/**
* The height of the entity.
*
* @property height
* @type Number
* @default 100
*/
width: 100,
/**
* The width of the entity.
*
* @property width
* @type Number
* @default 100
*/
height: 100,
/**
* The local offset in z-index for the rendered debug area.
*
* @property offsetZ
* @type Number
* @default 10000
*/
offsetZ: 10000
},
/**
* This component is attached to entities that will appear in the game world. It serves two purposes. First, it displays a rectangle that indicates the location of the entity. By default it uses the specified position and dimensions of the object (in grey). If the object has a collision component it will display the AABB of the collision shape (in pink). If the entity has a LogicCarrier component and is/was carrying an object, a green rectangle will be drawn showing the collision group. The RenderDebug component also allows the developer to right-click on an entity and it will print the object in the debug console.
*
* @memberof platypus.components
* @uses platypus.Component
* @constructs
* @listens platypus.Entity#camera-update
* @listens platypus.Entity#collide-off
* @listens platypus.Entity#collide-on
* @listens platypus.Entity#handle-render
* @listens platypus.Entity#load
* @listens platypus.Entity#orientation-updated
*/
initialize: function () {
this.container = new Container();
this.parentContainer = this.owner.parent.worldContainer;
this.parentContainer.addChild(this.container);
this.needsCameraCheck = true;
this.shapes = arrayCache.setUp();
this.isOutdated = true;
this.aabbColor = standardizeColor(this.aabbColor);
this.collisionColor = this.collisionColor ? standardizeColor(this.collisionColor) : 0;
this.groupColor = standardizeColor(this.groupColor);
this.renderColor = standardizeColor(this.renderColor);
},
events: {
"load": function () {
if (!config.dev) {
this.owner.removeComponent(this);
return;
}
},
"camera-update": function () {
// Set visiblity of sprite if within camera bounds
this.needsCameraCheck = true;
},
"handle-render": function () {
var aabb = null,
offset = -0.5;
if (this.isOutdated) {
this.updateSprites();
this.isOutdated = false;
}
if (this.owner.getCollisionGroupAABB) {
aabb = this.owner.getCollisionGroupAABB();
if (!this.groupShape) {
this.groupShape = createShape('rectangle', this.groupColor, offset, offset, 1, 1, this.offsetZ);
this.container.addChild(this.groupShape);
}
this.groupShape.scaleX = aabb.width;
this.groupShape.scaleY = aabb.height;
this.groupShape.x = aabb.x - this.owner.x;
this.groupShape.y = aabb.y - this.owner.y;
}
this.update();
},
"orientation-updated": function () {
this.isOutdated = true;
},
"collide-on": function () {
this.isOutdated = true;
},
"collide-off": function () {
this.isOutdated = true;
}
},
methods: {
update: function () {
var x = 0,
y = 0;
x = this.owner.x;
y = this.owner.y;
if (this.container.zIndex !== this.owner.z + 0.000001) {
this.container.zIndex = this.owner.z + 0.000001;
}
this.container.setTransform(x, y, 1, 1, 0, 0, 0);
// Set isCameraOn of sprite if within camera bounds
if (!this.needsCameraCheck) {
this.needsCameraCheck = (this.lastX !== this.owner.x) || (this.lastY !== this.owner.y);
}
if (this.needsCameraCheck) {
this.isOnCamera = this.owner.parent.isOnCanvas(this.container.getBounds(false));
this.needsCameraCheck = false;
}
this.lastX = this.owner.x;
this.lastY = this.owner.y;
this.container.visible = this.isOnCamera;
},
updateSprites: function () {
var owner = this.owner,
z = this.offsetZ,
i = 0,
j = 0,
lineWidth = 2,
width = this.width,
height = this.height,
shapes = null,
aabb = null,
shape = null;
for (i = 0; i < this.shapes.length; i++) {
this.container.removeChild(this.shapes[i]);
}
this.shapes.length = 0;
if (owner.getAABB) {
for (j = 0; j < owner.collisionTypes.length; j++) {
const
collisionType = owner.collisionTypes[j];
let collisionColor = this.collisionColor || collisionColors[collisionType];
if (!collisionColor) {
collisionColor = collisionColors[collisionType] = createCollisionColor(collisionType);
}
aabb = owner.getAABB(collisionType);
width = this.initialWidth = aabb.width;
height = this.initialHeight = aabb.height;
shapes = owner.getShapes(collisionType);
shape = createShape('rectangle', this.aabbColor, aabb.left - owner.x, aabb.top - owner.y, width, height, z--);
this.shapes.push(shape);
this.container.addChild(shape);
for (i = 0; i < shapes.length; i++) {
width = shapes[i].width - lineWidth;
height = shapes[i].height - lineWidth;
shape = createShape(shapes[i].type, collisionColor, shapes[i].offsetX - width / 2, shapes[i].offsetY - height / 2, (shapes[i].radius ? shapes[i].radius - lineWidth : width), height, z--, lineWidth);
this.shapes.push(shape);
this.container.addChild(shape);
}
}
} else {
shape = createShape('rectangle', this.renderColor, -width / 2, -height / 2, width, height, z--);
this.shapes.push(shape);
this.container.addChild(shape);
}
},
destroy: function () {
var i = 0;
for (i = 0; i < this.shapes.length; i++) {
this.container.removeChild(this.shapes[i]);
}
arrayCache.recycle(this.shapes);
this.parentContainer.removeChild(this.container);
this.container = null;
}
}
});
}());