phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
316 lines (252 loc) • 10.5 kB
JavaScript
var GetTilesWithinShape = require('../../../src/tilemaps/components/GetTilesWithinShape');
var CONST = require('../../../src/tilemaps/const/ORIENTATION_CONST');
var Geom = require('../../../src/geom/');
describe('Phaser.Tilemaps.Components.GetTilesWithinShape', function ()
{
var layer;
var camera;
var TILE_WIDTH = 32;
var TILE_HEIGHT = 32;
var GRID_WIDTH = 5;
var GRID_HEIGHT = 5;
function createTile(x, y)
{
return { x: x, y: y, index: 1, collides: false, hasInterestingFace: false };
}
function createLayer(scaleX, scaleY)
{
if (scaleX === undefined) { scaleX = 1; }
if (scaleY === undefined) { scaleY = 1; }
var data = [];
for (var ty = 0; ty < GRID_HEIGHT; ty++)
{
data[ty] = [];
for (var tx = 0; tx < GRID_WIDTH; tx++)
{
data[ty][tx] = createTile(tx, ty);
}
}
var tilemapLayer = {
scaleX: scaleX,
scaleY: scaleY,
worldToTileXY: function (worldX, worldY, snapToFloor, point)
{
if (snapToFloor)
{
point.x = Math.floor(worldX / TILE_WIDTH);
point.y = Math.floor(worldY / TILE_HEIGHT);
}
else
{
point.x = worldX / TILE_WIDTH;
point.y = worldY / TILE_HEIGHT;
}
},
tileToWorldXY: function (tileX, tileY, point)
{
point.x = tileX * TILE_WIDTH * scaleX;
point.y = tileY * TILE_HEIGHT * scaleY;
}
};
return {
orientation: CONST.ORTHOGONAL,
tileWidth: TILE_WIDTH,
tileHeight: TILE_HEIGHT,
width: GRID_WIDTH,
height: GRID_HEIGHT,
data: data,
tilemapLayer: tilemapLayer
};
}
beforeEach(function ()
{
layer = createLayer();
camera = {};
});
it('should return an empty array when shape is undefined', function ()
{
var result = GetTilesWithinShape(undefined, {}, camera, layer);
expect(result).toEqual([]);
});
it('should return an empty array when layer orientation is ISOMETRIC', function ()
{
layer.orientation = CONST.ISOMETRIC;
var shape = new Geom.Rectangle(0, 0, 64, 64);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result).toEqual([]);
});
it('should return an empty array when layer orientation is STAGGERED', function ()
{
layer.orientation = CONST.STAGGERED;
var shape = new Geom.Rectangle(0, 0, 64, 64);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result).toEqual([]);
});
it('should return an empty array when layer orientation is HEXAGONAL', function ()
{
layer.orientation = CONST.HEXAGONAL;
var shape = new Geom.Rectangle(0, 0, 64, 64);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result).toEqual([]);
});
it('should return an array when given a valid orthogonal layer and shape', function ()
{
var shape = new Geom.Rectangle(0, 0, 32, 32);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(Array.isArray(result)).toBe(true);
});
it('should return the single tile whose bounds exactly match a Rectangle shape', function ()
{
// Rectangle(32, 32, 32, 32) covers exactly tile (1,1) in world space
var shape = new Geom.Rectangle(32, 32, 32, 32);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBe(1);
expect(result[0].x).toBe(1);
expect(result[0].y).toBe(1);
});
it('should return all tiles when a Rectangle shape covers the entire layer', function ()
{
// 5x5 grid of 32x32 tiles = 160x160 world pixels
var shape = new Geom.Rectangle(0, 0, 160, 160);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBe(25);
});
it('should return the first row of tiles for a Rectangle shape covering only row 0', function ()
{
var shape = new Geom.Rectangle(0, 0, 160, 32);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBe(5);
for (var i = 0; i < result.length; i++)
{
expect(result[i].y).toBe(0);
}
});
it('should return a single column of tiles for a Rectangle shape covering only column 0', function ()
{
var shape = new Geom.Rectangle(0, 0, 32, 160);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBe(5);
for (var i = 0; i < result.length; i++)
{
expect(result[i].x).toBe(0);
}
});
it('should return tiles intersecting a Circle centered within a tile', function ()
{
// Circle centered at world (80, 80) covers tile (2,2) which has world rect (64,64)-(96,96)
var shape = new Geom.Circle(80, 80, 16);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBeGreaterThan(0);
var tileXValues = result.map(function (t) { return t.x; });
var tileYValues = result.map(function (t) { return t.y; });
expect(tileXValues).toContain(2);
expect(tileYValues).toContain(2);
});
it('should return tiles intersecting a Circle that spans multiple tiles', function ()
{
// Large circle centered at (80, 80) with radius 64 should cover many tiles
var shape = new Geom.Circle(80, 80, 64);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBeGreaterThan(1);
});
it('should return tiles intersecting a Triangle shape', function ()
{
// Triangle covering top-left portion of the layer
var shape = new Geom.Triangle(0, 0, 64, 0, 0, 64);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBeGreaterThan(0);
});
it('should return tiles intersecting a horizontal Line shape', function ()
{
// Horizontal line at y=16 spanning x=0 to x=96 (crosses tiles (0,0), (1,0), (2,0))
var shape = new Geom.Line(0, 16, 96, 16);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBeGreaterThan(0);
for (var i = 0; i < result.length; i++)
{
expect(result[i].y).toBe(0);
}
});
it('should return tiles intersecting a diagonal Line shape', function ()
{
// Diagonal line from (0,0) to (128,128) - should cross multiple tiles
var shape = new Geom.Line(0, 0, 128, 128);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBeGreaterThan(1);
});
it('should return tiles intersecting a vertical Line shape', function ()
{
// Vertical line at x=16 spanning y=0 to y=96 (crosses tiles in column 0, rows 0-2)
var shape = new Geom.Line(16, 0, 16, 96);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBeGreaterThan(0);
for (var i = 0; i < result.length; i++)
{
expect(result[i].x).toBe(0);
}
});
it('should return an empty array when shape is outside the layer bounds', function ()
{
// Shape far outside the 5x5 grid (160x160 world pixels)
var shape = new Geom.Rectangle(1000, 1000, 32, 32);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result).toEqual([]);
});
it('should return tile objects with x and y properties', function ()
{
var shape = new Geom.Rectangle(0, 0, 32, 32);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBeGreaterThan(0);
expect(result[0].x).toBeDefined();
expect(result[0].y).toBeDefined();
});
it('should return an empty array for an object that is not a recognised Geom shape', function ()
{
// Plain object with bounding box properties but no Geom prototype —
// intersectTest will remain NOOP (returns undefined/falsy), so nothing passes
var shape = { left: 0, top: 0, right: 64, bottom: 64 };
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result).toEqual([]);
});
it('should account for tilemapLayer scaleX and scaleY when building tile rects', function ()
{
// Scale up tiles 2x: each tile is now 64x64 in world space
layer = createLayer(2, 2);
// Rectangle covering the large scaled tile at (0,0) → world rect (0,0)-(64,64)
var shape = new Geom.Rectangle(0, 0, 64, 64);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result.length).toBeGreaterThan(0);
});
it('should respect isNotEmpty filtering option and skip empty tiles', function ()
{
// Mark all tiles as empty (index -1)
for (var ty = 0; ty < GRID_HEIGHT; ty++)
{
for (var tx = 0; tx < GRID_WIDTH; tx++)
{
layer.data[ty][tx].index = -1;
}
}
var shape = new Geom.Rectangle(0, 0, 160, 160);
var result = GetTilesWithinShape(shape, { isNotEmpty: true }, camera, layer);
expect(result).toEqual([]);
});
it('should respect isColliding filtering option and only return colliding tiles', function ()
{
// Mark only tile (0,0) as colliding
layer.data[0][0].collides = true;
var shape = new Geom.Rectangle(0, 0, 64, 32);
var result = GetTilesWithinShape(shape, { isColliding: true }, camera, layer);
expect(result.length).toBe(1);
expect(result[0].x).toBe(0);
expect(result[0].y).toBe(0);
});
it('should return tiles containing null entries as non-results', function ()
{
// Set tile (0,0) to null — GetTilesWithin skips null tiles
layer.data[0][0] = null;
var shape = new Geom.Rectangle(0, 0, 32, 32);
var result = GetTilesWithinShape(shape, {}, camera, layer);
expect(result).toEqual([]);
});
});