phaser/v3/merge/plugins/path/PathManagerPlugin.js
2016-11-23 00:17:46 +00:00

353 lines
No EOL
12 KiB
JavaScript

/**
* @author Richard Davey <rich@photonstorm.com>
* @author Pete Baron <pete@photonstorm.com>
* @copyright 2016 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
/**
* PathManager controls a list of Paths and a list of PathFollowers.
* It is the central control for the majority of the Pathing API.
*
* @class Phaser.Plugin.PathManager
* @constructor
* @param {Phaser.Game} game - A reference to the current Phaser.Game instance.
* @param {Phaser.PluginManager} parent - The Phaser Plugin Manager which looks after this plugin.
*/
Phaser.Plugin.PathManager = function (game, parent) {
Phaser.Plugin.call(this, game, parent);
/**
* @property {array} _list - list of paths
* @private
*/
this._list = [];
/**
* @property {array} _followers - list of path followers
* @private
*/
this._followers = [];
this._branchRegistry = {};
};
Phaser.Plugin.PathManager.prototype = Object.create(Phaser.Plugin.prototype);
Phaser.Plugin.PathManager.prototype.constructor = Phaser.Plugin.PathManager;
/**
* create a new Path from JSON data
*
* JSON data format:
* required: "coordinateSystem":, "smoothness":, "loops":, "speed":, "pointList":[ {"x":, "y":}, ... ]
* optional: "branchFrom": { "path":, "point": }, "joinTo": { "path":, "point": }
*/
Phaser.Plugin.PathManager.prototype.createPathsFromJSON = function(jsonKey) {
var parse = this.game.cache.getJSON(jsonKey);
var path;
var createdPaths = [];
var branchList = [];
parse.paths.forEach(function(config) {
path = new Phaser.Path(config.coordinateSystem, config.loops);
path.name = config.name;
this.addPoints(path, config.pointList, config.speed);
this._list.push(path);
createdPaths.push(path);
config.pointList.reduce(function(list, pnt, index) {
if (pnt.branchType === Phaser.Path.BranchTypes.ATTACHED) {
list.push({
path: path.name,
branchPath: pnt.branchPath,
pointIndex: index,
type: pnt.branchType
});
} else if (pnt.branchType === Phaser.Path.BranchTypes.JOINED) {
list.push({
path: pnt.branchPath,
branchPath: path.name,
pointIndex: pnt.branchPointIndex,
type: pnt.branchType
});
}
return list;
}, branchList);
}, this);
branchList.forEach(function(branch) {
var mainPath = this.findPathByName(branch.path);
var branchPath = this.findPathByName(branch.branchPath);
var mainPathPointIndex = branch.pointIndex;
if (branch.type === Phaser.Path.BranchTypes.ATTACHED) {
this.attachBranch(branchPath, mainPath, mainPathPointIndex);
} else if (branch.type === Phaser.Path.BranchTypes.JOINED) {
this.joinBranch(branchPath, mainPath, mainPathPointIndex, false);
}
}, this);
return createdPaths;
};
Phaser.Plugin.PathManager.prototype.addPath = function(path) {
// if path has points then addPoints, otherwise don't
// this.addPoints(path, parse.pointList, parse.speed);
this._list.push(path);
return path;
};
// create a branching path and attach the start to an existing path
// when a PathFollower encounters the attachment point, it will be able to switch onto this new branch
//
// @param: count {value, optional}, make this branch counted (it won't be taken until a follower has passed it enough times)
Phaser.Plugin.PathManager.prototype.attachBranch = function(branchPath, mainPath, mainPathPointIndex, count) {
if (typeof mainPath === 'string') {
mainPath = this.findPathByName(mainPath);
}
var branchFromPoint = new Phaser.PathPoint();
if (mainPath.getPathPoint(mainPathPointIndex, branchFromPoint)) {
// move the first point of the branchPath to the branchFromPoint location
branchPath.origin = branchFromPoint;
var branchToPoint = branchPath.getPathPointReference(0);
// attach the branch (use point reference so the changes go into the path)
var branchFromPointRef = mainPath.getPathPointReference(mainPathPointIndex);
this._branchAttach(branchFromPointRef, branchPath, 0);
branchFromPointRef.branchType = Phaser.Path.BranchTypes.ATTACHED;
// attach the branch's first point back to where it branched off from (for path reversal)
branchToPoint.branchPath = mainPath;
branchToPoint.branchPointIndex = mainPathPointIndex;
// make sure this branch knows that it's using offset coordinates based on the first path point location
branchPath.coordinateSystem = Phaser.Path.CoordinateSystems.OFFSET;
branchPath.type = Phaser.Path.PathTypes.BRANCH;
// set up counted branches data
if (count !== undefined) {
branchFromPointRef.data = {
type: Phaser.PathPoint.DATA_COUNTER,
value: count
};
}
if (this._branchRegistry[branchPath.name]) {
this._branchRegistry[branchPath.name].push(branchFromPointRef);
} else {
this._branchRegistry[branchPath.name] = [branchFromPointRef];
}
}
};
// attach the end of a path to an existing path
// when a PathFollower encounters the attachment point, it will automatically switch onto the attached path
Phaser.Plugin.PathManager.prototype.joinBranch = function(branchPath, mainPath, mainPathPointIndex, addPoint) {
if (typeof addPoint === 'undefined') {
addPoint = true;
}
if (typeof mainPath === 'string') {
mainPath = this.findPathByName(mainPath);
}
var mainPathJoinPoint, branchLastPoint;
mainPathJoinPoint = new Phaser.PathPoint();
mainPath.getPathPoint(mainPathPointIndex, mainPathJoinPoint);
if (mainPathJoinPoint) {
if (addPoint) {
var newBranchPoint = new Phaser.PathPoint();
if (branchPath.getPathPoint(0, newBranchPoint)) {
// make sure the newly added last path point is relative to the previously added first path point for the branch path by subtracting it out
branchLastPoint = branchPath.addPathPoint(mainPathJoinPoint.x - newBranchPoint.x, mainPathJoinPoint.y - newBranchPoint.y, mainPathJoinPoint.vx, mainPathJoinPoint.vy, 1.0);
this._branchAttach(branchLastPoint, mainPath, mainPathPointIndex);
}
} else {
branchLastPoint = branchPath.getPathPointReference(branchPath.length - 1);
this._branchAttach(branchLastPoint, mainPath, mainPathPointIndex);
}
branchLastPoint.branchType = Phaser.Path.BranchTypes.JOINED;
}
if (this._branchRegistry[branchPath.name]) {
this._branchRegistry[branchPath.name].push(branchLastPoint);
} else {
this._branchRegistry[branchPath.name] = [branchLastPoint];
}
};
// internal function, set the branching parameters of a PathPoint
Phaser.Plugin.PathManager.prototype._branchAttach = function(attachPoint, branchingPath, branchToPointIndex) {
attachPoint.branchPath = branchingPath;
attachPoint.branchPointIndex = branchToPointIndex;
};
Phaser.Plugin.PathManager.prototype._branchDetach = function(attachedPoint) {
attachedPoint.branchPath = null;
attachedPoint.branchPointIndex = null;
};
Phaser.Plugin.PathManager.prototype.removeBranch = function(branch) {
if (typeof branch === 'string') {
branch = this.findPathByName(branch);
}
this._branchRegistry[branch.name].forEach(function(point) {
this._branchDetach(point);
}, this);
this._branchRegistry[branch.name] = null;
this.removePath(this.pathIndex(branch));
};
// @return: the Path object which is at 'index' in the list
Phaser.Plugin.PathManager.prototype.getPath = function(index) {
return this._list[index];
};
// add a list of points to a Path
Phaser.Plugin.PathManager.prototype.addPoints = function(path, pointList, speed) {
if (speed === undefined) speed = 1.0;
for (var i = 0; i < pointList.length; i++) {
path.addPathPoint(pointList[i].x, pointList[i].y, pointList[i].vx, pointList[i].vy, speed, pointList[i].data);
}
return path.numPoints();
};
// @return: the Path object matching 'name' in the list
Phaser.Plugin.PathManager.prototype.findPathByName = function(name) {
for (var i = 0; i < this._list.length; i++) {
if (this._list[i].name == name) {
return this._list[i];
}
}
return null;
};
Phaser.Plugin.PathManager.prototype.findPathByPoint = function(point) {
var l = this._list.length;
for (var i = 0; i < l; i++) {
if (this._list[i].pointIndex(point) > -1) {
return this._list[i];
}
}
};
/*
* FOLLOWERS
*
* the following functions control PathFollower objects
*
*/
// create a new PathFollower and add it to the list
// @param: physicsAdjustTime - how quickly does a physics object attempt to get back to the path's virtual particle position (milliseconds), 0 = it's not a physics object
// @return: the new PathFollower object
Phaser.Plugin.PathManager.prototype.addFollower = function(path, follower, speed, rotationOffset, angularOffset, callbackAtEnd, physicsAdjustTime) {
var f = new Phaser.PathFollower(path, follower, speed, rotationOffset, angularOffset, callbackAtEnd, physicsAdjustTime);
this._followers.push(f);
return f;
};
// update all PathFollower objects in the _followers list
// this will automatically move them along the Paths
// was called updateFollowers
Phaser.Plugin.PathManager.prototype.update = function() {
// move this to a plugin var
//var elapsedTime = 1.0;
for (var i = this._followers.length - 1; i >= 0; --i) {
var f = this._followers[i];
// when a follower's update returns false, kill it
if (!f.update(this.game.time.elpased)) {
// callback for this follower when it dies
if (f.callbackAtEnd) {
f.callbackAtEnd(f.follower);
}
// destroy the follower
f.destroy();
// remove the follower from the list
this._followers.splice(i, 1);
}
}
};
// remove all PathFollowers on this path without destroying their attached graphic objects
// (eg. a long line of enemies use a path to enter, then switch to AI control on arrival maintaining their relative positions)
Phaser.Plugin.PathManager.prototype.removeAllFollowers = function(path) {
for (var i = this._followers.length - 1; i >= 0; --i) {
var f = this._followers[i];
if (f.path == path) {
// callback for this follower when it dies
if (f.callbackAtEnd) {
f.callbackAtEnd(f.follower);
}
// destroy the follower
f.destroy();
// remove the follower from the list
this._followers.splice(i, 1);
}
}
};
Phaser.Plugin.PathManager.prototype.pathIndex = function(path) {
return this._list.indexOf(path);
};
Phaser.Plugin.PathManager.prototype.removePath = function(pathIndex) {
this.removeAllFollowers(this.getPath(pathIndex));
if (pathIndex < this._list.length) {
return this._list.splice(pathIndex, 1);
} else {
throw new Error("ERROR: Cannot remove non-existent path");
}
};
/*
* DEBUG DRAWING OF ALL PATHS
*/
// draw all paths
Phaser.Plugin.PathManager.prototype.drawPaths = function(graphics) {
for (var i = 0; i < this._list.length; i++) {
this._list[i].debug(graphics);
}
};