UNPKG

phaser-arcade-slopes

Version:

A Phaser CE plugin that brings sloped tile collision handling to Phaser's Arcade Physics engine

236 lines (217 loc) 7.32 kB
/** * @author Chris Andrew <chris@hexus.io> * @copyright 2016-2021 Chris Andrew * @license MIT */ /** * A facade class to attach to a Phaser game. * * @class Phaser.Plugin.ArcadeSlopes.Facade * @constructor * @param {Phaser.Plugin.ArcadeSlopes.TileSlopeFactory} factory - A tile slope factory. * @param {object} solvers - A set of collision solvers. * @param {integer} defaultSolver - The default collision solver type to use for sloped tiles. */ Phaser.Plugin.ArcadeSlopes.Facade = function (factory, solvers, defaultSolver) { /** * A tile slope factory. * * @property {Phaser.Plugin.ArcadeSlopes.TileSlopeFactory} factory */ this.factory = factory; /** * A set of collision solvers. * * Maps solver constants to their respective instances. * * @property {object} solvers */ this.solvers = solvers; /** * The default collision solver type to use for sloped tiles. * * @property {string} defaultSolver * @default */ this.defaultSolver = defaultSolver || Phaser.Plugin.ArcadeSlopes.SAT; /** * The plugin this facade belongs to. * * @property {Phaser.Plugin.ArcadeSlopes} plugin */ this.plugin = null; }; /** * Enable the physics body of the given object for sloped tile interaction. * * @method Phaser.Plugin.ArcadeSlopes.Facade#enable * @param {Phaser.Sprite|Phaser.Group} object - The object to enable sloped tile physics for. */ Phaser.Plugin.ArcadeSlopes.Facade.prototype.enable = function (object) { if (Array.isArray(object)) { for (var i = 0; i < object.length; i++) { this.enable(object[i]); } } else { if (object instanceof Phaser.Group) { this.enable(object.children); } else { if (object.hasOwnProperty('body')) { this.enableBody(object.body); } if (object.hasOwnProperty('children') && object.children.length > 0) { this.enable(object.children); } } } }; /** * Enable the given physics body for sloped tile collisions. * * @method Phaser.Plugin.ArcadeSlopes.Facade#enableBody * @param {Phaser.Physics.Arcade.Body} body - The physics body to enable. */ Phaser.Plugin.ArcadeSlopes.Facade.prototype.enableBody = function (body) { // Create an SAT shape for the body // TODO: Rename body.polygon to body.shape or body.slopes.shape if (body.isCircle) { body.polygon = new SAT.Circle( new SAT.Vector( body.x + body.halfWidth, body.y + body.halfHeight ), body.radius ); } else { body.polygon = new SAT.Box( new SAT.Vector(body.x, body.y), body.width * body.sprite.scale.x, body.height * body.sprite.scale.y ).toPolygon(); } // Attach a new set of properties that configure the body's interaction // with sloped tiles, if they don't exist (TODO: Formalize as a class) body.slopes = body.slopes || { debug: false, friction: new Phaser.Point(), preferY: false, pullUp: 0, pullDown: 0, pullLeft: 0, pullRight: 0, pullTopLeft: 0, pullTopRight: 0, pullBottomLeft: 0, pullBottomRight: 0, sat: { response: null, }, skipFriction: false, tile: null, velocity: new SAT.Vector() }; }; /** * Converts a layer of the given tilemap. * * Attaches Phaser.Plugin.ArcadeSlopes.TileSlope objects that are used to define * how the tile should collide with a physics body. * * @method Phaser.Plugin.ArcadeSlopes.Facade#convertTilemap * @param {Phaser.Tilemap} map - The map containing the layer to convert. * @param {number|string|Phaser.TileMapLayer} layer - The layer of the map to convert. * @param {string|object} slopeMap - A mapping type string, or a map of tilemap indexes to ArcadeSlope.TileSlope constants. * @param {integer} index - An optional first tile index (firstgid). * @return {Phaser.Tilemap} - The converted tilemap. */ Phaser.Plugin.ArcadeSlopes.Facade.prototype.convertTilemap = function (map, layer, slopeMap, index) { return this.factory.convertTilemap(map, layer, slopeMap, index); }; /** * Converts a tilemap layer. * * @method Phaser.Plugin.ArcadeSlopes.Facade#convertTilemapLayer * @param {Phaser.TilemapLayer} layer - The tilemap layer to convert. * @param {string|object} slopeMap - A mapping type string, or a map of tilemap indexes to ArcadeSlope.TileSlope constants. * @param {integer} index - An optional first tile index (firstgid). * @return {Phaser.TilemapLayer} - The converted tilemap layer. */ Phaser.Plugin.ArcadeSlopes.Facade.prototype.convertTilemapLayer = function (layer, slopeMap, index) { return this.factory.convertTilemapLayer(layer, slopeMap, index); }; /** * Collides a physics body against a tile. * * @method Phaser.Plugin.ArcadeSlopes.Facade#collide * @param {integer} i - The tile index. * @param {Phaser.Physics.Arcade.Body} body - The physics body. * @param {Phaser.Tile} tile - The tile. * @param {Phaser.TilemapLayer} tilemapLayer - The tilemap layer. * @param {boolean} overlapOnly - Whether to only check for an overlap. * @return {boolean} - Whether the body was separated. */ Phaser.Plugin.ArcadeSlopes.Facade.prototype.collide = function (i, body, tile, tilemapLayer, overlapOnly) { return this.solvers.sat.collide(i, body, tile, tilemapLayer, overlapOnly); }; /** * Reset all the collision properties on a physics body. * * Resets body.touching, body.blocked, body.overlap*, body.slopes.sat.response. * * Leaves wasTouching alone. * * @method Phaser.Plugin.ArcadeSlopes.Facade#resetBodyFlags * @param {Phaser.Physics.Arcade.Body} body - The physics body. */ Phaser.Plugin.ArcadeSlopes.Facade.prototype.resetCollision = function (body) { body.touching.none = true; body.touching.up = false; body.touching.down = false; body.touching.left = false; body.touching.right = false; body.blocked.none = true; body.blocked.up = false; body.blocked.down = false; body.blocked.left = false; body.blocked.right = false; body.overlapX = 0; body.overlapY = 0; if (!body.slopes) { return; } body.slopes.sat.response = null; }; /** * Whether to prefer Y axis separation in an attempt to prevent physics bodies * from sliding down slopes when they are separated. * * Disabled by default. Only relevant in a game that uses gravity. * * @name Phaser.Plugin.ArcadeSlopes.Facade#preferY * @property {boolean} preferY */ Object.defineProperty(Phaser.Plugin.ArcadeSlopes.Facade.prototype, 'preferY', { get: function () { return this.solvers.sat.options.preferY; }, set: function (enabled) { this.solvers.sat.options.preferY = !!enabled; } }); /** * Whether to use heuristics to avoid collisions with the internal edges between * connected tiles. * * Enabled by default. Relevant to platformers. * * @name Phaser.Plugin.ArcadeSlopes.Facade#heuristics * @property {boolean} heuristics */ Object.defineProperty(Phaser.Plugin.ArcadeSlopes.Facade.prototype, 'heuristics', { get: function () { return this.solvers.sat.options.restrain; }, set: function (enabled) { this.solvers.sat.options.restrain = !!enabled; } });