phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
365 lines (320 loc) • 15.3 kB
JavaScript
var SpriteSheet = require('../../../src/textures/parsers/SpriteSheet');
describe('Phaser.Textures.Parsers.SpriteSheet', function ()
{
var texture;
var calls;
function makeMockTexture (sourceWidth, sourceHeight)
{
calls = [];
return {
key: 'testTexture',
source: [ { width: sourceWidth || 256, height: sourceHeight || 256 } ],
add: function (name, sourceIndex, x, y, w, h)
{
calls.push({ name: name, sourceIndex: sourceIndex, x: x, y: y, w: w, h: h });
}
};
}
beforeEach(function ()
{
texture = makeMockTexture(256, 256);
});
// -------------------------------------------------------------------------
// Error handling
// -------------------------------------------------------------------------
it('should throw an error when frameWidth is not provided', function ()
{
expect(function ()
{
SpriteSheet(texture, 0, 0, 0, 256, 256, {});
}).toThrow('TextureManager.SpriteSheet: Invalid frameWidth given.');
});
it('should throw an error when config has no frameWidth property', function ()
{
expect(function ()
{
SpriteSheet(texture, 0, 0, 0, 256, 256, { frameHeight: 32 });
}).toThrow('TextureManager.SpriteSheet: Invalid frameWidth given.');
});
// -------------------------------------------------------------------------
// Return value
// -------------------------------------------------------------------------
it('should return the texture object', function ()
{
var result = SpriteSheet(texture, 0, 0, 0, 256, 256, { frameWidth: 32 });
expect(result).toBe(texture);
});
// -------------------------------------------------------------------------
// __BASE frame
// -------------------------------------------------------------------------
it('should add a __BASE entry using the source dimensions', function ()
{
texture = makeMockTexture(512, 128);
SpriteSheet(texture, 0, 0, 0, 512, 128, { frameWidth: 32 });
var base = calls.find(function (c) { return c.name === '__BASE'; });
expect(base).toBeDefined();
expect(base.x).toBe(0);
expect(base.y).toBe(0);
expect(base.w).toBe(512);
expect(base.h).toBe(128);
expect(base.sourceIndex).toBe(0);
});
it('should use the correct sourceIndex for __BASE', function ()
{
texture = { key: 'multi', source: [ {}, { width: 64, height: 64 } ], add: function (n, si, x, y, w, h) { calls.push({ name: n, sourceIndex: si }); } };
SpriteSheet(texture, 1, 0, 0, 64, 64, { frameWidth: 32 });
var base = calls.find(function (c) { return c.name === '__BASE'; });
expect(base.sourceIndex).toBe(1);
});
// -------------------------------------------------------------------------
// Frame count (basic grids)
// -------------------------------------------------------------------------
it('should add the correct number of frames for a simple 2x2 grid', function ()
{
// 64x64 sheet, 32x32 frames => 2 cols * 2 rows = 4 frames
texture = makeMockTexture(64, 64);
SpriteSheet(texture, 0, 0, 0, 64, 64, { frameWidth: 32 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(4);
});
it('should add the correct number of frames for a 4x2 grid', function ()
{
// 128 wide / 32 = 4 cols, 64 tall / 32 = 2 rows = 8 frames
texture = makeMockTexture(128, 64);
SpriteSheet(texture, 0, 0, 0, 128, 64, { frameWidth: 32 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(8);
});
it('should number frames starting from 0', function ()
{
texture = makeMockTexture(64, 32);
SpriteSheet(texture, 0, 0, 0, 64, 32, { frameWidth: 32 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames[0].name).toBe(0);
expect(frames[1].name).toBe(1);
});
// -------------------------------------------------------------------------
// frameHeight defaults to frameWidth
// -------------------------------------------------------------------------
it('should use frameWidth as frameHeight when frameHeight is not provided', function ()
{
// 64 wide / 32 = 2 cols, 64 tall / 32 = 2 rows = 4 frames
texture = makeMockTexture(64, 64);
SpriteSheet(texture, 0, 0, 0, 64, 64, { frameWidth: 32 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(4);
expect(frames[0].h).toBe(32);
});
it('should use explicit frameHeight when provided', function ()
{
// 64 wide / 32 = 2 cols, 64 tall / 16 = 4 rows = 8 frames
texture = makeMockTexture(64, 64);
SpriteSheet(texture, 0, 0, 0, 64, 64, { frameWidth: 32, frameHeight: 16 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(8);
expect(frames[0].w).toBe(32);
expect(frames[0].h).toBe(16);
});
// -------------------------------------------------------------------------
// Frame positions
// -------------------------------------------------------------------------
it('should place frames at correct x/y positions', function ()
{
// 64x64, 32x32 frames => frames at (0,0), (32,0), (0,32), (32,32)
texture = makeMockTexture(64, 64);
SpriteSheet(texture, 0, 0, 0, 64, 64, { frameWidth: 32 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames[0].x).toBe(0);
expect(frames[0].y).toBe(0);
expect(frames[1].x).toBe(32);
expect(frames[1].y).toBe(0);
expect(frames[2].x).toBe(0);
expect(frames[2].y).toBe(32);
expect(frames[3].x).toBe(32);
expect(frames[3].y).toBe(32);
});
it('should offset frame positions by the x/y parameters', function ()
{
texture = makeMockTexture(128, 128);
SpriteSheet(texture, 0, 10, 20, 64, 64, { frameWidth: 32 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames[0].x).toBe(10);
expect(frames[0].y).toBe(20);
expect(frames[1].x).toBe(42);
expect(frames[1].y).toBe(20);
});
// -------------------------------------------------------------------------
// margin
// -------------------------------------------------------------------------
it('should account for margin when placing frames', function ()
{
// 66x66, 32x32 frames, margin 2
// row = floor((66 - 2 + 0) / (32 + 0)) = floor(64/32) = 2
// col = floor((66 - 2 + 0) / (32 + 0)) = 2 => 4 frames
// first frame at (margin, margin) = (2, 2)
texture = makeMockTexture(66, 66);
SpriteSheet(texture, 0, 0, 0, 66, 66, { frameWidth: 32, margin: 2 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames[0].x).toBe(2);
expect(frames[0].y).toBe(2);
});
it('should reduce frame count when margin eats into available space', function ()
{
// 64x64, 32x32 frames, margin 1
// row = floor((64 - 1 + 0) / 32) = floor(63/32) = 1
// col = 1 => total = 1
texture = makeMockTexture(64, 64);
SpriteSheet(texture, 0, 0, 0, 64, 64, { frameWidth: 32, margin: 1 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(1);
});
// -------------------------------------------------------------------------
// spacing
// -------------------------------------------------------------------------
it('should account for spacing between frames', function ()
{
// 66x32, 32x32 frames, spacing 2
// row = floor((66 - 0 + 2) / (32 + 2)) = floor(68/34) = 2
// col = floor((32 - 0 + 2) / (32 + 2)) = floor(34/34) = 1 => total 2
// frame 0 at (0,0), frame 1 at (34,0)
texture = makeMockTexture(66, 32);
SpriteSheet(texture, 0, 0, 0, 66, 32, { frameWidth: 32, spacing: 2 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(2);
expect(frames[0].x).toBe(0);
expect(frames[1].x).toBe(34);
});
// -------------------------------------------------------------------------
// startFrame
// -------------------------------------------------------------------------
it('should start from frame 0 by default', function ()
{
texture = makeMockTexture(64, 32);
SpriteSheet(texture, 0, 0, 0, 64, 32, { frameWidth: 32 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(2);
expect(frames[0].name).toBe(0);
});
it('should skip frames before startFrame', function ()
{
// 128x32, 32x32 => 4 frames. startFrame=2 => frames 2,3 added
texture = makeMockTexture(128, 32);
SpriteSheet(texture, 0, 0, 0, 128, 32, { frameWidth: 32, startFrame: 2 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(2);
// counter c starts at 0 even when startFrame skips
expect(frames[0].name).toBe(0);
});
it('should reset startFrame to 0 when startFrame exceeds total', function ()
{
// 64x32, 32x32 => 2 frames. startFrame=99 => reset to 0 => all 2 frames
texture = makeMockTexture(64, 32);
SpriteSheet(texture, 0, 0, 0, 64, 32, { frameWidth: 32, startFrame: 99 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(2);
});
it('should support negative startFrame as an offset from end', function ()
{
// 128x32, 32x32 => 4 frames. startFrame=-1 => total+(-1)=3 => only frame index 3
texture = makeMockTexture(128, 32);
SpriteSheet(texture, 0, 0, 0, 128, 32, { frameWidth: 32, startFrame: -1 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(1);
});
it('should reset startFrame to 0 when negative startFrame exceeds total in magnitude', function ()
{
// 64x32 => 2 frames. startFrame=-99 => reset to 0 => all 2 frames
texture = makeMockTexture(64, 32);
SpriteSheet(texture, 0, 0, 0, 64, 32, { frameWidth: 32, startFrame: -99 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(2);
});
// -------------------------------------------------------------------------
// endFrame
// -------------------------------------------------------------------------
it('should include all frames when endFrame is -1 (default)', function ()
{
texture = makeMockTexture(128, 32);
SpriteSheet(texture, 0, 0, 0, 128, 32, { frameWidth: 32, endFrame: -1 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(4);
});
it('should limit frames to endFrame', function ()
{
// 128x32, 32x32 => 4 frames. endFrame=2 => frames 0,1,2
texture = makeMockTexture(128, 32);
SpriteSheet(texture, 0, 0, 0, 128, 32, { frameWidth: 32, endFrame: 2 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(3);
});
it('should reset endFrame to total when endFrame exceeds total', function ()
{
texture = makeMockTexture(64, 32);
SpriteSheet(texture, 0, 0, 0, 64, 32, { frameWidth: 32, endFrame: 999 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(2);
});
it('should reset endFrame to total when endFrame is less than startFrame', function ()
{
// startFrame=2, endFrame=1 => endFrame reset to total=4 => frames 2,3,4
texture = makeMockTexture(128, 32);
SpriteSheet(texture, 0, 0, 0, 128, 32, { frameWidth: 32, startFrame: 2, endFrame: 1 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(2);
});
// -------------------------------------------------------------------------
// Zero frames warning
// -------------------------------------------------------------------------
it('should warn when frame dimensions result in zero frames', function ()
{
var warnSpy = vi.spyOn(console, 'warn').mockImplementation(function () {});
texture = makeMockTexture(16, 16);
SpriteSheet(texture, 0, 0, 0, 16, 16, { frameWidth: 32 });
expect(warnSpy).toHaveBeenCalledWith(
'SpriteSheet frame dimensions will result in zero frames for texture:',
'testTexture'
);
warnSpy.mockRestore();
});
it('should not add any numbered frames when total is zero', function ()
{
var warnSpy = vi.spyOn(console, 'warn').mockImplementation(function () {});
texture = makeMockTexture(16, 16);
SpriteSheet(texture, 0, 0, 0, 16, 16, { frameWidth: 32 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(0);
warnSpy.mockRestore();
});
// -------------------------------------------------------------------------
// Combined margin + spacing
// -------------------------------------------------------------------------
it('should correctly handle both margin and spacing together', function ()
{
// margin=2, spacing=2, frameWidth=32
// row = floor((70 - 2 + 2) / (32 + 2)) = floor(70/34) = 2
// col = floor((36 - 2 + 2) / (32 + 2)) = floor(36/34) = 1 => total 2
// frame 0 at (2, 2), frame 1 at (2+32+2=36, 2) => but 36+32 > 70? 68<=70 ok
texture = makeMockTexture(70, 36);
SpriteSheet(texture, 0, 0, 0, 70, 36, { frameWidth: 32, margin: 2, spacing: 2 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
expect(frames.length).toBe(2);
expect(frames[0].x).toBe(2);
expect(frames[0].y).toBe(2);
expect(frames[1].x).toBe(36);
expect(frames[1].y).toBe(2);
});
// -------------------------------------------------------------------------
// Frame dimensions are correct
// -------------------------------------------------------------------------
it('should use frameWidth and frameHeight for frame dimensions', function ()
{
texture = makeMockTexture(64, 48);
SpriteSheet(texture, 0, 0, 0, 64, 48, { frameWidth: 32, frameHeight: 16 });
var frames = calls.filter(function (c) { return c.name !== '__BASE'; });
frames.forEach(function (f)
{
expect(f.w).toBe(32);
expect(f.h).toBe(16);
});
});
});