Tilemap & layers: replace v2 raycasting with getTilesWithinShape

This commit is contained in:
Michael Hadley 2017-11-26 07:55:44 -06:00
parent 9d29948a02
commit 8ec6528d20
7 changed files with 124 additions and 0 deletions

View file

@ -310,6 +310,13 @@ var Tilemap = new Class({
return TilemapComponents.GetTilesWithin(tileX, tileY, width, height, filteringOptions, layer);
},
getTilesWithinShape: function (shape, filteringOptions, camera, layer)
{
layer = this.getLayer(layer);
if (layer === null) { return null; }
return TilemapComponents.GetTilesWithinShape(shape, filteringOptions, camera, layer);
},
getTilesWithinWorldXY: function (worldX, worldY, width, height, filteringOptions, camera, layer)
{
layer = this.getLayer(layer);

View file

@ -0,0 +1,68 @@
var GetTilesWithin = require('./GetTilesWithin');
var WorldToTileX = require('./WorldToTileX');
var WorldToTileY = require('./WorldToTileY');
var TileToWorldX = require('./TileToWorldX');
var TileToWorldY = require('./TileToWorldY');
var Geom = require('../../../geom/');
var Intersects = require('../../../geom/intersects/');
var NOOP = require('../../../utils/NOOP');
var TriangleToRectangle = function (triangle, rect)
{
return Intersects.RectangleToTriangle(rect, triangle);
};
// Circle, Line, Rect, Triangle in world coordinates.
// Notes: circle is not working yet - see CircleToRectangle in geom. Could possibly be optimized
// by copying the shape and shifting it into tilemapLayer coordinates instead of shifting the tiles.
var GetTilesWithinShape = function (shape, filteringOptions, camera, layer)
{
if (shape === undefined) { return []; }
// intersectTest is a function with parameters: shape, rect
var intersectTest = NOOP;
if (shape instanceof Geom.Circle) { intersectTest = Intersects.CircleToRectangle; }
else if (shape instanceof Geom.Rectangle) { intersectTest = Intersects.RectangleToRectangle; }
else if (shape instanceof Geom.Triangle) { intersectTest = TriangleToRectangle; }
else if (shape instanceof Geom.Line) { intersectTest = Intersects.LineToRectangle; }
// Top left corner of the shapes's bounding box, rounded down to include partial tiles
var xStart = WorldToTileX(shape.left, true, camera, layer);
var yStart = WorldToTileY(shape.top, true, camera, layer);
// Bottom right corner of the shapes's bounding box, rounded up to include partial tiles
var xEnd = Math.ceil(WorldToTileX(shape.right, false, camera, layer));
var yEnd = Math.ceil(WorldToTileY(shape.bottom, false, camera, layer));
// Tiles within bounding rectangle of shape. Bounds are forced to be at least 1 x 1 tile in size
// to grab tiles for shapes that don't have a height or width (e.g. a horizontal line).
var width = Math.max(xEnd - xStart, 1);
var height = Math.max(yEnd - yStart, 1);
var tiles = GetTilesWithin(xStart, yStart, width, height, filteringOptions, layer);
var tileWidth = layer.tileWidth;
var tileHeight = layer.tileHeight;
if (layer.tilemapLayer)
{
tileWidth *= layer.tilemapLayer.scaleX;
tileHeight *= layer.tilemapLayer.scaleY;
}
var results = [];
var tileRect = new Geom.Rectangle(0, 0, tileWidth, tileHeight);
for (var i = 0; i < tiles.length; i++)
{
var tile = tiles[i];
tileRect.x = TileToWorldX(tile.x, camera, layer);
tileRect.y = TileToWorldY(tile.y, camera, layer);
if (intersectTest(shape, tileRect))
{
results.push(tile);
}
}
return results;
};
module.exports = GetTilesWithinShape;

View file

@ -0,0 +1,19 @@
var TileToWorldX = function (tileX, camera, layer)
{
var tileWidth = layer.tileWidth;
var tilemapLayer = layer.tilemapLayer;
var layerWorldX = 0;
if (tilemapLayer)
{
if (camera === undefined) { camera = tilemapLayer.scene.cameras.main; }
layerWorldX = tilemapLayer.x - (camera.scrollX * tilemapLayer.scrollFactorX);
tileWidth *= tilemapLayer.scaleX;
}
return layerWorldX + tileX * tileWidth;
};
module.exports = TileToWorldX;

View file

@ -0,0 +1,19 @@
var TileToWorldY = function (tileY, camera, layer)
{
var tileHeight = layer.tileHeight;
var tilemapLayer = layer.tilemapLayer;
var layerWorldY = 0;
if (tilemapLayer)
{
if (camera === undefined) { camera = tilemapLayer.scene.cameras.main; }
layerWorldY = tilemapLayer.y - (camera.scrollY * tilemapLayer.scrollFactorY);
tileHeight *= tilemapLayer.scaleY;
}
return layerWorldY + tileY * tileHeight;
};
module.exports = TileToWorldY;

View file

@ -8,6 +8,7 @@ module.exports = {
GetTileAt: require('./GetTileAt'),
GetTileAtWorldXY: require('./GetTileAtWorldXY'),
GetTilesWithin: require('./GetTilesWithin'),
GetTilesWithinShape: require('./GetTilesWithinShape'),
GetTilesWithinWorldXY: require('./GetTilesWithinWorldXY'),
HasTileAt: require('./HasTileAt'),
HasTileAtWorldXY: require('./HasTileAtWorldXY'),

View file

@ -108,6 +108,11 @@ var DynamicTilemapLayer = new Class({
return TilemapComponents.GetTilesWithin(tileX, tileY, width, height, filteringOptions, this.layer);
},
getTilesWithinShape: function (shape, filteringOptions, camera)
{
return TilemapComponents.GetTilesWithinShape(shape, filteringOptions, camera, this.layer);
},
getTilesWithinWorldXY: function (worldX, worldY, width, height, filteringOptions, camera)
{
return TilemapComponents.GetTilesWithinWorldXY(worldX, worldY, width, height, filteringOptions, camera, this.layer);

View file

@ -254,6 +254,11 @@ var StaticTilemapLayer = new Class({
return TilemapComponents.GetTilesWithinWorldXY(worldX, worldY, width, height, filteringOptions, camera, this.layer);
},
getTilesWithinShape: function (shape, filteringOptions, camera)
{
return TilemapComponents.GetTilesWithinShape(shape, filteringOptions, camera, this.layer);
},
hasTileAt: function (tileX, tileY)
{
return TilemapComponents.HasTileAt(tileX, tileY, this.layer);