phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
301 lines (246 loc) • 9.14 kB
JavaScript
var GetTilesWithinWorldXY = require('../../../src/tilemaps/components/GetTilesWithinWorldXY');
function createMockTile (index)
{
return {
index: index !== undefined ? index : 1,
collides: false,
hasInterestingFace: false
};
}
function createMockLayerData (width, height)
{
var data = [];
for (var y = 0; y < height; y++)
{
data[y] = [];
for (var x = 0; x < width; x++)
{
data[y][x] = createMockTile(1);
}
}
return data;
}
describe('Phaser.Tilemaps.Components.GetTilesWithinWorldXY', function ()
{
var mockLayer;
var mockCamera;
var mockFilteringOptions;
var worldToTileXYSpy;
beforeEach(function ()
{
worldToTileXYSpy = vi.fn(function (wx, wy, snap, point, camera, layer)
{
if (snap === true)
{
point.x = Math.floor(wx / 32);
point.y = Math.floor(wy / 32);
}
else
{
point.x = wx / 32;
point.y = wy / 32;
}
});
mockLayer = {
width: 20,
height: 20,
data: createMockLayerData(20, 20),
tilemapLayer: {
tilemap: {
_convert: {
WorldToTileXY: worldToTileXYSpy
}
}
}
};
mockCamera = {};
mockFilteringOptions = {};
});
it('should call WorldToTileXY twice', function ()
{
GetTilesWithinWorldXY(0, 0, 64, 64, mockFilteringOptions, mockCamera, mockLayer);
expect(worldToTileXYSpy).toHaveBeenCalledTimes(2);
});
it('should call WorldToTileXY first with snap=true for top-left corner', function ()
{
GetTilesWithinWorldXY(32, 64, 64, 64, mockFilteringOptions, mockCamera, mockLayer);
var firstCall = worldToTileXYSpy.mock.calls[0];
expect(firstCall[0]).toBe(32);
expect(firstCall[1]).toBe(64);
expect(firstCall[2]).toBe(true);
});
it('should call WorldToTileXY second with snap=false for bottom-right corner', function ()
{
GetTilesWithinWorldXY(32, 64, 64, 64, mockFilteringOptions, mockCamera, mockLayer);
var secondCall = worldToTileXYSpy.mock.calls[1];
expect(secondCall[0]).toBe(32 + 64);
expect(secondCall[1]).toBe(64 + 64);
expect(secondCall[2]).toBe(false);
});
it('should pass the camera to WorldToTileXY calls', function ()
{
GetTilesWithinWorldXY(0, 0, 64, 64, mockFilteringOptions, mockCamera, mockLayer);
expect(worldToTileXYSpy.mock.calls[0][4]).toBe(mockCamera);
expect(worldToTileXYSpy.mock.calls[1][4]).toBe(mockCamera);
});
it('should pass the layer to WorldToTileXY calls', function ()
{
GetTilesWithinWorldXY(0, 0, 64, 64, mockFilteringOptions, mockCamera, mockLayer);
expect(worldToTileXYSpy.mock.calls[0][5]).toBe(mockLayer);
expect(worldToTileXYSpy.mock.calls[1][5]).toBe(mockLayer);
});
it('should return an array', function ()
{
var result = GetTilesWithinWorldXY(0, 0, 64, 64, mockFilteringOptions, mockCamera, mockLayer);
expect(Array.isArray(result)).toBe(true);
});
it('should return tiles within the specified world area', function ()
{
// worldX=0, worldY=0, width=64, height=64 with tileSize=32
// -> tile 0,0 to 2,2 => a 2x2 area of tiles
var result = GetTilesWithinWorldXY(0, 0, 64, 64, mockFilteringOptions, mockCamera, mockLayer);
expect(result.length).toBe(4);
});
it('should return a single tile for a single-tile-sized area', function ()
{
var result = GetTilesWithinWorldXY(0, 0, 32, 32, mockFilteringOptions, mockCamera, mockLayer);
expect(result.length).toBe(1);
});
it('should return empty array when area has zero width', function ()
{
var result = GetTilesWithinWorldXY(0, 0, 0, 64, mockFilteringOptions, mockCamera, mockLayer);
expect(result.length).toBe(0);
});
it('should return empty array when area has zero height', function ()
{
var result = GetTilesWithinWorldXY(0, 0, 64, 0, mockFilteringOptions, mockCamera, mockLayer);
expect(result.length).toBe(0);
});
it('should pass worldX + width as x coordinate of second WorldToTileXY call', function ()
{
var worldX = 100;
var worldY = 200;
var width = 150;
var height = 250;
GetTilesWithinWorldXY(worldX, worldY, width, height, mockFilteringOptions, mockCamera, mockLayer);
var secondCall = worldToTileXYSpy.mock.calls[1];
expect(secondCall[0]).toBe(worldX + width);
expect(secondCall[1]).toBe(worldY + height);
});
it('should ceil the bottom-right tile coordinate for partial tiles', function ()
{
// Set up mock where bottom-right returns a fractional tile position
worldToTileXYSpy.mockImplementation(function (wx, wy, snap, point)
{
if (snap === true)
{
point.x = 1;
point.y = 1;
}
else
{
// Fractional: ceil(1.1) = 2, ceil(1.1) = 2
// So we expect a 1x1 area (2-1=1, 2-1=1)
point.x = 1.1;
point.y = 1.1;
}
});
var result = GetTilesWithinWorldXY(32, 32, 35, 35, mockFilteringOptions, mockCamera, mockLayer);
// xStart=1, yStart=1, xEnd=ceil(1.1)=2, yEnd=ceil(1.1)=2
// width = 2-1 = 1, height = 2-1 = 1
expect(result.length).toBe(1);
});
it('should include partial tiles on the right and bottom edges', function ()
{
// End coords land exactly on a tile boundary (no partial)
worldToTileXYSpy.mockImplementation(function (wx, wy, snap, point)
{
if (snap === true)
{
point.x = 0;
point.y = 0;
}
else
{
// Exactly 3.0 — ceil(3.0) = 3
point.x = 3.0;
point.y = 3.0;
}
});
var result = GetTilesWithinWorldXY(0, 0, 96, 96, mockFilteringOptions, mockCamera, mockLayer);
// width = ceil(3.0) - 0 = 3, height = 3
expect(result.length).toBe(9);
});
it('should filter out empty tiles when isNotEmpty is set', function ()
{
mockLayer.data[0][0].index = -1;
mockLayer.data[0][1].index = -1;
var result = GetTilesWithinWorldXY(0, 0, 64, 32, { isNotEmpty: true }, mockCamera, mockLayer);
for (var i = 0; i < result.length; i++)
{
expect(result[i].index).not.toBe(-1);
}
});
it('should filter tiles by collision when isColliding is set', function ()
{
mockLayer.data[0][0].collides = true;
mockLayer.data[0][1].collides = false;
var result = GetTilesWithinWorldXY(0, 0, 64, 32, { isColliding: true }, mockCamera, mockLayer);
for (var i = 0; i < result.length; i++)
{
expect(result[i].collides).toBe(true);
}
});
it('should handle null tiles in layer data gracefully', function ()
{
mockLayer.data[0][0] = null;
var result = GetTilesWithinWorldXY(0, 0, 64, 32, mockFilteringOptions, mockCamera, mockLayer);
expect(Array.isArray(result)).toBe(true);
// null tiles should not be included
for (var i = 0; i < result.length; i++)
{
expect(result[i]).not.toBeNull();
}
});
it('should clamp results to layer boundaries when area extends beyond layer', function ()
{
// Request tiles starting at tile 18,18 with a large area
worldToTileXYSpy.mockImplementation(function (wx, wy, snap, point)
{
if (snap === true)
{
point.x = 18;
point.y = 18;
}
else
{
point.x = 25;
point.y = 25;
}
});
var result = GetTilesWithinWorldXY(576, 576, 224, 224, mockFilteringOptions, mockCamera, mockLayer);
// Layer is 20x20 tiles, so only tiles 18,18 to 19,19 should be returned
expect(result.length).toBe(4);
});
it('should return tiles from correct tile coordinates derived from world coords', function ()
{
// Mark a specific tile so we can identify it in results
mockLayer.data[2][3].index = 99;
worldToTileXYSpy.mockImplementation(function (wx, wy, snap, point)
{
if (snap === true)
{
point.x = 3;
point.y = 2;
}
else
{
point.x = 4;
point.y = 3;
}
});
var result = GetTilesWithinWorldXY(96, 64, 32, 32, mockFilteringOptions, mockCamera, mockLayer);
expect(result.length).toBe(1);
expect(result[0].index).toBe(99);
});
});