UNPKG

phaser-raycaster

Version:
281 lines (241 loc) 11.7 kB
/*Map methods for containers*/ /** * Get array of mapped container's and its children vertices used as rays targets. * * @method Raycaster.Map#container.getPoints * @memberof Raycaster.Map * @instance * @private * @since 0.7.1 * * @param {Raycaster.Ray} [ray] - {Raycaster.Ray} object used in some some types of maps. * @param {boolean} [isChild] - Flag definig if it is child container. * * @return {Phaser.Geom.Point[]} - Array of mapped object's vertices. */ export function getPoints(ray = false, isChild = false) { if(!this.active) return []; let points = this._points; //calculate offset based on container position and origin point let offset = new Phaser.Geom.Point(); offset.x = this.object.x - this.object.displayWidth * this.object.originX; offset.y = this.object.y - this.object.displayHeight * this.object.originY; //get tangent points of container's circles if(this.segmentCount == 0 && !isChild) { if(ray) { //create temporary ray let vector = new Phaser.Geom.Line(0, 0, ray.origin.x - offset.x, ray.origin.y - offset.y); Phaser.Geom.Line.SetToAngle(vector, 0, 0, Phaser.Geom.Line.Angle(vector) - this.object.rotation, Phaser.Geom.Line.Length(vector)); //calculate tangent rays let rayA = new Phaser.Geom.Line(), rayB = new Phaser.Geom.Line(), c; for(let circle of this._circles) { circle.points = []; c = new Phaser.Geom.Line(ray.origin.x, ray.origin.y, circle.x, circle.y); let rayLength = Math.sqrt(Math.pow(Phaser.Geom.Line.Length(c), 2) - Math.pow(circle.radius, 2)); //ray angle let angle = Phaser.Geom.Line.Angle(c); let dAngle = Math.asin((circle.radius) / Phaser.Geom.Line.Length(c)); Phaser.Geom.Line.SetToAngle(rayA, ray.origin.x, ray.origin.y, angle - dAngle, rayLength); Phaser.Geom.Line.SetToAngle(rayB, ray.origin.x, ray.origin.y, angle + dAngle, rayLength); //adding tangent points circle.points.push(rayA.getPointB()); circle.points.push(rayB.getPointB()); points.push(rayA.getPointB()); points.push(rayB.getPointB()); } } } return points; }; /** * Get array of mapped container's and its children segments used to test object's intersection with ray. * * @method Raycaster.Map#container.getSegments * @memberof Raycaster.Map * @instance * @private * @since 0.7.1 * * @return {Phaser.Geom.Line[]} - Array of mapped object's segments. */ export function getSegments() { if(!this.active) return []; return this._segments; }; /** * Update container's and its children maps of points and segments. * * @method Raycaster.Map#container.updateMap * @memberof Raycaster.Map * @instance * @private * @since 0.7.1 * * @return {Raycaster.Map} {@link Raycaster.Map Raycaster.Map} instance */ export function updateMap() { if(!this.active) return this; let points = []; let segments = []; let container = this.object; this._circles = []; //calculate offset based on container position and origin point let offset = new Phaser.Geom.Point(); offset.x = this.object.x - this.object.displayWidth * this.object.originX; offset.y = this.object.y - this.object.displayHeight * this.object.originY; let rotation = container.rotation; if(this.mapChild) { this._updateChildMap(this.mapChild, points, segments, rotation, offset); } else { //iterate through container's children container.iterate(function(child){ this._updateChildMap(child, points, segments, rotation, offset); }.bind(this)); //get children intersections for(let i = 0, iLength = container.list.length; i < iLength; i++){ let childA = container.list[i]; let mapA = childA.data.get('raycasterMap'); if(!mapA) continue; for(let j = i+1, jLength = container.list.length; j < jLength; j++){ let childB = container.list[j]; let mapB = childB.data.get('raycasterMap'); //check if bounding boxes overlap if(!mapB || !Phaser.Geom.Intersects.RectangleToRectangle(childA.getBounds(), childB.getBounds())) continue; //find objects intersections for(let segmentA of mapA.getSegments()) { for(let segmentB of mapB.getSegments()) { let intersection = []; if(!Phaser.Geom.Intersects.LineToLine(segmentA, segmentB, intersection)) continue; //calculate positions after container's rotation if(rotation !== 0) { let vector = new Phaser.Geom.Line(container.x, container.y, intersection.x * container.scaleX + offset.x, intersection.y * container.scaleY + offset.y); Phaser.Geom.Line.SetToAngle(vector, this.object.x, this.object.y, Phaser.Geom.Line.Angle(vector) + rotation, Phaser.Geom.Line.Length(vector)); points.push(vector.getPointB()); } //if rotation === 0 else points.push(new Phaser.Geom.Point(intersection.x * container.scaleX + offset.x, intersection.y * container.scaleX + offset.y)); } } } } } this._points = points; this._segments = segments; return this; }; /** * Update container's child map of points and segments. * * @method Raycaster.Map#container._updateChildMap * @memberof Raycaster.Map * @instance * @private * @since 0.10.3 * * @param {object} [child] - Container's child object. * @param {Phaser.Geom.Point[]} [points] - Container's mapped points. * @param {Phaser.Geom.Line[]} [segments] - Container's mapped segments. * @param {number} [rotation] - Container's rotation. * @param {Phaser.Geom.Point} [offset] - Container's offset. */ export function _updateChildMap(child, points, segments, rotation, offset) { if(!child.data) child.setDataEnabled(); //if object is not supported if(child.data.get('raycasterMapNotSupported')) return; //get child map let map = child.data.get('raycasterMap'); if(!map) { map = new this.constructor({ object: child, segmentCount: this.segmentCount }); if(map.notSupported) { map.destroy(); child.data.set('raycasterMapNotSupported', true); return; } child.data.set('raycasterMap', map); } else map.updateMap(); //add child points let childPoints = []; for(let point of map.getPoints(false, true)) { let childPoint; //calculate positions after container's rotation if(rotation !== 0) { let vector = new Phaser.Geom.Line(this.object.x, this.object.y, point.x * this.object.scaleX + offset.x, point.y * this.object.scaleY + offset.y); Phaser.Geom.Line.SetToAngle(vector, this.object.x, this.object.y, Phaser.Geom.Line.Angle(vector) + rotation, Phaser.Geom.Line.Length(vector)); childPoint = vector.getPointB(); } //if rotation === 0 else childPoint = new Phaser.Geom.Point(point.x * this.object.scaleX + offset.x, point.y * this.object.scaleX + offset.y); //add neighbour points childPoint.neighbours = []; if(childPoints.length > 0) { let previousPoint = childPoints.slice(-1)[0]; previousPoint.neighbours.push(childPoint); childPoint.neighbours.push(previousPoint); } childPoints.push(childPoint); points.push(childPoint); } //add neighbour point to last child point if(childPoints.length > 0) { childPoints.slice(-1)[0].neighbours.push(childPoints[0]); } //add child segments for(let segment of map.getSegments()) { //calculate positions after container's rotation if(rotation !== 0) { let pointA = segment.getPointA(); let pointB = segment.getPointB(); let vectorA = new Phaser.Geom.Line(this.object.x, this.object.y, pointA.x * this.object.scaleX + offset.x, pointA.y * this.object.scaleY + offset.y); let vectorB = new Phaser.Geom.Line(this.object.x, this.object.y, pointB.x * this.object.scaleX + offset.x, pointB.y * this.object.scaleY + offset.y); Phaser.Geom.Line.SetToAngle(vectorA, this.object.x, this.object.y, Phaser.Geom.Line.Angle(vectorA) + rotation, Phaser.Geom.Line.Length(vectorA)); Phaser.Geom.Line.SetToAngle(vectorB, this.object.x, this.object.y, Phaser.Geom.Line.Angle(vectorB) + rotation, Phaser.Geom.Line.Length(vectorB)); segments.push(new Phaser.Geom.Line(vectorA.getPointB().x, vectorA.getPointB().y, vectorB.getPointB().x, vectorB.getPointB().y)); } //if rotation === 0 else segments.push(new Phaser.Geom.Line(segment.getPointA().x * this.object.scaleX + offset.x, segment.getPointA().y * this.object.scaleY + offset.y, segment.getPointB().x * this.object.scaleX + offset.x, segment.getPointB().y * this.object.scaleY + offset.y)); } //if child's map is a circle and this.segmentsCount == 0, store transformed circles in this._circles array. if(map.type == 'Arc' && this.segmentCount == 0) { let circleOffset = new Phaser.Geom.Point(); circleOffset.x = (map.object.x - map.object.displayWidth * (map.object.originX - 0.5)) * this.object.scaleX + offset.x; circleOffset.y = (map.object.y - map.object.displayHeight * (map.object.originY - 0.5)) * this.object.scaleY + offset.y; if(rotation !== 0) { let vector = new Phaser.Geom.Line(this.object.x, this.object.y, circleOffset.x, circleOffset.y) Phaser.Geom.Line.SetToAngle(vector, this.object.x, this.object.y, Phaser.Geom.Line.Angle(vector) + rotation, Phaser.Geom.Line.Length(vector)); circleOffset = vector.getPointB(); } this._circles.push(new Phaser.Geom.Circle(circleOffset.x, circleOffset.y, map.object.radius * map.object.scaleX * this.object.scaleX)); } else if(map.type === 'Container') { for(let childMapCircle of map._circles) { let circleOffset = new Phaser.Geom.Point(); circleOffset.x = childMapCircle.x * this.object.scaleX + offset.x; circleOffset.y = childMapCircle.y * this.object.scaleY + offset.y; if(rotation !== 0) { let vector = new Phaser.Geom.Line(this.object.x, this.object.y, circleOffset.x, circleOffset.y) Phaser.Geom.Line.SetToAngle(vector, this.object.x, this.object.y, Phaser.Geom.Line.Angle(vector) + rotation, Phaser.Geom.Line.Length(vector)); circleOffset = vector.getPointB(); } this._circles.push(new Phaser.Geom.Circle(circleOffset.x, circleOffset.y, childMapCircle.radius * this.object.scaleX)); } } }