pubtool4pixi
Version:
Usefultool for PIXI xes project
416 lines (380 loc) • 15.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _getPrototypeOf = require("babel-runtime/core-js/object/get-prototype-of");
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require("babel-runtime/helpers/createClass");
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require("babel-runtime/helpers/possibleConstructorReturn");
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require("babel-runtime/helpers/inherits");
var _inherits3 = _interopRequireDefault(_inherits2);
var _defineProperties = require("babel-runtime/core-js/object/define-properties");
var _defineProperties2 = _interopRequireDefault(_defineProperties);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// import { Container, Point } from "pixi.js";
var Container = PIXI.Container;
var Point = PIXI.Point;
function defineProperty(name, defaultValue) {
var getter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function (value) {
return value;
};
var setter = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function (value) {
return value;
};
var value = defaultValue;
var o = {};
o[name] = {
get: function get() {
return getter(value);
},
set: function set(para) {
value = setter(para);
}
};
(0, _defineProperties2.default)(this, o);
}
/**
* @class HitContainer
* @extends PIXI.Container
* @classdesc Hit test container
* @property {Number} ssampleCount - 采样个数,如360代表每隔一度采样一次 - 默认:360
* @property {Number} sampleMinAlpha - 采样像素点阈值,采样的数据为RGBA中的A 范围在0-255 - 默认:0
* @property {Number} sampleDist - 采样衰减距离 - 默认:1像素
* @example
* var local = new HitContainer();
* local.sampleCount = 720;
* local.sampleMinAlpha = 10;
* var localSprite = new PIXI.Sprite(res["image_example1"].texture);
* localSprite.anchor.set(0.5);
* local.addChild(localSprite);
* var target = new HitContainer();
* var targetSprite = new PIXI.Sprite(res["image_example2"].texture);
* targetSprite.anchor.set(0.5);
* target.addChild(targetSprite);
* local.initBound();
* target.initBound();
* local.position.set(10,10);
* console.log(local.hitTest(target));
* */
var HitContainer = function (_Container) {
(0, _inherits3.default)(HitContainer, _Container);
function HitContainer() {
(0, _classCallCheck3.default)(this, HitContainer);
var _this = (0, _possibleConstructorReturn3.default)(this, (HitContainer.__proto__ || (0, _getPrototypeOf2.default)(HitContainer)).call(this));
defineProperty.call(_this, "sampleCount", 360, undefined, function (value) {
return parseInt(value);
});
defineProperty.call(_this, "sampleMinAlpha", 0);
defineProperty.call(_this, "sampleDist", 1);
return _this;
}
(0, _createClass3.default)(HitContainer, [{
key: "_toRad",
value: function _toRad(deg) {
return deg * Math.PI / 180;
}
/**
* @function _polarToPixel
* @memberOf HitContainer
* @description Caculate the position in Cartesian coordinate with given point in polar coordinate.
* @param {Number} amplitude Amplitude of polar coordinate point.
* @param {Number} phase Phase of polar coordinate point.
* @return {Point} Point in Cartesian coordinate
*/
}, {
key: "_polarToPixel",
value: function _polarToPixel(amplitude, phase) {
return {
x: amplitude * Math.cos(phase),
y: amplitude * Math.sin(phase)
};
}
/**
* @function _caculateBoundMatrix
* @memberOf HitContainer
* @description Caculate the matrix base on visible pixel in this container.
* @return {Array} Two-dimensional array contains binnary numbers. 1 means visible and 0 means transparent.
*/
}, {
key: "_caculateBoundMatrix",
value: function _caculateBoundMatrix() {
var buffer = app.renderer.extract.pixels(this);
var width = Math.floor(this.width);
var count = width;
var arr = [];
var length = buffer.length;
for (var i = 0; i < length; i += 4) {
if (count === width) {
arr.push([]);
count = 0;
}
var alpha = buffer[i + 3];
arr[arr.length - 1].push(alpha > this.sampleMinAlpha ? 1 : 0);
count++;
}
return arr;
}
/**
* @function _caculateBound
* @memberOf HitContainer
* @description Caculate bound area for this in polor coordinate.
* @param {Number} Two-dimensional array contains binnary numbers.
* @return {Array} An array contains polor coordinate points.
*/
}, {
key: "_caculateBound",
value: function _caculateBound(buffer) {
var bound = this.getBounds();
var globalP = this.getGlobalPosition();
var dx = bound.x - globalP.x;
var dy = bound.y - globalP.y;
var sampleAmplitudeMax = Math.floor(Math.sqrt(this.width * this.width + this.height * this.height, 2) / 2);
var arr = [];
var me = this;
var width = me.width;
var height = me.height;
var step = 360 / this.sampleCount;
var dist = me.sampleDist;
for (var j = 0; j < 360; j += step) {
for (var i = sampleAmplitudeMax; i > 0; i -= dist) {
var p = me._polarToPixel(i, me._toRad(j));
p.x -= dx;
p.y -= dy;
if (p.x > width || p.y > height || p.x < 0 || p.y < 0) {
continue;
}
var indexX = Math.floor(p.x);
var indexY = Math.floor(p.y);
if (buffer[indexY] === undefined || buffer[indexY][indexX] === undefined || buffer[indexY][indexX] === 0) {
continue;
} else {
arr.push({
amplitude: i,
phase: j
});
break;
}
}
}
return arr;
}
/**
* @function _getBoundaryGraphics
* @memberOf HitContainer
* @description Draw a polygon based on given points in polor coordinate.
* @para {Array} points in polor coordinate.
* @return {PIXI.Graphics} Polygon graphic.
*/
}, {
key: "_getBoundaryGraphics",
value: function _getBoundaryGraphics(bound) {
var _this2 = this;
var gra = new PIXI.Graphics();
gra.lineStyle(1, 0xff0000, 0);
gra.beginFill(0xff00ff, 0);
bound.forEach(function (element, index) {
var relP = _this2._polarToPixel(element.amplitude, _this2._toRad(element.phase));
if (index === 0) {
gra.moveTo(relP.x, relP.y);
} else {
gra.lineTo(relP.x, relP.y);
}
});
gra.endFill();
return gra;
}
/**
* @function initBound
* @memberOf HitContainer
* @description Prepare for hit test. This method must be done before hit test. If the boundary of container is changed. You must do it again.
* @description 预处理碰撞检测,这个方法必须在碰撞检测前调用。如果容器的边界发生了变化,需要再次调用
*/
}, {
key: "initBound",
value: function initBound(boundMatrix, bound) {
this._BoundMatrix = boundMatrix || this._caculateBoundMatrix();
this._Bound = bound || this._caculateBound(this._BoundMatrix);
this._BoundGraphics && this._BoundGraphics.destroy();
this._BoundGraphics = this._getBoundaryGraphics(this._Bound);
this.addChild(this._BoundGraphics);
}
/**
* @function isInBound
* @memberOf HitContainer
* @para {Object}A point.
* @description Determine whether a point which defined in global is in the boundary.
* @description 检测一个全局点是否在边界内
*/
}, {
key: "isInBound",
value: function isInBound(point) {
return this._BoundGraphics.containsPoint(point);
}
/**
* @function hitTest
* @memberOf HitContainer
* @para {HitContainer}Target object.
* @description Detect whether the container collides with the target area
* @description 检测容器是否碰撞了目标区域
* @return {Boolean} Collision with target area or not
*/
}, {
key: "hitTest",
value: function hitTest(target) {
var _this3 = this;
var isHit = false;
var p1 = this.getGlobalPosition();
var targetTestFun = target.isInBound || target.containsPoint;
this._Bound.some(function (element, index) {
var relP = _this3._polarToPixel(element.amplitude, element.phase * Math.PI / 180);
relP.x += p1.x;
relP.y += p1.y;
isHit = targetTestFun.call(target, relP);
if (isHit) {
return true;
}
});
if (!isHit) {
p1 = target.getGlobalPosition();
target._Bound.some(function (element, index) {
var relP = target._polarToPixel(element.amplitude, element.phase * Math.PI / 180);
relP.x += p1.x;
relP.y += p1.y;
isHit = targetTestFun.call(_this3, relP);
if (isHit) {
return true;
}
});
}
return isHit;
}
/**
* @function testHitArea
* @memberOf HitContainer
* @para {HitContainer}Target object.
* @description Detect the proportion of hit area.
* @description 检测碰撞面积比例
* @return {Number}The proportion of hit area.
*/
}, {
key: "testHitArea",
value: function testHitArea(target) {
if (!this.hitTest(target)) {
return 0;
}
var targetBound = target.getBounds();
var localBound = this.getBounds();
var maxEmptyMatrix = this._generateMaxEmptyMatrix(targetBound, localBound);
maxEmptyMatrix = this._addBoundToMatrix(maxEmptyMatrix, localBound);
var maxEmptyMatrixTarget = this._generateMaxEmptyMatrix(targetBound, localBound);
maxEmptyMatrixTarget = target._addBoundToMatrix(maxEmptyMatrixTarget, targetBound);
var hitMatrix = this._multiplyMatrix(maxEmptyMatrix, maxEmptyMatrixTarget);
var totalSurfaceArea = this._caculateSuerfaceArea(hitMatrix);
var localSurfaceArea = this._caculateSuerfaceArea(this._BoundMatrix);
return totalSurfaceArea / localSurfaceArea;
}
/**
* @function _caculateSuerfaceArea
* @memberOf HitContainer
* @para {Array}A matrix which want to be measured.
* @description Caculate the area based on pixel.
* @return {Number} Area.
*/
}, {
key: "_caculateSuerfaceArea",
value: function _caculateSuerfaceArea(matrix) {
var s = 0;
for (var i = 0; i < matrix.length; i++) {
for (var j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] !== 0 && matrix[i][j] !== undefined) {
s++;
}
}
}
return s;
}
/**
* @function _multiplyMatrix
* @memberOf HitContainer
* @para {Array} Matrix 1.
* @para {Array} Matrix 2.
* @description Matrix 1 and Matrix 2 must have same shape. The method will multiply every item in matrix 1 and 2. This is not Matrix multiplication.
* @return {Array} A new matrix which have a same shape with given matrix contains resault.
*/
}, {
key: "_multiplyMatrix",
value: function _multiplyMatrix(Matrix1, Matrix2) {
var newMatrix = [];
for (var i = 0; i < Matrix1.length; i++) {
newMatrix.push([]);
for (var j = 0; j < Matrix1[i].length; j++) {
newMatrix[i][j] = Matrix1[i][j] * Matrix2[i][j];
}
}
return newMatrix;
}
/**
* @function _addBoundToMatrix
* @memberOf HitContainer
* @para {Array} Matrix 1.
* @para {PIXI.Rectangle} localBound.
* @description Add local pixel in to a Matrix.
* @return {Array} The matrix after add the local pixel.
*/
}, {
key: "_addBoundToMatrix",
value: function _addBoundToMatrix(emptyMatrix, localBound) {
var dx = Math.floor(localBound.x - emptyMatrix.bound.x);
var dy = Math.floor(localBound.y - emptyMatrix.bound.y);
var localX = 0;
var localY = 0;
for (var i = dy; i < emptyMatrix.bound.height; i++) {
for (var j = dx; j < emptyMatrix.bound.width; j++) {
if (this._BoundMatrix[localY] === undefined || this._BoundMatrix[localY][localX] === undefined) {
continue;
}
emptyMatrix[i][j] += this._BoundMatrix[localY][localX];
localX++;
}
localX = 0;
localY++;
}
return emptyMatrix;
}
/**
* @function _generateMaxEmptyMatrix
* @memberOf HitContainer
* @para {Array} Matrix 1.
* @para {Array} Matrix 2.
* @description Caculate the smallest matrix which can contains both given matrix.
* @return {Array} An empty matrix.
*/
}, {
key: "_generateMaxEmptyMatrix",
value: function _generateMaxEmptyMatrix(bound1, bound2) {
var x = Math.min(bound1.x, bound2.x);
var y = Math.min(bound1.y, bound2.y);
var MaxX = Math.max(bound1.x + bound1.width, bound2.x + bound2.width);
var MaxY = Math.max(bound1.y + bound1.height, bound2.y + bound2.height);
var totalWidth = Math.floor(MaxX - x);
var totalHeight = Math.floor(MaxY - y);
var totalMatrix = [];
for (var i = 0; i < totalHeight; i++) {
var aRow = [];
for (var j = 0; j < totalWidth; j++) {
aRow.push(0);
}
totalMatrix.push(aRow);
}
var maxBound = new PIXI.Rectangle(x, y, totalWidth, totalHeight);
totalMatrix.bound = maxBound;
return totalMatrix;
}
}]);
return HitContainer;
}(Container);
exports.default = HitContainer;