UNPKG

phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.

388 lines (317 loc) 14.7 kB
var HexagonalWorldToTileXY = require('../../../src/tilemaps/components/HexagonalWorldToTileXY'); var Vector2 = require('../../../src/math/Vector2'); describe('Phaser.Tilemaps.Components.HexagonalWorldToTileXY', function () { var layerY; var layerX; function makeLayer (overrides) { var defaults = { baseTileWidth: 32, baseTileHeight: 32, tilemapLayer: null, staggerAxis: 'y', staggerIndex: 'odd' }; if (overrides) { for (var key in overrides) { defaults[key] = overrides[key]; } } return defaults; } function makeLayerWithTilemapLayer (overrides) { var tilemapLayer = { x: 0, y: 0, scrollFactorX: 1, scrollFactorY: 1, scaleX: 1, scaleY: 1, scene: { cameras: { main: { scrollX: 0, scrollY: 0 } } } }; if (overrides && overrides.tilemapLayer) { for (var key in overrides.tilemapLayer) { tilemapLayer[key] = overrides.tilemapLayer[key]; } } var layer = makeLayer(overrides); layer.tilemapLayer = tilemapLayer; return layer; } // ------------------------------------------------------------------------- // Return value and point argument // ------------------------------------------------------------------------- describe('return value', function () { it('should return a new Vector2 when no point is provided', function () { var layer = makeLayer(); var result = HexagonalWorldToTileXY(16, 16, true, null, null, layer); expect(result).toBeInstanceOf(Vector2); }); it('should return the point object that was passed in', function () { var layer = makeLayer(); var point = new Vector2(); var result = HexagonalWorldToTileXY(16, 16, true, point, null, layer); expect(result).toBe(point); }); it('should update the x and y properties of the provided point', function () { var layer = makeLayer(); var point = new Vector2(99, 99); HexagonalWorldToTileXY(16, 16, true, point, null, layer); expect(point.x).toBe(0); expect(point.y).toBe(0); }); }); // ------------------------------------------------------------------------- // staggerAxis 'y' — basic coordinate mapping // ------------------------------------------------------------------------- describe('staggerAxis y', function () { it('should return tile (0, 0) when world position is at the tile centre origin', function () { // worldX=16, worldY=16 is the centre of tile (0,0) for 32x32 tiles var layer = makeLayer({ staggerAxis: 'y' }); var result = HexagonalWorldToTileXY(16, 16, true, null, null, layer); expect(result.x).toBe(0); expect(result.y).toBe(0); }); it('should return tile (1, 0) when world position is one tile to the right on even row', function () { // worldX=48 is one tile width (32) past the half-width origin at 16 // py = 0, so r = 0 → y = 0 (even row) var layer = makeLayer({ staggerAxis: 'y' }); var result = HexagonalWorldToTileXY(48, 16, true, null, null, layer); expect(result.x).toBe(1); expect(result.y).toBe(0); }); it('should produce different results for staggerIndex odd vs even when row is odd', function () { // worldX=16, worldY=48 resolves to row y=1 (odd) // staggerIndex 'odd': x = (ri/2) + qi - 0.5 // staggerIndex 'even': x = (ri/2) + qi + 0.5 var layerOdd = makeLayer({ staggerAxis: 'y', staggerIndex: 'odd' }); var layerEven = makeLayer({ staggerAxis: 'y', staggerIndex: 'even' }); var resultOdd = HexagonalWorldToTileXY(16, 48, true, null, null, layerOdd); var resultEven = HexagonalWorldToTileXY(16, 48, true, null, null, layerEven); // Both should be on row y=1 expect(resultOdd.y).toBe(1); expect(resultEven.y).toBe(1); // x coordinate differs by 1 between staggerIndex modes expect(resultEven.x - resultOdd.x).toBeCloseTo(1, 10); }); it('should return the same x result for even rows regardless of staggerIndex', function () { // For even rows (y % 2 === 0) the formula is identical for both staggerIndex values var layerOdd = makeLayer({ staggerAxis: 'y', staggerIndex: 'odd' }); var layerEven = makeLayer({ staggerAxis: 'y', staggerIndex: 'even' }); var resultOdd = HexagonalWorldToTileXY(16, 16, true, null, null, layerOdd); var resultEven = HexagonalWorldToTileXY(16, 16, true, null, null, layerEven); expect(resultOdd.x).toBe(resultEven.x); expect(resultOdd.y).toBe(resultEven.y); }); }); // ------------------------------------------------------------------------- // staggerAxis 'x' — basic coordinate mapping // ------------------------------------------------------------------------- describe('staggerAxis x', function () { it('should return tile (0, 0) when world position is at the tile centre origin', function () { var layer = makeLayer({ staggerAxis: 'x' }); var result = HexagonalWorldToTileXY(16, 16, true, null, null, layer); expect(result.x).toBe(0); expect(result.y).toBe(0); }); it('should produce results using the flat-top hexagon formula', function () { // staggerAxis 'x' uses different px/py scaling than 'y' var layerX = makeLayer({ staggerAxis: 'x' }); var layerY = makeLayer({ staggerAxis: 'y' }); // At the origin both axes agree var rx = HexagonalWorldToTileXY(16, 16, true, null, null, layerX); var ry = HexagonalWorldToTileXY(16, 16, true, null, null, layerY); expect(rx.x).toBe(ry.x); expect(rx.y).toBe(ry.y); }); it('should produce different tile coordinates off-centre compared to staggerAxis y', function () { // worldX=48, worldY=32 produces (1,1) for staggerAxis 'y' and (0,1) for 'x' var layerX = makeLayer({ staggerAxis: 'x', staggerIndex: 'odd' }); var layerY = makeLayer({ staggerAxis: 'y', staggerIndex: 'odd' }); var rx = HexagonalWorldToTileXY(48, 32, true, null, null, layerX); var ry = HexagonalWorldToTileXY(48, 32, true, null, null, layerY); // The results should differ because the axis orientation changes the math var differ = (rx.x !== ry.x) || (rx.y !== ry.y); expect(differ).toBe(true); }); }); // ------------------------------------------------------------------------- // snapToFloor — present in signature, not applied in implementation // ------------------------------------------------------------------------- describe('snapToFloor parameter', function () { it('should not throw when snapToFloor is true', function () { var layer = makeLayer(); expect(function () { HexagonalWorldToTileXY(16, 16, true, null, null, layer); }).not.toThrow(); }); it('should not throw when snapToFloor is false', function () { var layer = makeLayer(); expect(function () { HexagonalWorldToTileXY(16, 16, false, null, null, layer); }).not.toThrow(); }); }); // ------------------------------------------------------------------------- // tilemapLayer — offset, scroll, scale // ------------------------------------------------------------------------- describe('with tilemapLayer', function () { it('should offset world coordinates by tilemapLayer position', function () { // tilemapLayer at (100, 100) — worldX/Y must shift by that amount to reach origin tile var layer = makeLayerWithTilemapLayer({ staggerAxis: 'y' }); layer.tilemapLayer.x = 100; layer.tilemapLayer.y = 100; var result = HexagonalWorldToTileXY(116, 116, true, null, null, layer); expect(result.x).toBe(0); expect(result.y).toBe(0); }); it('should factor in camera scroll when scrollFactor is 0', function () { // scrollFactor=0 means layer is fixed, so full camera scroll is subtracted var layer = makeLayerWithTilemapLayer({ staggerAxis: 'y' }); layer.tilemapLayer.scrollFactorX = 0; layer.tilemapLayer.scrollFactorY = 0; var camera = { scrollX: 50, scrollY: 50 }; // worldX - (0 + 50 * 1) = worldX - 50; so worldX=66 → 16 → origin var result = HexagonalWorldToTileXY(66, 66, true, null, camera, layer); expect(result.x).toBe(0); expect(result.y).toBe(0); }); it('should not apply camera scroll when scrollFactor is 1', function () { // scrollFactor=1 means the layer scrolls with the camera (1 - 1 = 0 contribution) var layer = makeLayerWithTilemapLayer({ staggerAxis: 'y' }); var camera = { scrollX: 999, scrollY: 999 }; // worldX - (0 + 999 * 0) = worldX — camera scroll has no effect var result = HexagonalWorldToTileXY(16, 16, true, null, camera, layer); expect(result.x).toBe(0); expect(result.y).toBe(0); }); it('should scale tile dimensions by tilemapLayer scale', function () { // With scaleX=scaleY=2, effective tile size is 64x64, so origin centre is at (32,32) var layer = makeLayerWithTilemapLayer({ staggerAxis: 'y' }); layer.tilemapLayer.scaleX = 2; layer.tilemapLayer.scaleY = 2; var result = HexagonalWorldToTileXY(32, 32, true, null, null, layer); expect(result.x).toBe(0); expect(result.y).toBe(0); }); it('should use scene main camera when camera argument is null', function () { // Supplying camera=null should fall back to tilemapLayer.scene.cameras.main var layer = makeLayerWithTilemapLayer({ staggerAxis: 'y' }); layer.tilemapLayer.scene.cameras.main.scrollX = 0; layer.tilemapLayer.scene.cameras.main.scrollY = 0; expect(function () { HexagonalWorldToTileXY(16, 16, true, null, null, layer); }).not.toThrow(); }); it('should use the provided camera rather than the scene main camera', function () { // Use a camera with no scroll — should still map origin to (0,0) var layer = makeLayerWithTilemapLayer({ staggerAxis: 'y' }); // Point scene camera to something that would give wrong result if used layer.tilemapLayer.scene.cameras.main.scrollX = 999; layer.tilemapLayer.scene.cameras.main.scrollY = 999; var camera = { scrollX: 0, scrollY: 0 }; var result = HexagonalWorldToTileXY(16, 16, true, null, camera, layer); expect(result.x).toBe(0); expect(result.y).toBe(0); }); }); // ------------------------------------------------------------------------- // Edge cases // ------------------------------------------------------------------------- describe('edge cases', function () { it('should handle negative world coordinates without throwing', function () { var layer = makeLayer(); expect(function () { HexagonalWorldToTileXY(-100, -100, true, null, null, layer); }).not.toThrow(); }); it('should handle zero world coordinates without throwing', function () { var layer = makeLayer(); expect(function () { HexagonalWorldToTileXY(0, 0, true, null, null, layer); }).not.toThrow(); }); it('should handle large world coordinates without throwing', function () { var layer = makeLayer(); expect(function () { HexagonalWorldToTileXY(100000, 100000, true, null, null, layer); }).not.toThrow(); }); it('should return integer or half-integer x values for staggerIndex odd on odd rows', function () { // On odd rows staggerIndex 'odd' produces x = (ri/2) + qi - 0.5 — fractional by 0.5 var layer = makeLayer({ staggerAxis: 'y', staggerIndex: 'odd' }); var result = HexagonalWorldToTileXY(16, 48, true, null, null, layer); // x should be an integer or n + 0.5 var frac = Math.abs(result.x - Math.floor(result.x)); expect(frac === 0 || frac === 0.5).toBe(true); }); it('should return integer or half-integer x values for staggerIndex even on odd rows', function () { var layer = makeLayer({ staggerAxis: 'y', staggerIndex: 'even' }); var result = HexagonalWorldToTileXY(16, 48, true, null, null, layer); var frac = Math.abs(result.x - Math.floor(result.x)); expect(frac === 0 || frac === 0.5).toBe(true); }); it('should return consistent results for identical inputs', function () { var layer = makeLayer(); var r1 = HexagonalWorldToTileXY(64, 64, true, null, null, layer); var r2 = HexagonalWorldToTileXY(64, 64, true, null, null, layer); expect(r1.x).toBe(r2.x); expect(r1.y).toBe(r2.y); }); it('should not mutate the layer object', function () { var layer = makeLayer(); var origWidth = layer.baseTileWidth; var origHeight = layer.baseTileHeight; HexagonalWorldToTileXY(16, 16, true, null, null, layer); expect(layer.baseTileWidth).toBe(origWidth); expect(layer.baseTileHeight).toBe(origHeight); }); }); });