phaser
Version:
A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.
628 lines (490 loc) • 20.2 kB
JavaScript
vi.mock('../../../src/device/OS', function ()
{
return {
desktop: false,
cordova: false,
crosswalk: false,
electron: false,
ejecta: false,
iOS: false,
iOSVersion: 0,
iPad: false,
iPhone: false,
kindle: false,
linux: false,
macOS: false,
node: false,
nodeWebkit: false,
pixelRatio: 1,
webApp: false,
windows: false,
windowsPhone: false
};
});
vi.mock('../../../src/gameobjects/group/Group', function ()
{
function MockGroup (scene, children, config) {}
MockGroup.prototype.getChildren = function () { return []; };
return MockGroup;
});
vi.mock('../../../src/physics/arcade/ArcadeSprite', function ()
{
function MockArcadeSprite () {}
return MockArcadeSprite;
});
var CONST = require('../../../src/physics/arcade/const');
var PhysicsGroup = require('../../../src/physics/arcade/PhysicsGroup');
describe('PhysicsGroup', function ()
{
var proto = PhysicsGroup.prototype;
function makeMockWorld ()
{
return {
enableBody: vi.fn(),
disableBody: vi.fn()
};
}
function makeMockBody (physicsType)
{
if (physicsType === undefined) { physicsType = CONST.DYNAMIC_BODY; }
return {
physicsType: physicsType,
velocity: { x: 0, y: 0, set: vi.fn(function (x, y) { this.x = x; this.y = y; }) },
destroy: vi.fn(),
setCollideWorldBounds: vi.fn(),
setBoundsRectangle: vi.fn(),
setAccelerationX: vi.fn(),
setAccelerationY: vi.fn(),
setAllowDrag: vi.fn(),
setAllowGravity: vi.fn(),
setAllowRotation: vi.fn(),
setDamping: vi.fn(),
setBounceX: vi.fn(),
setBounceY: vi.fn(),
setDragX: vi.fn(),
setDragY: vi.fn(),
setEnable: vi.fn(),
setGravityX: vi.fn(),
setGravityY: vi.fn(),
setFrictionX: vi.fn(),
setFrictionY: vi.fn(),
setMaxSpeed: vi.fn(),
setMaxVelocityX: vi.fn(),
setMaxVelocityY: vi.fn(),
setVelocityX: vi.fn(),
setVelocityY: vi.fn(),
setAngularVelocity: vi.fn(),
setAngularAcceleration: vi.fn(),
setAngularDrag: vi.fn(),
setMass: vi.fn(),
setImmovable: vi.fn()
};
}
function makeDefaultsContext ()
{
return {
world: makeMockWorld(),
defaults: {
setCollideWorldBounds: false,
setBoundsRectangle: null,
setAccelerationX: 0,
setAccelerationY: 0,
setAllowDrag: true,
setAllowGravity: true,
setAllowRotation: true,
setDamping: false,
setBounceX: 0,
setBounceY: 0,
setDragX: 0,
setDragY: 0,
setEnable: true,
setGravityX: 0,
setGravityY: 0,
setFrictionX: 0,
setFrictionY: 0,
setMaxSpeed: -1,
setMaxVelocityX: 10000,
setMaxVelocityY: 10000,
setVelocityX: 0,
setVelocityY: 0,
setAngularVelocity: 0,
setAngularAcceleration: 0,
setAngularDrag: 0,
setMass: 1,
setImmovable: false
}
};
}
describe('createCallbackHandler', function ()
{
it('should call world.enableBody when child has no body', function ()
{
var ctx = makeDefaultsContext();
var child = { body: null };
ctx.world.enableBody = vi.fn(function (c) { c.body = makeMockBody(); });
proto.createCallbackHandler.call(ctx, child);
expect(ctx.world.enableBody).toHaveBeenCalledWith(child, CONST.DYNAMIC_BODY);
});
it('should apply all defaults to the body after enabling', function ()
{
var ctx = makeDefaultsContext();
var body = makeMockBody();
var child = { body: null };
ctx.world.enableBody = vi.fn(function (c) { c.body = body; });
proto.createCallbackHandler.call(ctx, child);
expect(body.setCollideWorldBounds).toHaveBeenCalledWith(false);
expect(body.setAllowDrag).toHaveBeenCalledWith(true);
expect(body.setAllowGravity).toHaveBeenCalledWith(true);
expect(body.setMass).toHaveBeenCalledWith(1);
expect(body.setImmovable).toHaveBeenCalledWith(false);
expect(body.setMaxVelocityX).toHaveBeenCalledWith(10000);
expect(body.setMaxVelocityY).toHaveBeenCalledWith(10000);
});
it('should not recreate body when child already has a dynamic body', function ()
{
var ctx = makeDefaultsContext();
var existingBody = makeMockBody(CONST.DYNAMIC_BODY);
var child = { body: existingBody };
proto.createCallbackHandler.call(ctx, child);
expect(ctx.world.enableBody).not.toHaveBeenCalled();
expect(existingBody.destroy).not.toHaveBeenCalled();
});
it('should apply defaults to an existing dynamic body', function ()
{
var ctx = makeDefaultsContext();
var existingBody = makeMockBody(CONST.DYNAMIC_BODY);
var child = { body: existingBody };
proto.createCallbackHandler.call(ctx, child);
expect(existingBody.setEnable).toHaveBeenCalledWith(true);
expect(existingBody.setGravityX).toHaveBeenCalledWith(0);
expect(existingBody.setGravityY).toHaveBeenCalledWith(0);
});
it('should destroy and recreate body when child has a non-dynamic body', function ()
{
var ctx = makeDefaultsContext();
var staticBody = makeMockBody(CONST.STATIC_BODY);
var newBody = makeMockBody(CONST.DYNAMIC_BODY);
var child = { body: staticBody };
ctx.world.enableBody = vi.fn(function (c) { c.body = newBody; });
proto.createCallbackHandler.call(ctx, child);
expect(staticBody.destroy).toHaveBeenCalled();
expect(ctx.world.enableBody).toHaveBeenCalledWith(child, CONST.DYNAMIC_BODY);
});
it('should set child.body to null before calling enableBody when replacing a non-dynamic body', function ()
{
var ctx = makeDefaultsContext();
var staticBody = makeMockBody(CONST.STATIC_BODY);
var capturedBodyAtEnableTime;
var child = { body: staticBody };
ctx.world.enableBody = vi.fn(function (c)
{
capturedBodyAtEnableTime = c.body;
c.body = makeMockBody(CONST.DYNAMIC_BODY);
});
proto.createCallbackHandler.call(ctx, child);
expect(capturedBodyAtEnableTime).toBeNull();
});
});
describe('removeCallbackHandler', function ()
{
it('should call world.disableBody when child has a body', function ()
{
var ctx = makeDefaultsContext();
var body = makeMockBody();
var child = { body: body };
proto.removeCallbackHandler.call(ctx, child);
expect(ctx.world.disableBody).toHaveBeenCalledWith(child);
});
it('should not call world.disableBody when child has no body', function ()
{
var ctx = makeDefaultsContext();
var child = { body: null };
proto.removeCallbackHandler.call(ctx, child);
expect(ctx.world.disableBody).not.toHaveBeenCalled();
});
it('should not call world.disableBody when child.body is undefined', function ()
{
var ctx = makeDefaultsContext();
var child = {};
proto.removeCallbackHandler.call(ctx, child);
expect(ctx.world.disableBody).not.toHaveBeenCalled();
});
});
describe('setVelocity', function ()
{
it('should set velocity on all children', function ()
{
var setMock0 = vi.fn();
var setMock1 = vi.fn();
var setMock2 = vi.fn();
var children = [
{ body: { velocity: { set: setMock0 } } },
{ body: { velocity: { set: setMock1 } } },
{ body: { velocity: { set: setMock2 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocity.call(ctx, 100, 200);
expect(setMock0).toHaveBeenCalledWith(100, 200);
expect(setMock1).toHaveBeenCalledWith(100, 200);
expect(setMock2).toHaveBeenCalledWith(100, 200);
});
it('should apply step increment to each child', function ()
{
var calls = [];
var makeChild = function ()
{
return { body: { velocity: { set: function (x, y) { calls.push([ x, y ]); } } } };
};
var children = [ makeChild(), makeChild(), makeChild() ];
var ctx = { getChildren: function () { return children; } };
proto.setVelocity.call(ctx, 100, 50, 10);
expect(calls[0]).toEqual([ 100, 50 ]);
expect(calls[1]).toEqual([ 110, 60 ]);
expect(calls[2]).toEqual([ 120, 70 ]);
});
it('should default step to zero when not provided', function ()
{
var calls = [];
var makeChild = function ()
{
return { body: { velocity: { set: function (x, y) { calls.push([ x, y ]); } } } };
};
var children = [ makeChild(), makeChild() ];
var ctx = { getChildren: function () { return children; } };
proto.setVelocity.call(ctx, 300, 400);
expect(calls[0]).toEqual([ 300, 400 ]);
expect(calls[1]).toEqual([ 300, 400 ]);
});
it('should return this', function ()
{
var ctx = { getChildren: function () { return []; } };
var result = proto.setVelocity.call(ctx, 0, 0);
expect(result).toBe(ctx);
});
it('should work with negative velocities', function ()
{
var calls = [];
var children = [
{ body: { velocity: { set: function (x, y) { calls.push([ x, y ]); } } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocity.call(ctx, -100, -200);
expect(calls[0]).toEqual([ -100, -200 ]);
});
it('should work with zero velocity', function ()
{
var calls = [];
var children = [
{ body: { velocity: { set: function (x, y) { calls.push([ x, y ]); } } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocity.call(ctx, 0, 0);
expect(calls[0]).toEqual([ 0, 0 ]);
});
it('should handle empty children array', function ()
{
var ctx = { getChildren: function () { return []; } };
var result = proto.setVelocity.call(ctx, 100, 200);
expect(result).toBe(ctx);
});
it('should work with floating point velocities', function ()
{
var calls = [];
var children = [
{ body: { velocity: { set: function (x, y) { calls.push([ x, y ]); } } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocity.call(ctx, 1.5, 2.7);
expect(calls[0][0]).toBeCloseTo(1.5);
expect(calls[0][1]).toBeCloseTo(2.7);
});
});
describe('setVelocityX', function ()
{
it('should set x velocity on all children', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityX.call(ctx, 150);
expect(children[0].body.velocity.x).toBe(150);
expect(children[1].body.velocity.x).toBe(150);
expect(children[2].body.velocity.x).toBe(150);
});
it('should not alter y velocity', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 99 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityX.call(ctx, 50);
expect(children[0].body.velocity.y).toBe(99);
});
it('should apply step increment to x velocity for each child', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityX.call(ctx, 100, 25);
expect(children[0].body.velocity.x).toBe(100);
expect(children[1].body.velocity.x).toBe(125);
expect(children[2].body.velocity.x).toBe(150);
});
it('should default step to zero when not provided', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityX.call(ctx, 200);
expect(children[0].body.velocity.x).toBe(200);
expect(children[1].body.velocity.x).toBe(200);
});
it('should return this', function ()
{
var ctx = { getChildren: function () { return []; } };
var result = proto.setVelocityX.call(ctx, 0);
expect(result).toBe(ctx);
});
it('should work with negative x velocity', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityX.call(ctx, -75);
expect(children[0].body.velocity.x).toBe(-75);
});
it('should work with negative step values', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityX.call(ctx, 100, -20);
expect(children[0].body.velocity.x).toBe(100);
expect(children[1].body.velocity.x).toBe(80);
expect(children[2].body.velocity.x).toBe(60);
});
it('should handle empty children array', function ()
{
var ctx = { getChildren: function () { return []; } };
var result = proto.setVelocityX.call(ctx, 100);
expect(result).toBe(ctx);
});
it('should work with floating point values and step', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityX.call(ctx, 1.5, 0.5);
expect(children[0].body.velocity.x).toBeCloseTo(1.5);
expect(children[1].body.velocity.x).toBeCloseTo(2.0);
});
});
describe('setVelocityY', function ()
{
it('should set y velocity on all children', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityY.call(ctx, 250);
expect(children[0].body.velocity.y).toBe(250);
expect(children[1].body.velocity.y).toBe(250);
expect(children[2].body.velocity.y).toBe(250);
});
it('should not alter x velocity', function ()
{
var children = [
{ body: { velocity: { x: 42, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityY.call(ctx, 75);
expect(children[0].body.velocity.x).toBe(42);
});
it('should apply step increment to y velocity for each child', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityY.call(ctx, 50, 15);
expect(children[0].body.velocity.y).toBe(50);
expect(children[1].body.velocity.y).toBe(65);
expect(children[2].body.velocity.y).toBe(80);
});
it('should default step to zero when not provided', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityY.call(ctx, 300);
expect(children[0].body.velocity.y).toBe(300);
expect(children[1].body.velocity.y).toBe(300);
});
it('should return this', function ()
{
var ctx = { getChildren: function () { return []; } };
var result = proto.setVelocityY.call(ctx, 0);
expect(result).toBe(ctx);
});
it('should work with negative y velocity', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityY.call(ctx, -300);
expect(children[0].body.velocity.y).toBe(-300);
});
it('should work with negative step values', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityY.call(ctx, 200, -30);
expect(children[0].body.velocity.y).toBe(200);
expect(children[1].body.velocity.y).toBe(170);
expect(children[2].body.velocity.y).toBe(140);
});
it('should handle empty children array', function ()
{
var ctx = { getChildren: function () { return []; } };
var result = proto.setVelocityY.call(ctx, 100);
expect(result).toBe(ctx);
});
it('should work with floating point values and step', function ()
{
var children = [
{ body: { velocity: { x: 0, y: 0 } } },
{ body: { velocity: { x: 0, y: 0 } } }
];
var ctx = { getChildren: function () { return children; } };
proto.setVelocityY.call(ctx, 1.5, 0.5);
expect(children[0].body.velocity.y).toBeCloseTo(1.5);
expect(children[1].body.velocity.y).toBeCloseTo(2.0);
});
});
});