mirror of
https://github.com/photonstorm/phaser
synced 2025-02-16 14:08:28 +00:00
Plugins moved to their own new repo.
This commit is contained in:
parent
410bc389ed
commit
5eb7ae2cb0
12 changed files with 11 additions and 3107 deletions
|
@ -12,6 +12,7 @@ By Richard Davey, [Photon Storm](http://www.photonstorm.com)
|
|||
* Follow on [Twitter](https://twitter.com/photonstorm)
|
||||
* Join the [Forum](http://www.html5gamedevs.com/forum/14-phaser/)
|
||||
* Source code for 300+ [Phaser Examples](https://github.com/photonstorm/phaser-examples) or [browse them online](http://examples.phaser.io)
|
||||
* View the growing list of [Phaser Plugins](https://github.com/photonstorm/phaser-plugins)
|
||||
* Read the [documentation online](http://docs.phaser.io)
|
||||
* Join our [#phaserio IRC channel](http://www.html5gamedevs.com/topic/4470-official-phaserio-irc-channel-phaserio-on-freenode/) on freenode
|
||||
* Subscribe to the [Phaser Newsletter](https://confirmsubscription.com/h/r/369DE48E3E86AF1E) and we'll email you when new versions are released.
|
||||
|
|
639
plugins/AStar.js
639
plugins/AStar.js
|
@ -1,639 +0,0 @@
|
|||
/**
|
||||
* The MIT License (MIT)
|
||||
|
||||
* Copyright (c) 2014 Raphaël Roux
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Raphaël Roux
|
||||
* @copyright 2014 Raphaël Roux
|
||||
* @license {@link http://opensource.org/licenses/MIT}
|
||||
*/
|
||||
|
||||
/**
|
||||
* AStar is a phaser pathfinding plugin based on an A* kind of algorythm
|
||||
* It works with the Phaser.Tilemap
|
||||
*
|
||||
* @class Phaser.Plugin.AStar
|
||||
* @constructor
|
||||
* @param {Any} parent - The object that owns this plugin, usually Phaser.PluginManager.
|
||||
*/
|
||||
Phaser.Plugin.AStar = function (parent)
|
||||
{
|
||||
|
||||
/**
|
||||
* @property {Any} parent - The parent of this plugin. If added to the PluginManager the parent will be set to that, otherwise it will be null.
|
||||
*/
|
||||
this.parent = parent;
|
||||
|
||||
/**
|
||||
* @property {Phaser.Tilemap} _tilemap - A reference to the tilemap used to store astar nodes according to the Phaser.Tilemap structure.
|
||||
*/
|
||||
this._tilemap;
|
||||
|
||||
/**
|
||||
* @property {number} _layerIndex - The layer index of the tilemap that is used to store astar nodes.
|
||||
*/
|
||||
this._layerIndex;
|
||||
|
||||
/**
|
||||
* @property {number} _tilesetIndex - The tileset index of the tileset that handle tiles properties.
|
||||
*/
|
||||
this._tilesetIndex;
|
||||
|
||||
/**
|
||||
* @property {array} _open - An array that references nodes to be considered by the search path algorythm.
|
||||
*/
|
||||
this._open;
|
||||
|
||||
/**
|
||||
* @property {array} _closed - An array that references nodes not to consider anymore.
|
||||
*/
|
||||
this._closed;
|
||||
|
||||
/**
|
||||
* @property {array} _visited - Internal array of visited tiles, use for debug pupose.
|
||||
*/
|
||||
this._visited;
|
||||
|
||||
/**
|
||||
* @property {boolean} _useDiagonal - Does the astar algorythm can use tile diagonal?
|
||||
* @default true
|
||||
*/
|
||||
this._useDiagonal = true;
|
||||
|
||||
/**
|
||||
* @property {boolean} _findClosest - Does the findPath algorythm must calculate the closest result if destination is unreachable. If not findPath will return an empty array
|
||||
* @default true
|
||||
*/
|
||||
this._findClosest = true;
|
||||
|
||||
/**
|
||||
* @property {string} _walkablePropName - Wich name have the walkable propertiy in your tileset.
|
||||
* @default 'walkable'
|
||||
*/
|
||||
this._walkablePropName = 'walkable';
|
||||
|
||||
/**
|
||||
* @property {function} _distanceFunction - The function used to calculate distance.
|
||||
*/
|
||||
this._distanceFunction = Phaser.Plugin.AStar.DISTANCE_EUCLIDIAN;
|
||||
|
||||
/**
|
||||
* @property {Phaser.Plugin.AStar.AStarPath} _lastPath - The last path calculated by astar.
|
||||
*/
|
||||
this._lastPath = null;
|
||||
|
||||
/**
|
||||
* @property {boolean} _debug - Boolean to debug mode, stores visited nodes, and have a cost. Disable in production.
|
||||
* @default false
|
||||
*/
|
||||
this._debug = true;
|
||||
};
|
||||
|
||||
Phaser.Plugin.AStar.prototype = Object.create(Phaser.Plugin.prototype);
|
||||
Phaser.Plugin.AStar.prototype.constructor = Phaser.Plugin.AStar;
|
||||
|
||||
|
||||
Phaser.Plugin.AStar.VERSION = '0.0.101';
|
||||
Phaser.Plugin.AStar.COST_ORTHOGONAL = 1;
|
||||
Phaser.Plugin.AStar.COST_DIAGONAL = Phaser.Plugin.AStar.COST_ORTHOGONAL*Math.sqrt(2);
|
||||
Phaser.Plugin.AStar.DISTANCE_MANHATTAN = 'distManhattan';
|
||||
Phaser.Plugin.AStar.DISTANCE_EUCLIDIAN = 'distEuclidian';
|
||||
|
||||
/**
|
||||
* Sets the Phaser.Tilemap used to searchPath into.
|
||||
* @method Phaser.Plugin.AStar#setAStarMap
|
||||
* @public
|
||||
* @param {Phaser.Tilemap} map - the Phaser.Tilemap used to searchPath into. It must have a tileset with tile porperties to know if tiles are walkable or not.
|
||||
* @param {string} layerName - The name of the layer that handle tiles.
|
||||
* @param {string} tilesetName - The name of the tileset that have walkable properties.
|
||||
* @return {Phaser.Plugin.AStar} The Phaser.Plugin.AStar itself.
|
||||
*/
|
||||
Phaser.Plugin.AStar.prototype.setAStarMap = function(map, layerName, tilesetName)
|
||||
{
|
||||
this._tilemap = map;
|
||||
this._layerIndex = this._tilemap.getLayerIndex(layerName);;
|
||||
this._tilesetIndex = this._tilemap.getTilesetIndex(tilesetName);
|
||||
|
||||
this.updateMap();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the Phaser.Tilemap used to searchPath into.
|
||||
* @method Phaser.Plugin.AStar-setAStarMap
|
||||
* @private
|
||||
* @return {void} The Phaser.Plugin.AStar itself.
|
||||
*/
|
||||
Phaser.Plugin.AStar.prototype.updateMap = function()
|
||||
{
|
||||
var tile;
|
||||
var walkable;
|
||||
|
||||
//for each tile, add a default AStarNode with x, y and walkable properties according to the tilemap/tileset datas
|
||||
for(var y=0; y < this._tilemap.height; y++)
|
||||
{
|
||||
for(var x=0; x < this._tilemap.width; x++)
|
||||
{
|
||||
tile = this._tilemap.layers[this._layerIndex].data[y][x];
|
||||
walkable = this._tilemap.tilesets[this._tilesetIndex].tileProperties[tile.index - 1][this._walkablePropName] !== "false" ? true : false;
|
||||
tile.properties.astarNode = new Phaser.Plugin.AStar.AStarNode(x, y, walkable);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Find a path between to tiles coordinates
|
||||
* @method Phaser.Plugin.AStar#findPath
|
||||
* @public
|
||||
* @param {Phaser.Point} startPoint - The start point x, y in tiles coordinates to search a path.
|
||||
* @param {Phaser.Point} goalPoint - The goal point x, y in tiles coordinates that you trying to reach.
|
||||
* @return {Phaser.Plugin.AStar.AStarPath} The Phaser.Plugin.AStar.AStarPath that results
|
||||
*/
|
||||
Phaser.Plugin.AStar.prototype.findPath = function(startPoint, goalPoint)
|
||||
{
|
||||
var path = new Phaser.Plugin.AStar.AStarPath();
|
||||
|
||||
var start = this._tilemap.layers[this._layerIndex].data[startPoint.y][startPoint.x].properties.astarNode; //:AStarNode;
|
||||
var goal = this._tilemap.layers[this._layerIndex].data[goalPoint.y][goalPoint.x].properties.astarNode
|
||||
|
||||
path.start = start;
|
||||
path.goal = goal;
|
||||
|
||||
this._open = [];
|
||||
this._closed = [];
|
||||
this._visited = [];
|
||||
|
||||
this._open.push(start);
|
||||
|
||||
start.g = 0;
|
||||
start.h = this[this._distanceFunction](start, goal);
|
||||
start.f = start.h;
|
||||
start.parent = null;
|
||||
|
||||
//Loop until there are no more nodes to search
|
||||
while(this._open.length > 0)
|
||||
{
|
||||
//Find lowest f in this._open
|
||||
var f = Infinity;
|
||||
var x;
|
||||
for (var i=0; i<this._open.length; i++)
|
||||
{
|
||||
if (this._open[i].f < f)
|
||||
{
|
||||
x = this._open[i];
|
||||
f = x.f;
|
||||
}
|
||||
}
|
||||
|
||||
//Solution found, return solution
|
||||
if (x == goal)
|
||||
{
|
||||
path.nodes = this.reconstructPath(goal);
|
||||
this._lastPath = path;
|
||||
if(this._debug === true) path.visited = this._visited;
|
||||
return path;
|
||||
}
|
||||
|
||||
//Close current node
|
||||
this._open.splice(this._open.indexOf(x), 1);
|
||||
this._closed.push(x);
|
||||
|
||||
//Then get its neighbors
|
||||
var n = this.neighbors(x);
|
||||
|
||||
for(var yIndex=0; yIndex < n.length; yIndex++)
|
||||
{
|
||||
|
||||
var y = n[yIndex];
|
||||
|
||||
if (-1 != this._closed.indexOf(y))
|
||||
continue;
|
||||
|
||||
var g = x.g + y.travelCost;
|
||||
var better = false;
|
||||
|
||||
//Add the node for being considered next loop.
|
||||
if (-1 == this._open.indexOf(y))
|
||||
{
|
||||
this._open.push(y);
|
||||
better = true;
|
||||
if(this._debug === true) this.visit(y);
|
||||
}
|
||||
else if (g < y.g)
|
||||
{
|
||||
better = true;
|
||||
}
|
||||
|
||||
if (better) {
|
||||
y.parent = x;
|
||||
y.g = g;
|
||||
y.h = this[this._distanceFunction](y, goal);
|
||||
y.f = y.g + y.h;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//If no solution found, does A* try to return the closest result?
|
||||
if(this._findClosest === true)
|
||||
{
|
||||
var min = Infinity;
|
||||
var closestGoal, node, dist;
|
||||
for(var i=0, ii=this._closed.length; i<ii; i++)
|
||||
{
|
||||
node = this._closed[i];
|
||||
|
||||
var dist = this[this._distanceFunction](goal, node);
|
||||
if (dist < min)
|
||||
{
|
||||
min = dist;
|
||||
closestGoal = node;
|
||||
}
|
||||
}
|
||||
|
||||
//Reconstruct a path a path from the closestGoal
|
||||
path.nodes = this.reconstructPath(closestGoal);
|
||||
if(this._debug === true) path.visited = this._visited;
|
||||
}
|
||||
|
||||
this._lastPath = path;
|
||||
|
||||
return path;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Reconstruct the result path backwards from the goal point, crawling its parents. Internal method.
|
||||
* @method Phaser.Plugin.AStar-reconstructPath
|
||||
* @private
|
||||
* @param {Phaser.Plugin.AStar.AStarNode} n - The astar node from wich you want to rebuild the path.
|
||||
* @return {array} An array of Phaser.Plugin.AStar.AStarNode
|
||||
*/
|
||||
Phaser.Plugin.AStar.prototype.reconstructPath = function(n)
|
||||
{
|
||||
var solution = [];
|
||||
var nn = n;
|
||||
while(nn.parent) {
|
||||
solution.push({x: nn.x, y: nn.y});
|
||||
nn = nn.parent;
|
||||
}
|
||||
return solution;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add a node into visited if it is not already in. Debug only.
|
||||
* @method Phaser.Plugin.AStar-visit
|
||||
* @private
|
||||
* @param {Phaser.Plugin.AStar.AStarNode} node - The astar node you want to register as visited
|
||||
* @return {void}
|
||||
*/
|
||||
Phaser.Plugin.AStar.prototype.visit = function(node)
|
||||
{
|
||||
for(var i in this._visited)
|
||||
{
|
||||
if (this._visited[i] == node) return;
|
||||
}
|
||||
|
||||
this._visited.push(node);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add a node into visited if it is not already in. Debug only.
|
||||
* @method Phaser.Plugin.AStar-neighbors
|
||||
* @private
|
||||
* @param {Phaser.Plugin.AStar.AStarNode} n - The astar node you want to register as visited
|
||||
* @return {void}
|
||||
*/
|
||||
Phaser.Plugin.AStar.prototype.neighbors = function(node)
|
||||
{
|
||||
var x = node.x;
|
||||
var y = node.y;
|
||||
var n = null;
|
||||
var neighbors = [];
|
||||
|
||||
var map = this._tilemap.layers[this._layerIndex].data;
|
||||
|
||||
//West
|
||||
if (x > 0) {
|
||||
|
||||
n = map[y][x-1].properties.astarNode;
|
||||
if (n.walkable) {
|
||||
n.travelCost = Phaser.Plugin.AStar.COST_ORTHOGONAL;
|
||||
neighbors.push(n);
|
||||
}
|
||||
}
|
||||
//East
|
||||
if (x < this._tilemap.width-1) {
|
||||
n = map[y][x+1].properties.astarNode;
|
||||
if (n.walkable) {
|
||||
n.travelCost = Phaser.Plugin.AStar.COST_ORTHOGONAL;
|
||||
neighbors.push(n);
|
||||
}
|
||||
}
|
||||
//North
|
||||
if (y > 0) {
|
||||
n = map[y-1][x].properties.astarNode;
|
||||
if (n.walkable) {
|
||||
n.travelCost = Phaser.Plugin.AStar.COST_ORTHOGONAL;
|
||||
neighbors.push(n);
|
||||
}
|
||||
}
|
||||
//South
|
||||
if (y < this._tilemap.height-1) {
|
||||
n = map[y+1][x].properties.astarNode;
|
||||
if (n.walkable) {
|
||||
n.travelCost = Phaser.Plugin.AStar.COST_ORTHOGONAL;
|
||||
neighbors.push(n);
|
||||
}
|
||||
}
|
||||
|
||||
//If diagonals aren't used do not search for other neighbors and return orthogonal search result
|
||||
if(this._useDiagonal === false)
|
||||
return neighbors;
|
||||
|
||||
//NorthWest
|
||||
if (x > 0 && y > 0) {
|
||||
n = map[y-1][x-1].properties.astarNode;
|
||||
if (n.walkable
|
||||
&& map[y][x-1].properties.astarNode.walkable
|
||||
&& map[y-1][x].properties.astarNode.walkable
|
||||
) {
|
||||
n.travelCost = Phaser.Plugin.AStar.COST_DIAGONAL;
|
||||
neighbors.push(n);
|
||||
}
|
||||
}
|
||||
//NorthEast
|
||||
if (x < this._tilemap.width-1 && y > 0) {
|
||||
n = map[y-1][x+1].properties.astarNode;
|
||||
if (n.walkable
|
||||
&& map[y][x+1].properties.astarNode.walkable
|
||||
&& map[y-1][x].properties.astarNode.walkable
|
||||
) {
|
||||
n.travelCost = Phaser.Plugin.AStar.COST_DIAGONAL;
|
||||
neighbors.push(n);
|
||||
}
|
||||
}
|
||||
//SouthWest
|
||||
if (x > 0 && y < this._tilemap.height-1) {
|
||||
n = map[y+1][x-1].properties.astarNode;
|
||||
if (n.walkable
|
||||
&& map[y][x-1].properties.astarNode.walkable
|
||||
&& map[y+1][x].properties.astarNode.walkable
|
||||
) {
|
||||
n.travelCost = Phaser.Plugin.AStar.COST_DIAGONAL;
|
||||
neighbors.push(n);
|
||||
}
|
||||
}
|
||||
//SouthEast
|
||||
if (x < this._tilemap.width-1 && y < this._tilemap.height-1) {
|
||||
n = map[y+1][x+1].properties.astarNode;
|
||||
if (n.walkable
|
||||
&& map[y][x+1].properties.astarNode.walkable
|
||||
&& map[y+1][x].properties.astarNode.walkable
|
||||
) {
|
||||
n.travelCost = Phaser.Plugin.AStar.COST_DIAGONAL;
|
||||
neighbors.push(n);
|
||||
}
|
||||
}
|
||||
|
||||
return neighbors;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculate a distance between tow astar nodes coordinates according to the Manhattan method
|
||||
* @method Phaser.Plugin.AStar-distManhattan
|
||||
* @private
|
||||
* @param {Phaser.Plugin.AStar.AStarNode} nodeA - The A node.
|
||||
* @param {Phaser.Plugin.AStar.AStarNode} nodeB - The B node.
|
||||
* @return {number} The distance between nodeA and nodeB
|
||||
*/
|
||||
Phaser.Plugin.AStar.prototype.distManhattan = function (nodeA, nodeB)
|
||||
{
|
||||
return Math.abs(nodeA.x - nodeB.x) + Math.abs(nodeA.y - nodeB.y);
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate a distance between tow astar nodes coordinates according to the Euclidian method. More accurate
|
||||
* @method Phaser.Plugin.AStar-distEuclidian
|
||||
* @private
|
||||
* @param {Phaser.Plugin.AStar.AStarNode} nodeA - The A node.
|
||||
* @param {Phaser.Plugin.AStar.AStarNode} nodeB - The B node.
|
||||
* @return {number} The distance between nodeA and nodeB
|
||||
*/
|
||||
Phaser.Plugin.AStar.prototype.distEuclidian = function(nodeA, nodeB)
|
||||
{
|
||||
return Math.sqrt(Math.pow((nodeA.x - nodeB.x), 2) + Math.pow((nodeA.y -nodeB.y), 2));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tells if a tile is walkable from its tilemap coordinates
|
||||
* @method Phaser.Plugin.AStar-isWalkable
|
||||
* @public
|
||||
* @param {number} x - The x coordiante of the tile in tilemap's coordinate.
|
||||
* @param {number} y - The y coordinate of the tile in tilemap's coordinate.
|
||||
* @return {boolean} The distance between nodeA and nodeB
|
||||
*/
|
||||
Phaser.Plugin.AStar.prototype.isWalkable = function(x, y)
|
||||
{
|
||||
return this._tilemap.layers[this._layerIndex].data[y][x].properties.astarNode.walkable;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @properties {string} version - The version number of Phaser.Plugin.AStar read only
|
||||
*/
|
||||
Object.defineProperty(Phaser.Plugin.AStar.prototype, "version", {
|
||||
|
||||
get: function () {
|
||||
return Phaser.Plugin.AStar.VERSION;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* AStarNode is an object that stores AStar value. Each tile have an AStarNode in their properties
|
||||
* @class Phaser.Plugin.AStar.AStarNode
|
||||
* @constructor
|
||||
* @param {number} x - The x coordinate of the tile.
|
||||
* @param {number} y - The y coordinate of the tile.
|
||||
* @param {boolean} isWalkable - Is this tile is walkable?
|
||||
*/
|
||||
Phaser.Plugin.AStar.AStarNode = function(x, y, isWalkable)
|
||||
{
|
||||
|
||||
/**
|
||||
* @property {number} x - The x coordinate of the tile.
|
||||
*/
|
||||
this.x = x;
|
||||
|
||||
/**
|
||||
* @property {number} y - The y coordinate of the tile.
|
||||
*/
|
||||
this.y = y;
|
||||
|
||||
/**
|
||||
* @property {number} g - The total travel cost from the start point. Sum of COST_ORTHOGONAL and COST_DIAGONAL
|
||||
*/
|
||||
this.g = 0;
|
||||
|
||||
/**
|
||||
* @property {number} h - The remaing distance as the crow flies between this node and the goal.
|
||||
*/
|
||||
this.h = 0;
|
||||
|
||||
/**
|
||||
* @property {number} f - The weight. Sum of g + h.
|
||||
*/
|
||||
this.f = 0;
|
||||
|
||||
/**
|
||||
* @property {Phaser.Plugin.AStar.AStarNode} parent - Where do we come from? It's an AStarNode reference needed to reconstruct a path backwards (from goal to start point)
|
||||
*/
|
||||
this.parent;
|
||||
|
||||
/**
|
||||
* @property {boolean} walkable - Is this node is walkable?
|
||||
*/
|
||||
this.walkable = isWalkable;
|
||||
|
||||
/**
|
||||
* @property {number} travelCost - The cost to travel to this node, COST_ORTHOGONAL or COST_DIAGONAL
|
||||
*/
|
||||
this.travelCost;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* AStarPath is an object that stores a searchPath result.
|
||||
* @class Phaser.Plugin.AStar.AStarPath
|
||||
* @constructor
|
||||
* @param {array} nodes - An array of nodes coordinates sorted backward from goal to start point.
|
||||
* @param {Phaser.Plugin.AStarNode} start - The start AStarNode used for the searchPath.
|
||||
* @param {Phaser.Plugin.AStarNode} goal - The goal AStarNode used for the searchPath.
|
||||
*/
|
||||
Phaser.Plugin.AStar.AStarPath = function(nodes, start, goal)
|
||||
{
|
||||
/**
|
||||
* @property {array} nodes - Array of AstarNodes x, y coordiantes that are the path solution from goal to start point.
|
||||
*/
|
||||
this.nodes = nodes || [];
|
||||
|
||||
/**
|
||||
* @property {Phaser.Plugin.Astar.AStarNode} start - Reference to the start point used by findPath.
|
||||
*/
|
||||
this.start = start || null;
|
||||
|
||||
/**
|
||||
* @property {Phaser.Plugin.Astar.AStarNode} goal - Reference to the goal point used by findPath.
|
||||
*/
|
||||
this.goal = goal || null;
|
||||
|
||||
/**
|
||||
* @property {array} visited - Array of AStarNodes that the findPath algorythm has visited. Used for debug only.
|
||||
*/
|
||||
this.visited = [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Debug method to draw the last calculated path by AStar
|
||||
* @method Phaser.Utils.Debug.AStar
|
||||
* @param {Phaser.Plugin.AStar} astar- The AStar plugin that you want to debug.
|
||||
* @param {number} x - X position on camera for debug display.
|
||||
* @param {number} y - Y position on camera for debug display.
|
||||
* @param {string} color - Color to stroke the path line.
|
||||
* @return {void}
|
||||
*/
|
||||
Phaser.Utils.Debug.prototype.AStar = function(astar, x, y, color, showVisited)
|
||||
{
|
||||
if (this.context == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var pathLength = 0;
|
||||
if(astar._lastPath !== null)
|
||||
{
|
||||
pathLength = astar._lastPath.nodes.length;
|
||||
}
|
||||
|
||||
color = color || 'rgb(255,255,255)';
|
||||
|
||||
game.debug.start(x, y, color);
|
||||
|
||||
|
||||
if(pathLength > 0)
|
||||
{
|
||||
var node = astar._lastPath.nodes[0];
|
||||
this.context.strokeStyle = color;
|
||||
this.context.beginPath();
|
||||
this.context.moveTo((node.x * astar._tilemap.tileWidth) + (astar._tilemap.tileWidth/2) - game.camera.view.x, (node.y * astar._tilemap.tileHeight) + (astar._tilemap.tileHeight/2) - game.camera.view.y);
|
||||
|
||||
for(var i=0; i<pathLength; i++)
|
||||
{
|
||||
node = astar._lastPath.nodes[i];
|
||||
this.context.lineTo((node.x * astar._tilemap.tileWidth) + (astar._tilemap.tileWidth/2) - game.camera.view.x, (node.y * astar._tilemap.tileHeight) + (astar._tilemap.tileHeight/2) - game.camera.view.y);
|
||||
}
|
||||
|
||||
this.context.lineTo((astar._lastPath.start.x * astar._tilemap.tileWidth) + (astar._tilemap.tileWidth/2) - game.camera.view.x, (astar._lastPath.start.y * astar._tilemap.tileHeight) + (astar._tilemap.tileHeight/2) - game.camera.view.y);
|
||||
|
||||
this.context.stroke();
|
||||
|
||||
//Draw circles on visited nodes
|
||||
if(showVisited !== false)
|
||||
{
|
||||
var visitedNode;
|
||||
for(var j=0; j < astar._lastPath.visited.length; j++)
|
||||
{
|
||||
visitedNode = astar._lastPath.visited[j];
|
||||
this.context.beginPath();
|
||||
this.context.arc((visitedNode.x * astar._tilemap.tileWidth) + (astar._tilemap.tileWidth/2) - game.camera.view.x, (visitedNode.y * astar._tilemap.tileHeight) + (astar._tilemap.tileHeight/2) - game.camera.view.y, 2, 0, Math.PI*2, true);
|
||||
this.context.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.line('Path length: ' + pathLength);
|
||||
this.line('Distance func: ' + astar._distanceFunction);
|
||||
this.line('Use diagonal: ' + astar._useDiagonal);
|
||||
this.line('Find Closest: ' + astar._findClosest);
|
||||
|
||||
game.debug.stop();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
/**
|
||||
* Phaser - Display - CSS3Filters
|
||||
*
|
||||
* Allows for easy addition and modification of CSS3 Filters on DOM objects (typically the Game.Stage.canvas).
|
||||
*/
|
||||
|
||||
Phaser.Plugins.CSS3Filters = function (parent) {
|
||||
|
||||
this.parent = parent;
|
||||
|
||||
this._blur = 0;
|
||||
this._grayscale = 0;
|
||||
this._sepia = 0;
|
||||
this._brightness = 0;
|
||||
this._contrast = 0;
|
||||
this._hueRotate = 0;
|
||||
this._invert = 0;
|
||||
this._opacity = 0;
|
||||
this._saturate = 0;
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugins.CSS3Filters.prototype = {
|
||||
|
||||
setFilter: function (local, prefix, value, unit) {
|
||||
|
||||
this[local] = value;
|
||||
|
||||
if (this.parent)
|
||||
{
|
||||
this.parent.style['-webkit-filter'] = prefix + '(' + value + unit + ')';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Object.defineProperty(Phaser.Plugins.CSS3Filters.prototype, "blur", {
|
||||
|
||||
get: function () {
|
||||
return this._blur;
|
||||
},
|
||||
|
||||
/**
|
||||
* Applies a Gaussian blur to the DOM element. The value of 'radius' defines the value of the standard deviation to the Gaussian function,
|
||||
* or how many pixels on the screen blend into each other, so a larger value will create more blur.
|
||||
* If no parameter is provided, then a value 0 is used. The parameter is specified as a CSS length, but does not accept percentage values.
|
||||
*/
|
||||
set: function (radius) {
|
||||
this.setFilter('_blur', 'blur', radius, 'px');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Phaser.Plugins.CSS3Filters.prototype, "grayscale", {
|
||||
get: function () {
|
||||
return this._grayscale;
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts the input image to grayscale. The value of 'amount' defines the proportion of the conversion.
|
||||
* A value of 100% is completely grayscale. A value of 0% leaves the input unchanged.
|
||||
* Values between 0% and 100% are linear multipliers on the effect. If the 'amount' parameter is missing, a value of 100% is used.
|
||||
*/
|
||||
set: function (amount) {
|
||||
this.setFilter('_grayscale', 'grayscale', amount, '%');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Phaser.Plugins.CSS3Filters.prototype, "sepia", {
|
||||
get: function () {
|
||||
return this._sepia;
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts the input image to sepia. The value of 'amount' defines the proportion of the conversion.
|
||||
* A value of 100% is completely sepia. A value of 0 leaves the input unchanged.
|
||||
* Values between 0% and 100% are linear multipliers on the effect. If the 'amount' parameter is missing, a value of 100% is used.
|
||||
*/
|
||||
set: function (amount) {
|
||||
this.setFilter('_sepia', 'sepia', amount, '%');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Phaser.Plugins.CSS3Filters.prototype, "brightness", {
|
||||
get: function () {
|
||||
return this._brightness;
|
||||
},
|
||||
|
||||
/**
|
||||
* Applies a linear multiplier to input image, making it appear more or less bright.
|
||||
* A value of 0% will create an image that is completely black. A value of 100% leaves the input unchanged.
|
||||
* Other values are linear multipliers on the effect. Values of an amount over 100% are allowed, providing brighter results.
|
||||
* If the 'amount' parameter is missing, a value of 100% is used.
|
||||
*/
|
||||
set: function (amount) {
|
||||
this.setFilter('_brightness', 'brightness', amount, '%');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Phaser.Plugins.CSS3Filters.prototype, "contrast", {
|
||||
get: function () {
|
||||
return this._contrast;
|
||||
},
|
||||
|
||||
/**
|
||||
* Adjusts the contrast of the input. A value of 0% will create an image that is completely black.
|
||||
* A value of 100% leaves the input unchanged. Values of amount over 100% are allowed, providing results with less contrast.
|
||||
* If the 'amount' parameter is missing, a value of 100% is used.
|
||||
*/
|
||||
set: function (amount) {
|
||||
this.setFilter('_contrast', 'contrast', amount, '%');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Phaser.Plugins.CSS3Filters.prototype, "hueRotate", {
|
||||
|
||||
get: function () {
|
||||
return this._hueRotate;
|
||||
},
|
||||
|
||||
/**
|
||||
* Applies a hue rotation on the input image. The value of 'angle' defines the number of degrees around the color circle
|
||||
* the input samples will be adjusted. A value of 0deg leaves the input unchanged. If the 'angle' parameter is missing,
|
||||
* a value of 0deg is used. Maximum value is 360deg.
|
||||
*/
|
||||
set: function (angle) {
|
||||
this.setFilter('_hueRotate', 'hue-rotate', angle, 'deg');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Phaser.Plugins.CSS3Filters.prototype, "invert", {
|
||||
|
||||
get: function () {
|
||||
return this._invert;
|
||||
},
|
||||
|
||||
/**
|
||||
* Inverts the samples in the input image. The value of 'amount' defines the proportion of the conversion.
|
||||
* A value of 100% is completely inverted. A value of 0% leaves the input unchanged.
|
||||
* Values between 0% and 100% are linear multipliers on the effect. If the 'amount' parameter is missing, a value of 100% is used.
|
||||
*/
|
||||
set: function (value) {
|
||||
this.setFilter('_invert', 'invert', value, '%');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Phaser.Plugins.CSS3Filters.prototype, "opacity", {
|
||||
|
||||
get: function () {
|
||||
return this._opacity;
|
||||
},
|
||||
|
||||
/**
|
||||
* Applies transparency to the samples in the input image. The value of 'amount' defines the proportion of the conversion.
|
||||
* A value of 0% is completely transparent. A value of 100% leaves the input unchanged.
|
||||
* Values between 0% and 100% are linear multipliers on the effect. This is equivalent to multiplying the input image samples by amount.
|
||||
* If the 'amount' parameter is missing, a value of 100% is used.
|
||||
* This function is similar to the more established opacity property; the difference is that with filters, some browsers provide hardware acceleration for better performance.
|
||||
*/
|
||||
set: function (value) {
|
||||
this.setFilter('_opacity', 'opacity', value, '%');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(Phaser.Plugins.CSS3Filters.prototype, "saturate", {
|
||||
|
||||
get: function () {
|
||||
return this._saturate;
|
||||
},
|
||||
|
||||
/**
|
||||
* Saturates the input image. The value of 'amount' defines the proportion of the conversion.
|
||||
* A value of 0% is completely un-saturated. A value of 100% leaves the input unchanged.
|
||||
* Other values are linear multipliers on the effect. Values of amount over 100% are allowed, providing super-saturated results.
|
||||
* If the 'amount' parameter is missing, a value of 100% is used.
|
||||
*/
|
||||
set: function (value) {
|
||||
this.setFilter('_saturate', 'saturate', value, '%');
|
||||
}
|
||||
});
|
|
@ -1,108 +0,0 @@
|
|||
/* jshint camelcase:false */
|
||||
/**
|
||||
* A collection of methods useful for manipulating and comparing colors.
|
||||
*
|
||||
* @class ColorHarmony
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @copyright 2013 Photon Storm Ltd.
|
||||
* @license https://github.com/photonstorm/phaser/blob/master/license.txt MIT License
|
||||
* @module Phaser
|
||||
*/
|
||||
|
||||
Phaser.Plugins.ColorHarmony.prototype = {
|
||||
|
||||
/**
|
||||
* Returns a Complementary Color Harmony for the given color.
|
||||
* <p>A complementary hue is one directly opposite the color given on the color wheel</p>
|
||||
* <p>Value returned in 0xAARRGGBB format with Alpha set to 255.</p>
|
||||
*
|
||||
* @method getComplementHarmony
|
||||
* @param {Number} color The color to base the harmony on.
|
||||
* @return {Number} 0xAARRGGBB format color value.
|
||||
*/
|
||||
getComplementHarmony: function (color) {
|
||||
|
||||
var hsv = Phaser.Color.RGBtoHSV(color);
|
||||
var opposite = Phaser.Color.game.math.wrapValue(hsv.hue, 180, 359);
|
||||
return Phaser.Color.HSVtoRGB(opposite, 1.0, 1.0);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns an Analogous Color Harmony for the given color.
|
||||
* <p>An Analogous harmony are hues adjacent to each other on the color wheel</p>
|
||||
* <p>Values returned in 0xAARRGGBB format with Alpha set to 255.</p>
|
||||
*
|
||||
* @method getAnalogousHarmony
|
||||
* @param {Number} color The color to base the harmony on.
|
||||
* @param {Number} threshold Control how adjacent the colors will be (default +- 30 degrees)
|
||||
* @return {Object} Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color)
|
||||
*/
|
||||
getAnalogousHarmony: function (color, threshold) {
|
||||
if (typeof threshold === "undefined") { threshold = 30; }
|
||||
var hsv = Phaser.Color.RGBtoHSV(color);
|
||||
if(threshold > 359 || threshold < 0) {
|
||||
throw new Error("Color Warning: Invalid threshold given to getAnalogousHarmony()");
|
||||
}
|
||||
var warmer = Phaser.Color.game.math.wrapValue(hsv.hue, 359 - threshold, 359);
|
||||
var colder = Phaser.Color.game.math.wrapValue(hsv.hue, threshold, 359);
|
||||
return {
|
||||
color1: color,
|
||||
color2: Phaser.Color.HSVtoRGB(warmer, 1.0, 1.0),
|
||||
color3: Phaser.Color.HSVtoRGB(colder, 1.0, 1.0),
|
||||
hue1: hsv.hue,
|
||||
hue2: warmer,
|
||||
hue3: colder
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns an Split Complement Color Harmony for the given color.
|
||||
* <p>A Split Complement harmony are the two hues on either side of the color's Complement</p>
|
||||
* <p>Values returned in 0xAARRGGBB format with Alpha set to 255.</p>
|
||||
*
|
||||
* @method getSplitComplementHarmony
|
||||
* @param {Number} color The color to base the harmony on
|
||||
* @param {Number} threshold Control how adjacent the colors will be to the Complement (default +- 30 degrees)
|
||||
* @return {Object} An object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color)
|
||||
*/
|
||||
getSplitComplementHarmony: function (color, threshold) {
|
||||
if (typeof threshold === "undefined") { threshold = 30; }
|
||||
var hsv = Phaser.Color.RGBtoHSV(color);
|
||||
if(threshold >= 359 || threshold <= 0) {
|
||||
throw new Error("Phaser.Color Warning: Invalid threshold given to getSplitComplementHarmony()");
|
||||
}
|
||||
var opposite = Phaser.Color.game.math.wrapValue(hsv.hue, 180, 359);
|
||||
var warmer = Phaser.Color.game.math.wrapValue(hsv.hue, opposite - threshold, 359);
|
||||
var colder = Phaser.Color.game.math.wrapValue(hsv.hue, opposite + threshold, 359);
|
||||
return {
|
||||
color1: color,
|
||||
color2: Phaser.Color.HSVtoRGB(warmer, hsv.saturation, hsv.value),
|
||||
color3: Phaser.Color.HSVtoRGB(colder, hsv.saturation, hsv.value),
|
||||
hue1: hsv.hue,
|
||||
hue2: warmer,
|
||||
hue3: colder
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a Triadic Color Harmony for the given color.
|
||||
* <p>A Triadic harmony are 3 hues equidistant from each other on the color wheel</p>
|
||||
* <p>Values returned in 0xAARRGGBB format with Alpha set to 255.</p>
|
||||
*
|
||||
* @method getTriadicHarmony
|
||||
* @param {Number} color The color to base the harmony on.
|
||||
* @return {Object} An Object containing 3 properties: color1 (the original color), color2 and color3 (the equidistant colors)
|
||||
*/
|
||||
getTriadicHarmony: function (color) {
|
||||
var hsv = Phaser.Color.RGBtoHSV(color);
|
||||
var triadic1 = Phaser.Color.game.math.wrapValue(hsv.hue, 120, 359);
|
||||
var triadic2 = Phaser.Color.game.math.wrapValue(triadic1, 120, 359);
|
||||
return {
|
||||
color1: color,
|
||||
color2: Phaser.Color.HSVtoRGB(triadic1, 1.0, 1.0),
|
||||
color3: Phaser.Color.HSVtoRGB(triadic2, 1.0, 1.0)
|
||||
};
|
||||
}
|
||||
|
||||
};
|
|
@ -1,926 +0,0 @@
|
|||
/* jshint asi:true,camelcase:false,curly:false,indent:2,unused:false */
|
||||
/*
|
||||
amiga protracker module player for web audio api
|
||||
(c) 2012-2013 firehawk/tda (firehawk@haxor.fi)
|
||||
|
||||
originally hacked together in a weekend, so please excuse
|
||||
me for the spaghetti code. :)
|
||||
|
||||
AMIGAAAAAAAAH!!
|
||||
|
||||
kinda sorta changelog:
|
||||
(apr 2013)
|
||||
- changed the logic for pattern break/jump. mod.pattern_skank now
|
||||
plays correctly.
|
||||
(feb 2013)
|
||||
- fixed NaN samples with mod.fractured and mod.multicolour (thanks Aegis!)
|
||||
(jan 2013)
|
||||
- fixed vibrato amplitude (was half of what it should be, apparently)
|
||||
- fixed to work on safari again (thanks Matt Diamond @ stackoverflow.com)
|
||||
(dec 2012)
|
||||
- replaced effect switch-statement with jumptables
|
||||
- fixed clicks (bad loops, empty samples)
|
||||
- fixed playback bug with sample-only rows
|
||||
- added amiga 500 lowpass filters (not 100% authentic, though)
|
||||
- added compressor to output
|
||||
- latest safari has broken web audio so chrome-only for now
|
||||
(aug 2012)
|
||||
- first version written from scratch
|
||||
|
||||
todo:
|
||||
- safari on ipad is broken again, it seems
|
||||
- fix more playback bugs
|
||||
* mod.black_queen (pattern loop has glitches)
|
||||
- properly test EEx delay pattern
|
||||
- implement the rest of the effects
|
||||
- optimize for more speed!! SPEEEED!!
|
||||
* switch to fixed point sample pointers, Math.floor() is _slow_ on iOS
|
||||
*/
|
||||
|
||||
// constructor for protracker player object
|
||||
function Protracker()
|
||||
{
|
||||
var i, t;
|
||||
|
||||
this.initialize();
|
||||
this.clearsong();
|
||||
|
||||
this.url="";
|
||||
this.loading=false;
|
||||
this.ready=false;
|
||||
this.playing=false;
|
||||
this.buffer=0;
|
||||
this.mixerNode=0;
|
||||
this.paused=false;
|
||||
this.repeat=false;
|
||||
this.separation=true;
|
||||
|
||||
this.palclock=true;
|
||||
|
||||
this.autostart=false;
|
||||
|
||||
this.onReady=function(){};
|
||||
this.onPlay=function(){};
|
||||
this.onStop=function(){};
|
||||
|
||||
// paula period values
|
||||
this.baseperiodtable=new Array(
|
||||
856,808,762,720,678,640,604,570,538,508,480,453,
|
||||
428,404,381,360,339,320,302,285,269,254,240,226,
|
||||
214,202,190,180,170,160,151,143,135,127,120,113);
|
||||
|
||||
// finetune multipliers
|
||||
this.finetunetable=[];
|
||||
for(t=0;t<16;t++) this.finetunetable[t]=Math.pow(2, (t-8)/12/8);
|
||||
|
||||
// calc tables for vibrato waveforms
|
||||
this.vibratotable=[];
|
||||
for(t=0;t<4;t++) {
|
||||
this.vibratotable[t]=[];
|
||||
for(var i=0;i<64;i++) {
|
||||
switch(t) {
|
||||
case 0:
|
||||
this.vibratotable[t][i]=127*Math.sin(Math.PI*2*(i/64));
|
||||
break;
|
||||
case 1:
|
||||
this.vibratotable[t][i]=127-4*i;
|
||||
break;
|
||||
case 2:
|
||||
this.vibratotable[t][i]=(i<32)?127:-127;
|
||||
break;
|
||||
case 3:
|
||||
this.vibratotable[t][i]=(1-2*Math.random())*127;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// effect jumptables
|
||||
this.effects_t0 = new Array(
|
||||
this.effect_t0_0, this.effect_t0_1, this.effect_t0_2, this.effect_t0_3, this.effect_t0_4, this.effect_t0_5, this.effect_t0_6, this.effect_t0_7,
|
||||
this.effect_t0_8, this.effect_t0_9, this.effect_t0_a, this.effect_t0_b, this.effect_t0_c, this.effect_t0_d, this.effect_t0_e, this.effect_t0_f);
|
||||
this.effects_t0_e = new Array(
|
||||
this.effect_t0_e0, this.effect_t0_e1, this.effect_t0_e2, this.effect_t0_e3, this.effect_t0_e4, this.effect_t0_e5, this.effect_t0_e6, this.effect_t0_e7,
|
||||
this.effect_t0_e8, this.effect_t0_e9, this.effect_t0_ea, this.effect_t0_eb, this.effect_t0_ec, this.effect_t0_ed, this.effect_t0_ee, this.effect_t0_ef);
|
||||
this.effects_t1 = new Array(
|
||||
this.effect_t1_0, this.effect_t1_1, this.effect_t1_2, this.effect_t1_3, this.effect_t1_4, this.effect_t1_5, this.effect_t1_6, this.effect_t1_7,
|
||||
this.effect_t1_8, this.effect_t1_9, this.effect_t1_a, this.effect_t1_b, this.effect_t1_c, this.effect_t1_d, this.effect_t1_e, this.effect_t1_f);
|
||||
this.effects_t1_e = new Array(
|
||||
this.effect_t1_e0, this.effect_t1_e1, this.effect_t1_e2, this.effect_t1_e3, this.effect_t1_e4, this.effect_t1_e5, this.effect_t1_e6, this.effect_t1_e7,
|
||||
this.effect_t1_e8, this.effect_t1_e9, this.effect_t1_ea, this.effect_t1_eb, this.effect_t1_ec, this.effect_t1_ed, this.effect_t1_ee, this.effect_t1_ef);
|
||||
|
||||
this.context = null;
|
||||
this.samplerate=44100;
|
||||
this.bufferlen=2048;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// create the web audio context
|
||||
Protracker.prototype.createContext = function()
|
||||
{
|
||||
/* global webkitAudioContext:false */
|
||||
/* jshint newcap:false */
|
||||
this.context = new webkitAudioContext();
|
||||
this.samplerate=this.context.sampleRate;
|
||||
this.bufferlen=(this.samplerate > 44100) ? 4096 : 2048;
|
||||
|
||||
// fixed filter at 6kHz
|
||||
this.filterNode=this.context.createBiquadFilter();
|
||||
this.filterNode.frequency.value=6000
|
||||
|
||||
// "LED filter" at 3.5kHz - off by default
|
||||
this.lowpassNode=this.context.createBiquadFilter();
|
||||
this.lowpassNode.frequency.value=28867;
|
||||
|
||||
// mixer
|
||||
this.mixerNode=this.context.createJavaScriptNode(this.bufferlen, 1, 2);
|
||||
this.mixerNode.module=this;
|
||||
this.mixerNode.onaudioprocess=Protracker.prototype.mix;
|
||||
|
||||
// compressor for a bit of volume boost
|
||||
this.compressorNode=this.context.createDynamicsCompressor();
|
||||
|
||||
// patch up some cables :)
|
||||
this.mixerNode.connect(this.filterNode);
|
||||
this.filterNode.connect(this.lowpassNode);
|
||||
this.lowpassNode.connect(this.compressorNode);
|
||||
this.compressorNode.connect(this.context.destination);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// play loaded and parsed module with webaudio context
|
||||
Protracker.prototype.play = function()
|
||||
{
|
||||
if (this.context==null) this.createContext();
|
||||
|
||||
if (!this.ready) return false;
|
||||
if (this.paused) {
|
||||
this.paused=false;
|
||||
return true;
|
||||
}
|
||||
this.paused=false;
|
||||
this.initialize();
|
||||
this.flags=1+2;
|
||||
this.playing=true;
|
||||
this.onPlay();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// pause playback
|
||||
Protracker.prototype.pause = function()
|
||||
{
|
||||
if (!this.paused) {
|
||||
this.paused=true;
|
||||
} else {
|
||||
this.paused=false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// stop playback and release webaudio node
|
||||
Protracker.prototype.stop = function()
|
||||
{
|
||||
this.playing=false;
|
||||
this.onStop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// jump positions forward/back
|
||||
Protracker.prototype.jump = function(step)
|
||||
{
|
||||
this.tick=0;
|
||||
this.row=0;
|
||||
this.position+=step;
|
||||
this.flags=1+2;
|
||||
if (this.position<0) this.position=0;
|
||||
if (this.position >= this.songlen) this.stop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// set whether module repeats after songlen
|
||||
Protracker.prototype.setrepeat = function(rep)
|
||||
{
|
||||
this.repeat=rep;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// set stereo separation mode (false=paula, true=betterpaula)
|
||||
Protracker.prototype.setseparation = function(sep)
|
||||
{
|
||||
this.separation=sep;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// set amiga video standard (false=NTSC, true=PAL)
|
||||
Protracker.prototype.setamigatype = function(clock)
|
||||
{
|
||||
this.palclock=clock;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// set autostart to play immediately after loading
|
||||
Protracker.prototype.setautostart = function(st)
|
||||
{
|
||||
this.autostart=st;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// clear song data
|
||||
Protracker.prototype.clearsong = function()
|
||||
{
|
||||
this.title="";
|
||||
this.signature="";
|
||||
this.songlen=1;
|
||||
this.repeatpos=0;
|
||||
this.patterntable=new ArrayBuffer(128);
|
||||
for(var i=0;i<128;i++) this.patterntable[i]=0;
|
||||
|
||||
this.channels=4;
|
||||
|
||||
this.sample=[];
|
||||
this.samples=31;
|
||||
for(var i=0;i<31;i++) {
|
||||
this.sample[i]={};
|
||||
this.sample[i].name="";
|
||||
this.sample[i].length=0;
|
||||
this.sample[i].finetune=0;
|
||||
this.sample[i].volume=64;
|
||||
this.sample[i].loopstart=0;
|
||||
this.sample[i].looplength=0;
|
||||
this.sample[i].data=0;
|
||||
}
|
||||
|
||||
this.patterns=0;
|
||||
this.pattern=[];
|
||||
this.note=[];
|
||||
|
||||
this.looprow=0;
|
||||
this.loopstart=0;
|
||||
this.loopcount=0;
|
||||
|
||||
this.patterndelay=0;
|
||||
this.patternwait=0;
|
||||
}
|
||||
|
||||
|
||||
// initialize all player variables
|
||||
Protracker.prototype.initialize = function()
|
||||
{
|
||||
this.tick=0;
|
||||
this.position=0;
|
||||
this.row=0;
|
||||
this.offset=0;
|
||||
this.flags=0;
|
||||
|
||||
this.speed=6;
|
||||
this.bpm=125;
|
||||
this.breakrow=0;
|
||||
this.patternjump=0;
|
||||
this.patterndelay=0;
|
||||
this.patternwait=0;
|
||||
|
||||
this.channel=[];
|
||||
for(var i=0;i<this.channels;i++) {
|
||||
this.channel[i]={};
|
||||
this.channel[i].sample=0;
|
||||
this.channel[i].period=214;
|
||||
this.channel[i].voiceperiod=214;
|
||||
this.channel[i].note=24;
|
||||
this.channel[i].volume=64;
|
||||
this.channel[i].command=0;
|
||||
this.channel[i].data=0;
|
||||
this.channel[i].samplepos=0;
|
||||
this.channel[i].samplespeed=0;
|
||||
this.channel[i].flags=0;
|
||||
this.channel[i].noteon=0;
|
||||
this.channel[i].slidespeed=0;
|
||||
this.channel[i].slideto=214;
|
||||
this.channel[i].slidetospeed=0;
|
||||
this.channel[i].arpeggio=0;
|
||||
|
||||
this.channel[i].semitone=12;
|
||||
this.channel[i].vibratospeed=0
|
||||
this.channel[i].vibratodepth=0
|
||||
this.channel[i].vibratopos=0;
|
||||
this.channel[i].vibratowave=0;
|
||||
}
|
||||
this.vu=[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// load module from url into local buffer
|
||||
Protracker.prototype.load = function(url)
|
||||
{
|
||||
this.url=url;
|
||||
this.clearsong();
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("GET", this.url, true);
|
||||
request.responseType = "arraybuffer";
|
||||
this.request = request;
|
||||
this.loading=true;
|
||||
var asset = this;
|
||||
request.onload = function() {
|
||||
asset.buffer=new Uint8Array(request.response);
|
||||
asset.parse();
|
||||
if (asset.autostart) asset.play();
|
||||
}
|
||||
request.send();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// parse the module from local buffer
|
||||
Protracker.prototype.parse = function()
|
||||
{
|
||||
var i,j,c;
|
||||
|
||||
if (!this.buffer) return false;
|
||||
|
||||
for(var i=0;i<4;i++) this.signature+=String.fromCharCode(this.buffer[1080+i]);
|
||||
switch (this.signature) {
|
||||
case "M.K.":
|
||||
case "M!K!":
|
||||
case "4CHN":
|
||||
case "FLT4":
|
||||
break;
|
||||
|
||||
case "6CHN":
|
||||
this.channels=6;
|
||||
break;
|
||||
|
||||
case "8CHN":
|
||||
case "FLT8":
|
||||
this.channels=8;
|
||||
break;
|
||||
|
||||
case "28CH":
|
||||
this.channels=28;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
this.vu=[];
|
||||
for(var i=0;i<this.channels;i++) this.vu[i]=0.0;
|
||||
|
||||
i=0;
|
||||
while(this.buffer[i] && i<20)
|
||||
this.title=this.title+String.fromCharCode(this.buffer[i++]);
|
||||
|
||||
for(var i=0;i<this.samples;i++) {
|
||||
var st=20+i*30;
|
||||
j=0;
|
||||
while(this.buffer[st+j] && j<22) {
|
||||
this.sample[i].name+=
|
||||
((this.buffer[st+j]>0x1f) && (this.buffer[st+j]<0x7f)) ?
|
||||
(String.fromCharCode(this.buffer[st+j])) :
|
||||
(" ");
|
||||
j++;
|
||||
}
|
||||
this.sample[i].length=2*(this.buffer[st+22]*256 + this.buffer[st+23]);
|
||||
this.sample[i].finetune=this.buffer[st+24];
|
||||
if (this.sample[i].finetune > 7) this.sample[i].finetune=this.sample[i].finetune-16;
|
||||
this.sample[i].volume=this.buffer[st+25];
|
||||
this.sample[i].loopstart=2*(this.buffer[st+26]*256 + this.buffer[st+27]);
|
||||
this.sample[i].looplength=2*(this.buffer[st+28]*256 + this.buffer[st+29]);
|
||||
if (this.sample[i].looplength==2) this.sample[i].looplength=0;
|
||||
if (this.sample[i].loopstart>this.sample[i].length) {
|
||||
this.sample[i].loopstart=0;
|
||||
this.sample[i].looplength=0;
|
||||
}
|
||||
}
|
||||
|
||||
this.songlen=this.buffer[950];
|
||||
if (this.buffer[951] != 127) this.repeatpos=this.buffer[951];
|
||||
for(var i=0;i<128;i++) {
|
||||
this.patterntable[i]=this.buffer[952+i];
|
||||
if (this.patterntable[i] > this.patterns) this.patterns=this.patterntable[i];
|
||||
}
|
||||
this.patterns+=1;
|
||||
var patlen=4*64*this.channels;
|
||||
|
||||
this.pattern=[];
|
||||
this.note=[];
|
||||
for(var i=0;i<this.patterns;i++) {
|
||||
this.pattern[i]=new Uint8Array(patlen);
|
||||
this.note[i]=new Uint8Array(this.channels*64);
|
||||
for(j=0;j<patlen;j++) this.pattern[i][j]=this.buffer[1084+i*patlen+j];
|
||||
for(j=0;j<64;j++) {
|
||||
for(c=0;c<this.channels;c++) {
|
||||
this.note[i][j*this.channels+c]=0;
|
||||
var n=(this.pattern[i][j*4*this.channels+c*4]&0x0f)<<8 | this.pattern[i][j*4*this.channels+c*4+1];
|
||||
for(var np=0; np<this.baseperiodtable.length; np++) {
|
||||
if (n==this.baseperiodtable[np]) this.note[i][j*this.channels+c]=np;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sst=1084+this.patterns*patlen;
|
||||
for(var i=0;i<this.samples;i++) {
|
||||
this.sample[i].data=new Float32Array(this.sample[i].length);
|
||||
for(j=0;j<this.sample[i].length;j++) {
|
||||
var q=this.buffer[sst+j];
|
||||
if (q<128) {
|
||||
q=q/128.0;
|
||||
} else {
|
||||
q=((q-128)/128.0)-1.0;
|
||||
}
|
||||
|
||||
this.sample[i].data[j]=q;
|
||||
}
|
||||
sst+=this.sample[i].length;
|
||||
}
|
||||
|
||||
this.ready=true;
|
||||
this.loading=false;
|
||||
this.buffer=0;
|
||||
|
||||
if (this.context) this.lowpassNode.frequency.value=28867;
|
||||
|
||||
this.onReady();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// advance player
|
||||
Protracker.prototype.advance=function(mod) {
|
||||
var spd=(((mod.samplerate*60)/mod.bpm)/4)/6;
|
||||
// advance player
|
||||
if (mod.offset>spd) { mod.tick++; mod.offset=0; mod.flags|=1; }
|
||||
if (mod.tick>=mod.speed) {
|
||||
|
||||
if (mod.patterndelay) { // delay pattern
|
||||
if (mod.tick < ((mod.patternwait+1)*mod.speed)) {
|
||||
mod.patternwait++;
|
||||
} else {
|
||||
mod.row++;
|
||||
mod.tick=0;
|
||||
mod.flags|=2;
|
||||
mod.patterndelay=0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if (mod.flags&(16+32+64)) {
|
||||
if (mod.flags&64) { // loop pattern?
|
||||
mod.row=mod.looprow;
|
||||
mod.flags&=0xa1;
|
||||
mod.flags|=2;
|
||||
}
|
||||
else {
|
||||
if (mod.flags&16) { // pattern jump/break?
|
||||
//console.log("break to pattern " + mod.patternjump + " row "+mod.breakrow);
|
||||
mod.position=mod.patternjump;
|
||||
mod.row=mod.breakrow;
|
||||
mod.patternjump=0;
|
||||
mod.breakrow=0;
|
||||
mod.flags&=0xe1;
|
||||
mod.flags|=2;
|
||||
}
|
||||
}
|
||||
mod.tick=0;
|
||||
} else {
|
||||
mod.row++;
|
||||
mod.tick=0;
|
||||
mod.flags|=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mod.row>=64) {
|
||||
mod.position++;
|
||||
mod.row=0;
|
||||
mod.flags|=4;
|
||||
}
|
||||
if (mod.position>=mod.songlen) {
|
||||
if (mod.repeat) {
|
||||
mod.position=0;
|
||||
} else {
|
||||
mod.stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// mix an audio buffer with data
|
||||
Protracker.prototype.mix = function(ape) {
|
||||
var f;
|
||||
var p, pp, n, nn;
|
||||
var mod=ape.srcElement.module;
|
||||
var outp=[];
|
||||
|
||||
var bufs=new Array(ape.outputBuffer.getChannelData(0), ape.outputBuffer.getChannelData(1));
|
||||
var buflen=ape.outputBuffer.length;
|
||||
for(var s=0;s<buflen;s++)
|
||||
{
|
||||
outp[0]=0.0;
|
||||
outp[1]=0.0;
|
||||
|
||||
if (!mod.paused && mod.playing)
|
||||
{
|
||||
mod.advance(mod);
|
||||
|
||||
var och=0;
|
||||
for(var ch=0;ch<mod.channels;ch++)
|
||||
{
|
||||
// calculate playback position
|
||||
p=mod.patterntable[mod.position];
|
||||
pp=mod.row*4*mod.channels + ch*4;
|
||||
if (mod.flags&2) { // new row
|
||||
mod.channel[ch].command=mod.pattern[p][pp+2]&0x0f;
|
||||
mod.channel[ch].data=mod.pattern[p][pp+3];
|
||||
|
||||
if (!(mod.channel[ch].command==0x0e && (mod.channel[ch].data&0xf0)==0xd0)) {
|
||||
n=(mod.pattern[p][pp]&0x0f)<<8 | mod.pattern[p][pp+1];
|
||||
if (n) {
|
||||
// noteon, except if command=3 (porta to note)
|
||||
|
||||
if ((mod.channel[ch].command != 0x03) && (mod.channel[ch].command != 0x05)) {
|
||||
mod.channel[ch].period=n;
|
||||
mod.channel[ch].samplepos=0;
|
||||
if (mod.channel[ch].vibratowave>3) mod.channel[ch].vibratopos=0;
|
||||
mod.channel[ch].flags|=3; // recalc speed
|
||||
mod.channel[ch].noteon=1;
|
||||
} else {
|
||||
mod.channel[ch].slideto=n;
|
||||
|
||||
}
|
||||
}
|
||||
nn=mod.pattern[p][pp+0]&0xf0 | mod.pattern[p][pp+2]>>4;
|
||||
if (nn) {
|
||||
mod.channel[ch].sample=nn-1;
|
||||
|
||||
mod.channel[ch].volume=mod.sample[nn-1].volume;
|
||||
if (!n && (mod.channel[ch].samplepos > mod.sample[nn-1].length)) mod.channel[ch].samplepos=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
mod.channel[ch].voiceperiod=mod.channel[ch].period;
|
||||
if (mod.channel[ch].samplepos===0) mod.sample[ch]=mod.channel[ch].sample;
|
||||
|
||||
|
||||
// kill empty samples
|
||||
if (!mod.sample[mod.channel[ch].sample].length) mod.channel[ch].noteon=0;
|
||||
|
||||
// effects
|
||||
if (mod.flags&1) {
|
||||
if (!mod.tick) {
|
||||
// process only on tick 0
|
||||
mod.effects_t0[mod.channel[ch].command](mod, ch);
|
||||
} else {
|
||||
mod.effects_t1[mod.channel[ch].command](mod, ch);
|
||||
}
|
||||
}
|
||||
|
||||
// recalc note number from period
|
||||
if (mod.channel[ch].flags&2) {
|
||||
for(var np=0; np<mod.baseperiodtable.length; np++)
|
||||
if (mod.baseperiodtable[np]>=mod.channel[ch].period) mod.channel[ch].note=np;
|
||||
mod.channel[ch].semitone=7;
|
||||
if (mod.channel[ch].period>=120)
|
||||
mod.channel[ch].semitone=mod.baseperiodtable[mod.channel[ch].note]-mod.baseperiodtable[mod.channel[ch].note+1];
|
||||
}
|
||||
|
||||
// recalc sample speed and apply finetune
|
||||
if ((mod.channel[ch].flags&1 || mod.flags&2) && mod.channel[ch].voiceperiod)
|
||||
mod.channel[ch].samplespeed=
|
||||
(mod.palclock ? 7093789.2 : 7159090.5)/(mod.channel[ch].voiceperiod*2) * mod.finetunetable[mod.sample[mod.channel[ch].sample].finetune+8] / mod.samplerate;
|
||||
|
||||
// advance vibrato on each new tick
|
||||
if (mod.flags&1) {
|
||||
mod.channel[ch].vibratopos+=mod.channel[ch].vibratospeed;
|
||||
mod.channel[ch].vibratopos&=0x3f;
|
||||
}
|
||||
|
||||
// mix channel to output
|
||||
och=och^(ch&1);
|
||||
f=0.0;
|
||||
if (mod.channel[ch].noteon) {
|
||||
if (mod.sample[mod.channel[ch].sample].length > mod.channel[ch].samplepos)
|
||||
f=(1.0/mod.channels) *
|
||||
(mod.sample[mod.channel[ch].sample].data[Math.floor(mod.channel[ch].samplepos)]*mod.channel[ch].volume)/64.0;
|
||||
outp[och]+=f;
|
||||
mod.channel[ch].samplepos+=mod.channel[ch].samplespeed;
|
||||
}
|
||||
if (s===0) mod.vu[ch]=Math.abs(f);
|
||||
|
||||
// loop or end samples
|
||||
if (mod.channel[ch].noteon) {
|
||||
if (mod.sample[mod.channel[ch].sample].loopstart || mod.sample[mod.channel[ch].sample].looplength) {
|
||||
if (mod.channel[ch].samplepos >= (mod.sample[mod.channel[ch].sample].loopstart+mod.sample[mod.channel[ch].sample].looplength)) {
|
||||
mod.channel[ch].samplepos=mod.sample[mod.channel[ch].sample].loopstart;
|
||||
}
|
||||
} else {
|
||||
if (mod.channel[ch].samplepos >= mod.sample[mod.channel[ch].sample].length) {
|
||||
mod.channel[ch].noteon=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clear channel flags
|
||||
mod.channel[ch].flags=0;
|
||||
}
|
||||
mod.offset++;
|
||||
mod.flags&=0x70;
|
||||
}
|
||||
|
||||
// a more headphone-friendly stereo separation (aka. betterpaula)
|
||||
if (mod.separation) {
|
||||
var t=outp[0];
|
||||
outp[0]=outp[0]*0.6 + outp[1]*0.4;
|
||||
outp[1]=outp[1]*0.6 + t*0.4;
|
||||
}
|
||||
bufs[0][s]=outp[0];
|
||||
bufs[1][s]=outp[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// tick 0 effect functions
|
||||
//
|
||||
Protracker.prototype.effect_t0_0=function(mod, ch) { // 0 arpeggio
|
||||
mod.channel[ch].arpeggio=mod.channel[ch].data;
|
||||
}
|
||||
Protracker.prototype.effect_t0_1=function(mod, ch) { // 1 slide up
|
||||
if (mod.channel[ch].data) mod.channel[ch].slidespeed=mod.channel[ch].data;
|
||||
}
|
||||
Protracker.prototype.effect_t0_2=function(mod, ch) { // 2 slide down
|
||||
if (mod.channel[ch].data) mod.channel[ch].slidespeed=mod.channel[ch].data;
|
||||
}
|
||||
Protracker.prototype.effect_t0_3=function(mod, ch) { // 3 slide to note
|
||||
if (mod.channel[ch].data) mod.channel[ch].slidetospeed=mod.channel[ch].data;
|
||||
}
|
||||
Protracker.prototype.effect_t0_4=function(mod, ch) { // 4 vibrato
|
||||
if (mod.channel[ch].data&0x0f && mod.channel[ch].data&0xf0) {
|
||||
mod.channel[ch].vibratodepth=(mod.channel[ch].data&0x0f);
|
||||
mod.channel[ch].vibratospeed=(mod.channel[ch].data&0xf0)>>4;
|
||||
}
|
||||
mod.channel[ch].voiceperiod+=
|
||||
(mod.channel[ch].vibratodepth/32)*mod.channel[ch].semitone*(mod.vibratotable[mod.channel[ch].vibratowave&3][mod.channel[ch].vibratopos]/127);
|
||||
mod.channel[ch].flags|=1;
|
||||
}
|
||||
Protracker.prototype.effect_t0_5=function(mod, ch) { // 5
|
||||
}
|
||||
Protracker.prototype.effect_t0_6=function(mod, ch) { // 6
|
||||
}
|
||||
Protracker.prototype.effect_t0_7=function(mod, ch) { // 7
|
||||
}
|
||||
Protracker.prototype.effect_t0_8=function(mod, ch) { // 8
|
||||
}
|
||||
Protracker.prototype.effect_t0_9=function(mod, ch) { // 9 set sample offset
|
||||
mod.channel[ch].samplepos=mod.channel[ch].data*256;
|
||||
}
|
||||
Protracker.prototype.effect_t0_a=function(mod, ch) { // a
|
||||
}
|
||||
Protracker.prototype.effect_t0_b=function(mod, ch) { // b pattern jump
|
||||
mod.breakrow=0;
|
||||
mod.patternjump=mod.channel[ch].data;
|
||||
mod.flags|=16;
|
||||
}
|
||||
Protracker.prototype.effect_t0_c=function(mod, ch) { // c set volume
|
||||
mod.channel[ch].volume=mod.channel[ch].data;
|
||||
}
|
||||
Protracker.prototype.effect_t0_d=function(mod, ch) { // d pattern break
|
||||
mod.breakrow=((mod.channel[ch].data&0xf0)>>4)*10 + (mod.channel[ch].data&0x0f);
|
||||
if (!(mod.flags&16)) mod.patternjump=mod.position+1;
|
||||
mod.flags|=16;
|
||||
}
|
||||
Protracker.prototype.effect_t0_e=function(mod, ch) { // e
|
||||
var i=(mod.channel[ch].data&0xf0)>>4;
|
||||
mod.effects_t0_e[i](mod, ch);
|
||||
}
|
||||
Protracker.prototype.effect_t0_f=function(mod, ch) { // f set speed
|
||||
if (mod.channel[ch].data > 32) {
|
||||
mod.bpm=mod.channel[ch].data;
|
||||
} else {
|
||||
if (mod.channel[ch].data) mod.speed=mod.channel[ch].data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// tick 0 effect e functions
|
||||
//
|
||||
Protracker.prototype.effect_t0_e0=function(mod, ch) { // e0 filter on/off
|
||||
if (mod.channel[ch].data&0x0f) {
|
||||
mod.lowpassNode.frequency.value=4280; //3500;
|
||||
} else {
|
||||
mod.lowpassNode.frequency.value=28867;
|
||||
}
|
||||
}
|
||||
Protracker.prototype.effect_t0_e1=function(mod, ch) { // e1 fine slide up
|
||||
mod.channel[ch].period-=mod.channel[ch].data&0x0f;
|
||||
if (mod.channel[ch].period < 113) mod.channel[ch].period=113;
|
||||
}
|
||||
Protracker.prototype.effect_t0_e2=function(mod, ch) { // e2 fine slide down
|
||||
mod.channel[ch].period+=mod.channel[ch].data&0x0f;
|
||||
if (mod.channel[ch].period > 856) mod.channel[ch].period=856;
|
||||
mod.channel[ch].flags|=1;
|
||||
}
|
||||
Protracker.prototype.effect_t0_e3=function(mod, ch) { // e3 set glissando
|
||||
}
|
||||
Protracker.prototype.effect_t0_e4=function(mod, ch) { // e4 set vibrato waveform
|
||||
mod.channel[ch].vibratowave=mod.channel[ch].data&0x07;
|
||||
}
|
||||
Protracker.prototype.effect_t0_e5=function(mod, ch) { // e5 set finetune
|
||||
}
|
||||
Protracker.prototype.effect_t0_e6=function(mod, ch) { // e6 loop pattern
|
||||
if (mod.channel[ch].data&0x0f) {
|
||||
if (mod.loopcount) {
|
||||
mod.loopcount--;
|
||||
} else {
|
||||
mod.loopcount=mod.channel[ch].data&0x0f;
|
||||
}
|
||||
if (mod.loopcount) mod.flags|=64;
|
||||
} else {
|
||||
mod.looprow=mod.row;
|
||||
}
|
||||
}
|
||||
Protracker.prototype.effect_t0_e7=function(mod, ch) { // e7
|
||||
}
|
||||
Protracker.prototype.effect_t0_e8=function(mod, ch) { // e8
|
||||
}
|
||||
Protracker.prototype.effect_t0_e9=function(mod, ch) { // e9
|
||||
}
|
||||
Protracker.prototype.effect_t0_ea=function(mod, ch) { // ea fine volslide up
|
||||
mod.channel[ch].volume+=mod.channel[ch].data&0x0f;
|
||||
if (mod.channel[ch].volume > 64) mod.channel[ch].volume=64;
|
||||
}
|
||||
Protracker.prototype.effect_t0_eb=function(mod, ch) { // eb fine volslide down
|
||||
mod.channel[ch].volume-=mod.channel[ch].data&0x0f;
|
||||
if (mod.channel[ch].volume < 0) mod.channel[ch].volume=0;
|
||||
}
|
||||
Protracker.prototype.effect_t0_ec=function(mod, ch) { // ec
|
||||
}
|
||||
Protracker.prototype.effect_t0_ed=function(mod, ch) { // ed delay sample
|
||||
if (mod.tick==(mod.channel[ch].data&0x0f)) {
|
||||
// start note
|
||||
var p=mod.patterntable[mod.position];
|
||||
var pp=mod.row*4*mod.channels + ch*4;
|
||||
var n=(mod.pattern[p][pp]&0x0f)<<8 | mod.pattern[p][pp+1];
|
||||
if (n) {
|
||||
mod.channel[ch].period=n;
|
||||
mod.channel[ch].voiceperiod=mod.channel[ch].period;
|
||||
mod.channel[ch].samplepos=0;
|
||||
if (mod.channel[ch].vibratowave>3) mod.channel[ch].vibratopos=0;
|
||||
mod.channel[ch].flags|=3; // recalc speed
|
||||
mod.channel[ch].noteon=1;
|
||||
}
|
||||
n=mod.pattern[p][pp+0]&0xf0 | mod.pattern[p][pp+2]>>4;
|
||||
if (n) {
|
||||
mod.channel[ch].sample=n-1;
|
||||
mod.channel[ch].volume=mod.sample[n-1].volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
Protracker.prototype.effect_t0_ee=function(mod, ch) { // ee delay pattern
|
||||
mod.patterndelay=mod.channel[ch].data&0x0f;
|
||||
mod.patternwait=0;
|
||||
}
|
||||
Protracker.prototype.effect_t0_ef=function(mod, ch) { // ef
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// tick 1+ effect functions
|
||||
//
|
||||
Protracker.prototype.effect_t1_0=function(mod, ch) { // 0 arpeggio
|
||||
if (mod.channel[ch].data) {
|
||||
var apn=mod.channel[ch].note;
|
||||
if ((mod.tick%3)==1) apn+=mod.channel[ch].arpeggio>>4;
|
||||
if ((mod.tick%3)==2) apn+=mod.channel[ch].arpeggio&0x0f;
|
||||
if (apn>=0 && apn <= mod.baseperiodtable.length)
|
||||
mod.channel[ch].voiceperiod = mod.baseperiodtable[apn];
|
||||
mod.channel[ch].flags|=1;
|
||||
}
|
||||
}
|
||||
Protracker.prototype.effect_t1_1=function(mod, ch) { // 1 slide up
|
||||
mod.channel[ch].period-=mod.channel[ch].slidespeed;
|
||||
if (mod.channel[ch].period<113) mod.channel[ch].period=113;
|
||||
mod.channel[ch].flags|=3; // recalc speed
|
||||
}
|
||||
Protracker.prototype.effect_t1_2=function(mod, ch) { // 2 slide down
|
||||
mod.channel[ch].period+=mod.channel[ch].slidespeed;
|
||||
if (mod.channel[ch].period>856) mod.channel[ch].period=856;
|
||||
mod.channel[ch].flags|=3; // recalc speed
|
||||
}
|
||||
Protracker.prototype.effect_t1_3=function(mod, ch) { // 3 slide to note
|
||||
if (mod.channel[ch].period < mod.channel[ch].slideto) {
|
||||
mod.channel[ch].period+=mod.channel[ch].slidetospeed;
|
||||
if (mod.channel[ch].period > mod.channel[ch].slideto)
|
||||
mod.channel[ch].period=mod.channel[ch].slideto;
|
||||
}
|
||||
if (mod.channel[ch].period > mod.channel[ch].slideto) {
|
||||
mod.channel[ch].period-=mod.channel[ch].slidetospeed;
|
||||
if (mod.channel[ch].period<mod.channel[ch].slideto)
|
||||
mod.channel[ch].period=mod.channel[ch].slideto;
|
||||
}
|
||||
mod.channel[ch].flags|=3; // recalc speed
|
||||
}
|
||||
Protracker.prototype.effect_t1_4=function(mod, ch) { // 4 vibrato
|
||||
mod.channel[ch].voiceperiod+=
|
||||
(mod.channel[ch].vibratodepth/16)*mod.channel[ch].semitone*(mod.vibratotable[mod.channel[ch].vibratowave&3][mod.channel[ch].vibratopos]/127);
|
||||
mod.channel[ch].flags|=1;
|
||||
}
|
||||
Protracker.prototype.effect_t1_5=function(mod, ch) { // 5 volslide + slide to note
|
||||
mod.effect_t1_3(mod, ch); // slide to note
|
||||
mod.effect_t1_a(mod, ch); // volslide
|
||||
}
|
||||
Protracker.prototype.effect_t1_6=function(mod, ch) { // 6 volslide + vibrato
|
||||
mod.effect_t1_4(mod, ch); // vibrato
|
||||
mod.effect_t1_a(mod, ch); // volslide
|
||||
}
|
||||
Protracker.prototype.effect_t1_7=function(mod, ch) { // 7
|
||||
}
|
||||
Protracker.prototype.effect_t1_8=function(mod, ch) { // 8
|
||||
}
|
||||
Protracker.prototype.effect_t1_9=function(mod, ch) { // 9 set sample offset
|
||||
}
|
||||
Protracker.prototype.effect_t1_a=function(mod, ch) { // a volume slide
|
||||
if (!(mod.channel[ch].data&0x0f)) {
|
||||
// y is zero, slide up
|
||||
mod.channel[ch].volume+=(mod.channel[ch].data>>4);
|
||||
if (mod.channel[ch].volume>64) mod.channel[ch].volume=64;
|
||||
}
|
||||
if (!(mod.channel[ch].data&0xf0)) {
|
||||
// x is zero, slide down
|
||||
mod.channel[ch].volume-=(mod.channel[ch].data&0x0f);
|
||||
if (mod.channel[ch].volume<0) mod.channel[ch].volume=0;
|
||||
}
|
||||
}
|
||||
Protracker.prototype.effect_t1_b=function(mod, ch) { // b pattern jump
|
||||
}
|
||||
Protracker.prototype.effect_t1_c=function(mod, ch) { // c set volume
|
||||
}
|
||||
Protracker.prototype.effect_t1_d=function(mod, ch) { // d pattern break
|
||||
}
|
||||
Protracker.prototype.effect_t1_e=function(mod, ch) { // e
|
||||
var i=(mod.channel[ch].data&0xf0)>>4;
|
||||
mod.effects_t1_e[i](mod, ch);
|
||||
}
|
||||
Protracker.prototype.effect_t1_f=function(mod, ch) { // f
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// tick 1+ effect e functions
|
||||
//
|
||||
Protracker.prototype.effect_t1_e0=function(mod, ch) { // e0
|
||||
}
|
||||
Protracker.prototype.effect_t1_e1=function(mod, ch) { // e1
|
||||
}
|
||||
Protracker.prototype.effect_t1_e2=function(mod, ch) { // e2
|
||||
}
|
||||
Protracker.prototype.effect_t1_e3=function(mod, ch) { // e3
|
||||
}
|
||||
Protracker.prototype.effect_t1_e4=function(mod, ch) { // e4
|
||||
}
|
||||
Protracker.prototype.effect_t1_e5=function(mod, ch) { // e5
|
||||
}
|
||||
Protracker.prototype.effect_t1_e6=function(mod, ch) { // e6
|
||||
}
|
||||
Protracker.prototype.effect_t1_e7=function(mod, ch) { // e7
|
||||
}
|
||||
Protracker.prototype.effect_t1_e8=function(mod, ch) { // e8
|
||||
}
|
||||
Protracker.prototype.effect_t1_e9=function(mod, ch) { // e9 retrig sample
|
||||
if (mod.tick%(mod.channel[ch].data&0x0f)===0)
|
||||
mod.channel[ch].samplepos=0;
|
||||
}
|
||||
Protracker.prototype.effect_t1_ea=function(mod, ch) { // ea
|
||||
}
|
||||
Protracker.prototype.effect_t1_eb=function(mod, ch) { // eb
|
||||
}
|
||||
Protracker.prototype.effect_t1_ec=function(mod, ch) { // ec cut sample
|
||||
if (mod.tick==(mod.channel[ch].data&0x0f))
|
||||
mod.channel[ch].volume=0;
|
||||
}
|
||||
Protracker.prototype.effect_t1_ed=function(mod, ch) { // ed delay sample
|
||||
mod.effect_t0_ed(mod, ch);
|
||||
}
|
||||
Protracker.prototype.effect_t1_ee=function(mod, ch) { // ee
|
||||
}
|
||||
Protracker.prototype.effect_t1_ef=function(mod, ch) { // ef
|
||||
}
|
|
@ -1,287 +0,0 @@
|
|||
/**
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @copyright 2014 Photon Storm Ltd.
|
||||
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Javascript QuadTree
|
||||
* @version 1.0
|
||||
* @author Timo Hausmann
|
||||
*
|
||||
* @version 1.2, September 4th 2013
|
||||
* @author Richard Davey
|
||||
* The original code was a conversion of the Java code posted to GameDevTuts. However I've tweaked
|
||||
* it massively to add node indexing, removed lots of temp. var creation and significantly
|
||||
* increased performance as a result.
|
||||
*
|
||||
* Original version at https://github.com/timohausmann/quadtree-js/
|
||||
*/
|
||||
|
||||
/**
|
||||
* @copyright © 2012 Timo Hausmann
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* QuadTree Constructor
|
||||
*
|
||||
* @class Phaser.QuadTree
|
||||
* @classdesc A QuadTree implementation. The original code was a conversion of the Java code posted to GameDevTuts.
|
||||
* However I've tweaked it massively to add node indexing, removed lots of temp. var creation and significantly increased performance as a result.
|
||||
* Original version at https://github.com/timohausmann/quadtree-js/
|
||||
* @constructor
|
||||
* @param {number} x - The top left coordinate of the quadtree.
|
||||
* @param {number} y - The top left coordinate of the quadtree.
|
||||
* @param {number} width - The width of the quadtree in pixels.
|
||||
* @param {number} height - The height of the quadtree in pixels.
|
||||
* @param {number} [maxObjects=10] - The maximum number of objects per node.
|
||||
* @param {number} [maxLevels=4] - The maximum number of levels to iterate to.
|
||||
* @param {number} [level=0] - Which level is this?
|
||||
*/
|
||||
Phaser.QuadTree = function (x, y, width, height, maxObjects, maxLevels, level) {
|
||||
|
||||
this.maxObjects = maxObjects || 10;
|
||||
this.maxLevels = maxLevels || 4;
|
||||
this.level = level || 0;
|
||||
|
||||
this.bounds = {
|
||||
x: Math.round(x),
|
||||
y: Math.round(y),
|
||||
width: width,
|
||||
height: height,
|
||||
subWidth: Math.floor(width / 2),
|
||||
subHeight: Math.floor(height / 2),
|
||||
right: Math.round(x) + Math.floor(width / 2),
|
||||
bottom: Math.round(y) + Math.floor(height / 2)
|
||||
};
|
||||
|
||||
this.objects = [];
|
||||
this.nodes = [];
|
||||
|
||||
};
|
||||
|
||||
Phaser.QuadTree.prototype = {
|
||||
|
||||
/*
|
||||
* Populates this quadtree with the members of the given Group.
|
||||
*
|
||||
* @method Phaser.QuadTree#populate
|
||||
* @param {Phaser.Group} group - The Group to add to the quadtree.
|
||||
*/
|
||||
populate: function (group) {
|
||||
|
||||
group.forEach(this.populateHandler, this, true);
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
* Handler for the populate method.
|
||||
*
|
||||
* @method Phaser.QuadTree#populateHandler
|
||||
* @param {Phaser.Sprite} sprite - The Sprite to check.
|
||||
*/
|
||||
populateHandler: function (sprite) {
|
||||
|
||||
if (sprite.body && sprite.body.checkCollision.none === false && sprite.alive)
|
||||
{
|
||||
this.insert(sprite.body);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
* Split the node into 4 subnodes
|
||||
*
|
||||
* @method Phaser.QuadTree#split
|
||||
*/
|
||||
split: function () {
|
||||
|
||||
this.level++;
|
||||
|
||||
// top right node
|
||||
this.nodes[0] = new Phaser.QuadTree(this.bounds.right, this.bounds.y, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level);
|
||||
|
||||
// top left node
|
||||
this.nodes[1] = new Phaser.QuadTree(this.bounds.x, this.bounds.y, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level);
|
||||
|
||||
// bottom left node
|
||||
this.nodes[2] = new Phaser.QuadTree(this.bounds.x, this.bounds.bottom, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level);
|
||||
|
||||
// bottom right node
|
||||
this.nodes[3] = new Phaser.QuadTree(this.bounds.right, this.bounds.bottom, this.bounds.subWidth, this.bounds.subHeight, this.maxObjects, this.maxLevels, this.level);
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
* Insert the object into the node. If the node exceeds the capacity, it will split and add all objects to their corresponding subnodes.
|
||||
*
|
||||
* @method Phaser.QuadTree#insert
|
||||
* @param {Phaser.Physics.Arcade.Body|object} body - The Body object to insert into the quadtree.
|
||||
*/
|
||||
insert: function (body) {
|
||||
|
||||
var i = 0;
|
||||
var index;
|
||||
|
||||
// if we have subnodes ...
|
||||
if (this.nodes[0] != null)
|
||||
{
|
||||
index = this.getIndex(body);
|
||||
|
||||
if (index !== -1)
|
||||
{
|
||||
this.nodes[index].insert(body);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.objects.push(body);
|
||||
|
||||
if (this.objects.length > this.maxObjects && this.level < this.maxLevels)
|
||||
{
|
||||
// Split if we don't already have subnodes
|
||||
if (this.nodes[0] == null)
|
||||
{
|
||||
this.split();
|
||||
}
|
||||
|
||||
// Add objects to subnodes
|
||||
while (i < this.objects.length)
|
||||
{
|
||||
index = this.getIndex(this.objects[i]);
|
||||
|
||||
if (index !== -1)
|
||||
{
|
||||
// this is expensive - see what we can do about it
|
||||
this.nodes[index].insert(this.objects.splice(i, 1)[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
* Determine which node the object belongs to.
|
||||
*
|
||||
* @method Phaser.QuadTree#getIndex
|
||||
* @param {Phaser.Rectangle|object} rect - The bounds in which to check.
|
||||
* @return {number} index - Index of the subnode (0-3), or -1 if rect cannot completely fit within a subnode and is part of the parent node.
|
||||
*/
|
||||
getIndex: function (rect) {
|
||||
|
||||
// default is that rect doesn't fit, i.e. it straddles the internal quadrants
|
||||
var index = -1;
|
||||
|
||||
if (rect.x < this.bounds.right && rect.right < this.bounds.right)
|
||||
{
|
||||
if ((rect.y < this.bounds.bottom && rect.bottom < this.bounds.bottom))
|
||||
{
|
||||
// rect fits within the top-left quadrant of this quadtree
|
||||
index = 1;
|
||||
}
|
||||
else if ((rect.y > this.bounds.bottom))
|
||||
{
|
||||
// rect fits within the bottom-left quadrant of this quadtree
|
||||
index = 2;
|
||||
}
|
||||
}
|
||||
else if (rect.x > this.bounds.right)
|
||||
{
|
||||
// rect can completely fit within the right quadrants
|
||||
if ((rect.y < this.bounds.bottom && rect.bottom < this.bounds.bottom))
|
||||
{
|
||||
// rect fits within the top-right quadrant of this quadtree
|
||||
index = 0;
|
||||
}
|
||||
else if ((rect.y > this.bounds.bottom))
|
||||
{
|
||||
// rect fits within the bottom-right quadrant of this quadtree
|
||||
index = 3;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
* Return all objects that could collide with the given Sprite.
|
||||
*
|
||||
* @method Phaser.QuadTree#retrieve
|
||||
* @param {Phaser.Sprite} sprite - The sprite to check against.
|
||||
* @return {array} - Array with all detected objects.
|
||||
*/
|
||||
retrieve: function (sprite) {
|
||||
|
||||
var returnObjects = this.objects;
|
||||
|
||||
sprite.body.quadTreeIndex = this.getIndex(sprite.body);
|
||||
|
||||
// Temp store for the node IDs this sprite is in, we can use this for fast elimination later
|
||||
// sprite.body.quadTreeIDs.push(this.ID);
|
||||
|
||||
if (this.nodes[0])
|
||||
{
|
||||
// if rect fits into a subnode ..
|
||||
if (sprite.body.quadTreeIndex !== -1)
|
||||
{
|
||||
returnObjects = returnObjects.concat(this.nodes[sprite.body.quadTreeIndex].retrieve(sprite));
|
||||
}
|
||||
else
|
||||
{
|
||||
// if rect does not fit into a subnode, check it against all subnodes (unrolled for speed)
|
||||
returnObjects = returnObjects.concat(this.nodes[0].retrieve(sprite));
|
||||
returnObjects = returnObjects.concat(this.nodes[1].retrieve(sprite));
|
||||
returnObjects = returnObjects.concat(this.nodes[2].retrieve(sprite));
|
||||
returnObjects = returnObjects.concat(this.nodes[3].retrieve(sprite));
|
||||
}
|
||||
}
|
||||
|
||||
return returnObjects;
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
* Clear the quadtree.
|
||||
* @method Phaser.QuadTree#clear
|
||||
*/
|
||||
clear: function () {
|
||||
|
||||
this.objects = [];
|
||||
|
||||
for (var i = 0, len = this.nodes.length; i < len; i++)
|
||||
{
|
||||
if (this.nodes[i])
|
||||
{
|
||||
this.nodes[i].clear();
|
||||
delete this.nodes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Phaser.QuadTree.prototype.constructor = Phaser.QuadTree;
|
|
@ -1,37 +0,0 @@
|
|||
/**
|
||||
* A Sample Plugin demonstrating how to hook into the Phaser plugin system.
|
||||
*/
|
||||
Phaser.Plugin.SamplePlugin = function (game, parent) {
|
||||
|
||||
Phaser.Plugin.call(this, game, parent);
|
||||
|
||||
this.sprite = null;
|
||||
|
||||
};
|
||||
|
||||
// Extends the Phaser.Plugin template, setting up values we need
|
||||
Phaser.Plugin.SamplePlugin.prototype = Object.create(Phaser.Plugin.prototype);
|
||||
Phaser.Plugin.SamplePlugin.prototype.constructor = Phaser.Plugin.SamplePlugin;
|
||||
|
||||
/**
|
||||
* Add a Sprite reference to this Plugin.
|
||||
* All this plugin does is move the Sprite across the screen slowly.
|
||||
* @type {Phaser.Sprite}
|
||||
*/
|
||||
Phaser.Plugin.SamplePlugin.prototype.addSprite = function (sprite) {
|
||||
|
||||
this.sprite = sprite;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* This is run when the plugins update during the core game loop.
|
||||
*/
|
||||
Phaser.Plugin.SamplePlugin.prototype.update = function () {
|
||||
|
||||
if (this.sprite)
|
||||
{
|
||||
this.sprite.x += 0.5;
|
||||
}
|
||||
|
||||
};
|
|
@ -1,653 +0,0 @@
|
|||
/**
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @copyright 2014 Photon Storm Ltd.
|
||||
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates an object that is placed within a layer of a Phaser.Tilemap and can be moved around and rotated using the direction commands.
|
||||
*
|
||||
* @class Phaser.Plugin.TilemapWalker
|
||||
* @constructor
|
||||
* @param {Phaser.Game} game - Game reference to the currently running game.
|
||||
* @param {Phaser.Tilemap} map - A reference to the Tilemap this TilemapWalker belongs to.
|
||||
* @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to this.currentLayer.
|
||||
* @param {number} x - X position of the top left of the area to copy (given in tiles, not pixels)
|
||||
* @param {number} y - Y position of the top left of the area to copy (given in tiles, not pixels)
|
||||
* @return {Phaser.Plugin.TilemapWalker}
|
||||
*/
|
||||
Phaser.Plugin.TilemapWalker = function (game, map, layer, x, y) {
|
||||
|
||||
/**
|
||||
* @property {Phaser.Game} game - A reference to the currently running Game.
|
||||
*/
|
||||
this.game = game;
|
||||
|
||||
/**
|
||||
* @property {Phaser.Tilemap} map - A reference to the Tilemap this TilemapWalker belongs to.
|
||||
*/
|
||||
this.map = map;
|
||||
|
||||
/**
|
||||
* @property {number} locationLayer - The current layer of the location marker.
|
||||
*/
|
||||
this.locationLayer = map.getLayer(layer);
|
||||
|
||||
/**
|
||||
* @property {Phaser.Point} location - The current marker location. You can move the marker with the movement methods.
|
||||
*/
|
||||
this.location = new Phaser.Point();
|
||||
|
||||
/**
|
||||
* @property {number} facing - The direction the location marker is facing. You can rotate it using the turn and face methods.
|
||||
* @default
|
||||
*/
|
||||
this.facing = Phaser.Tilemap.NORTH;
|
||||
|
||||
/**
|
||||
* @property {boolean} collides - Does the TilemapWalker collide with the tiles in the map set for collision? If so it cannot move through them.
|
||||
* @default
|
||||
*/
|
||||
this.collides = true;
|
||||
|
||||
/**
|
||||
* @property {array} history - An array containing a history of movements through the map.
|
||||
*/
|
||||
this.history = [];
|
||||
|
||||
// TODO: History limit, History scan, record how many times walker has been on a tile before
|
||||
|
||||
if (typeof x !== 'undefined' && typeof y !== 'undefined')
|
||||
{
|
||||
this.setLocation(x, y);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.TilemapWalker.prototype = {
|
||||
|
||||
/**
|
||||
* Sets the location marker to the given x/y coordinates within the map.
|
||||
* Once set you can move the marker around via the movement and turn methods.
|
||||
*
|
||||
* @method Phaser.Tilemap#setLocation
|
||||
* @param {number} x - X position of the top left of the area to copy (given in tiles, not pixels)
|
||||
* @param {number} y - Y position of the top left of the area to copy (given in tiles, not pixels)
|
||||
* @param {number|string|Phaser.TilemapLayer} [layer] - The layer to operate on. If not given will default to this.currentLayer.
|
||||
* @return {boolean} True if the location could be set, otherwise false.
|
||||
*/
|
||||
setLocation: function (x, y, layer) {
|
||||
|
||||
if (this.checkTile(x, y))
|
||||
{
|
||||
this.location.set(x, y);
|
||||
this.history.push( { x: x, y: y });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the given x/y coordinate has a tile into which we can move.
|
||||
*
|
||||
* @method Phaser.Tilemap#checkTile
|
||||
* @param {number} x - X position of the top left of the area to copy (given in tiles, not pixels)
|
||||
* @param {number} y - Y position of the top left of the area to copy (given in tiles, not pixels)
|
||||
* @return {boolean} True if the location can be moved into, false if not.
|
||||
*/
|
||||
checkTile: function (x, y) {
|
||||
|
||||
if (this.map.hasTile(x, y, this.locationLayer))
|
||||
{
|
||||
if (this.collides)
|
||||
{
|
||||
var tile = this.map.getTile(x, y, this.locationLayer);
|
||||
|
||||
if (tile && tile.collides)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
},
|
||||
|
||||
updateLocation: function (x, y) {
|
||||
|
||||
if (this.checkTile(this.location.x + x, this.location.y + y, this.locationLayer))
|
||||
{
|
||||
this.location.set(this.location.x + x, this.location.y + y);
|
||||
this.history.push( { x: x, y: y });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
},
|
||||
|
||||
moveForward: function () {
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.updateLocation(0, -1);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.updateLocation(1, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.updateLocation(0, 1);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.updateLocation(-1, 0);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
moveBackward: function () {
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.updateLocation(0, 1);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.updateLocation(-1, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.updateLocation(0, -1);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.updateLocation(1, 0);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
moveLeft: function () {
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.updateLocation(-1, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.updateLocation(0, -1);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.updateLocation(1, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.updateLocation(0, 1);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
moveRight: function () {
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.updateLocation(1, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.updateLocation(0, 1);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.updateLocation(-1, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.updateLocation(0, -1);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
turnLeft: function () {
|
||||
|
||||
this.facing--;
|
||||
|
||||
if (this.facing === -1)
|
||||
{
|
||||
this.facing = 3;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
turnRight: function () {
|
||||
|
||||
this.facing++;
|
||||
|
||||
if (this.facing === 4)
|
||||
{
|
||||
this.facing = 0;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
putTile: function (index) {
|
||||
|
||||
this.map.putTile(index, this.location.x, this.location.y, this.locationLayer);
|
||||
|
||||
},
|
||||
|
||||
getTileFromLocation: function (x, y) {
|
||||
|
||||
return this.map.getTile(this.location.x + x, this.location.y + y, this.locationLayer, true);
|
||||
|
||||
},
|
||||
|
||||
getTile: function () {
|
||||
|
||||
return this.map.getTile(this.location.x, this.location.y, this.locationLayer, true);
|
||||
|
||||
},
|
||||
|
||||
getTiles: function (width, height, center) {
|
||||
|
||||
var startX;
|
||||
var startX;
|
||||
var endX;
|
||||
var endY;
|
||||
var incX;
|
||||
var incY;
|
||||
|
||||
var hw = Math.floor(width / 2);
|
||||
var hh = Math.floor(height / 2);
|
||||
|
||||
// For now we assume that center = bottom middle tile
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
startX = this.location.x - hw;
|
||||
endX = this.location.x + hw;
|
||||
incX = 1;
|
||||
|
||||
// bottom middle align
|
||||
startY = this.location.y - (height - 1);
|
||||
endY = this.location.y;
|
||||
incY = 1;
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
startX = this.location.x;
|
||||
endX = this.location.x + (width - 1);
|
||||
incX = 1;
|
||||
|
||||
// bottom middle align
|
||||
startY = this.location.y - hh;
|
||||
endY = this.location.y + hh;
|
||||
incY = 1;
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
startX = this.location.x - hw;
|
||||
endX = this.location.x + hw;
|
||||
incX = 1;
|
||||
|
||||
// bottom middle align
|
||||
startY = this.location.y;
|
||||
endY = this.location.y + (height - 1);
|
||||
incY = 1;
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
startX = this.location.x - (width - 1);
|
||||
endX = this.location.x;
|
||||
incX = 1;
|
||||
|
||||
// bottom middle align
|
||||
startY = this.location.y - hh;
|
||||
endY = this.location.y + hh;
|
||||
incY = 1;
|
||||
}
|
||||
|
||||
var output = [];
|
||||
var row = [];
|
||||
|
||||
for (var y = startY; y <= endY; y += incY)
|
||||
{
|
||||
row = [];
|
||||
|
||||
for (var x = startX; x <= endX; x += incX)
|
||||
{
|
||||
var tile = this.map.getTile(x, y, this.locationLayer, true);
|
||||
|
||||
if (tile)
|
||||
{
|
||||
row.push(tile.index);
|
||||
}
|
||||
else
|
||||
{
|
||||
// out of bounds, so block it off
|
||||
row.push(2);
|
||||
}
|
||||
}
|
||||
|
||||
output.push(row);
|
||||
}
|
||||
|
||||
// console.log(printMatrix(output));
|
||||
|
||||
if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
output = rotateMatrix(output, 90);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
output = rotateMatrix(output, 180);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
output = rotateMatrix(output, -90);
|
||||
}
|
||||
|
||||
// console.log('rotate');
|
||||
console.log(printMatrix(output));
|
||||
|
||||
return output;
|
||||
|
||||
},
|
||||
|
||||
getTileAhead: function (distance) {
|
||||
|
||||
if (typeof distance === 'undefined') { distance = 1; }
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.getTileFromLocation(0, -distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.getTileFromLocation(distance, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.getTileFromLocation(0, distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, 0);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getTileAheadLeft: function (distance) {
|
||||
|
||||
if (typeof distance === 'undefined') { distance = 1; }
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, -distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.getTileFromLocation(distance, -distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.getTileFromLocation(distance, distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, distance);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getTileAheadRight: function (distance) {
|
||||
|
||||
if (typeof distance === 'undefined') { distance = 1; }
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.getTileFromLocation(distance, -distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.getTileFromLocation(distance, distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, -distance);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getTileBehind: function (distance) {
|
||||
|
||||
if (typeof distance === 'undefined') { distance = 1; }
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.getTileFromLocation(0, distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.getTileFromLocation(0, -distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.getTileFromLocation(distance, 0);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getTileBehindLeft: function (distance) {
|
||||
|
||||
if (typeof distance === 'undefined') { distance = 1; }
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, -distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.getTileFromLocation(distance, -distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.getTileFromLocation(distance, distance);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getTileBehindRight: function (distance) {
|
||||
|
||||
if (typeof distance === 'undefined') { distance = 1; }
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.getTileFromLocation(distance, distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, -distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.getTileFromLocation(distance, -distance);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getTileLeft: function (distance) {
|
||||
|
||||
if (typeof distance === 'undefined') { distance = 1; }
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.getTileFromLocation(0, -distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.getTileFromLocation(distance, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.getTileFromLocation(0, distance);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getTileRight: function (distance) {
|
||||
|
||||
if (typeof distance === 'undefined') { distance = 1; }
|
||||
|
||||
if (this.facing === Phaser.Tilemap.NORTH)
|
||||
{
|
||||
return this.getTileFromLocation(distance, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.EAST)
|
||||
{
|
||||
return this.getTileFromLocation(0, distance);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.SOUTH)
|
||||
{
|
||||
return this.getTileFromLocation(-distance, 0);
|
||||
}
|
||||
else if (this.facing === Phaser.Tilemap.WEST)
|
||||
{
|
||||
return this.getTileFromLocation(0, -distance);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Original from http://jsfiddle.net/MrPolywhirl/NH42z/ - tided up and de-globalised by Richard Davey
|
||||
var rotateMatrix = function (matrix, direction) {
|
||||
|
||||
direction = ((direction % 360) + 360) % 360;
|
||||
|
||||
var ret = matrix;
|
||||
|
||||
var transpose = function (m) {
|
||||
var result = new Array(m[0].length);
|
||||
for (var i = 0; i < m[0].length; i++) {
|
||||
result[i] = new Array(m.length - 1);
|
||||
for (var j = m.length - 1; j > -1; j--) {
|
||||
result[i][j] = m[j][i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
var reverseRows = function (m) {
|
||||
return m.reverse();
|
||||
};
|
||||
|
||||
var reverseCols = function (m) {
|
||||
for (var i = 0; i < m.length; i++) {
|
||||
m[i].reverse();
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
var rotate90Left = function (m) {
|
||||
m = transpose(m);
|
||||
m = reverseRows(m);
|
||||
return m;
|
||||
};
|
||||
|
||||
var rotate90Right = function (m) {
|
||||
m = reverseRows(m);
|
||||
m = transpose(m);
|
||||
return m;
|
||||
};
|
||||
|
||||
var rotate180 = function (m) {
|
||||
m = reverseCols(m);
|
||||
m = reverseRows(m);
|
||||
return m;
|
||||
};
|
||||
|
||||
if (direction == 90 || direction == -270) {
|
||||
return rotate90Left(ret);
|
||||
} else if (direction == -90 || direction == 270) {
|
||||
return rotate90Right(ret);
|
||||
} else if (Math.abs(direction) == 180) {
|
||||
return rotate180(ret);
|
||||
}
|
||||
|
||||
return matrix;
|
||||
};
|
||||
|
||||
var pad = function (val, amt, ch) {
|
||||
ch = typeof ch !== 'undefined' ? ch : ' ';
|
||||
var str = val
|
||||
var max = Math.abs(amt);
|
||||
while (str.length < max) {
|
||||
if (amt < 0) {
|
||||
str += ch;
|
||||
} else {
|
||||
str = ch + str;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
var printMatrix = function (matrix) {
|
||||
var str = '';
|
||||
for (var r = 0; r < matrix.length; r++) {
|
||||
for (var c = 0; c < matrix[r].length; c++) {
|
||||
var cell = matrix[r][c].toString();
|
||||
if (cell != 'undefined') {
|
||||
str += pad(cell, 2);
|
||||
} else {
|
||||
str += '?';
|
||||
}
|
||||
if (c < matrix[r].length - 1) {
|
||||
str += ' |';
|
||||
}
|
||||
}
|
||||
if (r < matrix.length - 1) {
|
||||
str += '\n';
|
||||
for (var i = 0; i < matrix[r].length; i++) {
|
||||
str += '---'
|
||||
if (i < matrix[r].length - 1) {
|
||||
str += '+';
|
||||
}
|
||||
}
|
||||
str += '\n';
|
||||
}
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
/**
|
||||
* A Virtual Joystick
|
||||
*/
|
||||
Phaser.Plugin.VirtualJoystick = function (game, parent) {
|
||||
|
||||
Phaser.Plugin.call(this, game, parent);
|
||||
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.limit = 10;
|
||||
|
||||
this.baseCircle;
|
||||
|
||||
this.baseBMD;
|
||||
this.nubBMD;
|
||||
|
||||
this.base;
|
||||
this.nub;
|
||||
|
||||
this.baseCenter;
|
||||
this.nubCenter;
|
||||
|
||||
this.isDragging = false;
|
||||
|
||||
this.angle = 0;
|
||||
this.distance = 0;
|
||||
this.force = 0;
|
||||
this.deltaX = 0;
|
||||
this.deltaY = 0;
|
||||
this.speed = 0;
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.VirtualJoystick.prototype = Object.create(Phaser.Plugin.prototype);
|
||||
Phaser.Plugin.VirtualJoystick.prototype.constructor = Phaser.Plugin.VirtualJoystick;
|
||||
|
||||
Phaser.Plugin.VirtualJoystick.prototype.init = function (x, y, diameter, limit) {
|
||||
|
||||
if (typeof diameter === 'undefined') { diameter = 80; }
|
||||
if (typeof limit === 'undefined') { limit = Math.floor(diameter / 2); }
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
var radius = Math.floor(diameter / 2);
|
||||
var nr = radius - 4;
|
||||
|
||||
this.baseCircle = new Phaser.Circle(x, y, diameter);
|
||||
|
||||
this.baseBMD = this.game.make.bitmapData(diameter, diameter);
|
||||
this.nubBMD = this.game.make.bitmapData(nr * 2, nr * 2);
|
||||
|
||||
this.baseBMD.circle(radius, radius, radius, 'rgb(255, 0, 0)');
|
||||
this.nubBMD.circle(nr, nr, nr, 'rgb(0, 255, 0)');
|
||||
|
||||
// Base
|
||||
this.base = this.game.add.sprite(x, y, this.baseBMD);
|
||||
this.base.anchor.set(0.5);
|
||||
|
||||
// Nub
|
||||
this.nub = this.game.add.sprite(x, y, this.nubBMD);
|
||||
this.nub.anchor.set(0.5);
|
||||
|
||||
this.nub.inputEnabled = true;
|
||||
|
||||
this.nub.events.onInputDown.add(this.startDrag, this);
|
||||
this.nub.events.onInputUp.add(this.stopDrag, this);
|
||||
|
||||
// Need to find a way to not hog this callback
|
||||
this.game.input.setMoveCallback(this.move, this);
|
||||
|
||||
this.isDragging = false;
|
||||
|
||||
this.distance = 0;
|
||||
this.speed = 0;
|
||||
this.force = 0;
|
||||
this.limit = limit;
|
||||
this.limitPoint = new Phaser.Point();
|
||||
|
||||
this.location = new Phaser.Point();
|
||||
|
||||
}
|
||||
|
||||
Phaser.Plugin.VirtualJoystick.prototype.startDrag = function (nub, pointer) {
|
||||
|
||||
this.isDragging = true;
|
||||
|
||||
this.location.set(pointer.x, pointer.y);
|
||||
this.distance = Phaser.Point.distance(this.base, this.location, true);
|
||||
this.angle = this.game.math.wrapAngle(this.location.angle(this.base, true) + 180);
|
||||
this.force = this.game.math.percent(this.distance, this.limit);
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.VirtualJoystick.prototype.stopDrag = function (nub, pointer) {
|
||||
|
||||
this.isDragging = false;
|
||||
|
||||
this.distance = 0;
|
||||
this.angle = 0;
|
||||
this.force = 0;
|
||||
|
||||
this.nub.x = this.base.x;
|
||||
this.nub.y = this.base.y;
|
||||
|
||||
this.limitPoint.set(this.base.x, this.base.y);
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.VirtualJoystick.prototype.move = function (pointer, x, y) {
|
||||
|
||||
if (!this.isDragging)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.location.set(x, y);
|
||||
|
||||
this.distance = Phaser.Point.distance(this.base, this.location, true);
|
||||
|
||||
this.angle = this.game.math.wrapAngle(this.location.angle(this.base, true) + 180);
|
||||
|
||||
this.force = this.game.math.percent(this.distance, this.limit);
|
||||
|
||||
if (this.distance < this.limit)
|
||||
{
|
||||
this.limitPoint.copyFrom(this.location);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.baseCircle.circumferencePoint(this.angle, true, this.limitPoint);
|
||||
}
|
||||
|
||||
this.nub.position.set(this.limitPoint.x, this.limitPoint.y);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Given the speed calculate the velocity and return it as a Point object, or set it to the given point object.
|
||||
* One way to use this is: velocityFromAngle(angle, 200, sprite.velocity) which will set the values directly to the sprites velocity and not create a new Point object.
|
||||
*
|
||||
* @method Phaser.Plugin.VirtualJoystick#setVelocity
|
||||
* @param {Phaser.Sprite} sprite - The Sprite to set the velocity on. The Sprite must have a physics body already set. The value will be set into Sprite.body.velocity.
|
||||
* @param {number} [minSpeed=0] - The minimum speed the Sprite will move if the joystick is at its default (non-moved) position.
|
||||
* @param {number} [maxSpeed=100] - The maximum speed the Sprite will move if the joystick is at its full extent.
|
||||
* @return {Phaser.Sprite} The Sprite object.
|
||||
*/
|
||||
Phaser.Plugin.VirtualJoystick.prototype.setVelocity = function (sprite, minSpeed, maxSpeed) {
|
||||
|
||||
if (typeof minSpeed === 'undefined') { minSpeed = 0; }
|
||||
if (typeof maxSpeed === 'undefined') { maxSpeed = 200; }
|
||||
|
||||
if (this.force === 0 && minSpeed === 0)
|
||||
{
|
||||
sprite.body.velocity.set(0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var speed = (maxSpeed - minSpeed) * this.force;
|
||||
|
||||
sprite.body.velocity.set((Math.cos(this.game.math.degToRad(this.angle)) * speed), (Math.sin(this.game.math.degToRad(this.angle)) * speed));
|
||||
}
|
||||
|
||||
return sprite;
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.VirtualJoystick.prototype.update = function () {
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.VirtualJoystick.prototype.render = function () {
|
||||
|
||||
this.game.debug.text('force: ' + this.force, 32, 32);
|
||||
// this.game.debug.text(this.distance, 32, 32);
|
||||
// this.game.debug.text(this.angle, 132, 32);
|
||||
|
||||
// this.game.debug.text('x: ' + this.location.x + ' y: ' + this.location.y, 32, 64);
|
||||
// this.game.debug.text('x: ' + this.limitPoint.x + ' y: ' + this.limitPoint.y, 32, 64);
|
||||
// this.game.debug.text('x: ' + this.prev.x + ' y: ' + this.prev.y, 32, 64);
|
||||
// this.game.debug.text(Phaser.Point.distance(this.base, this.prev, true), 32, 96);
|
||||
|
||||
this.game.debug.geom(this.limitPoint, 'rgb(255,255,0)');
|
||||
|
||||
};
|
|
@ -1,92 +0,0 @@
|
|||
/**
|
||||
* Provides access to the Webcam (if available)
|
||||
*/
|
||||
Phaser.Plugin.Webcam = function (game, parent) {
|
||||
|
||||
Phaser.Plugin.call(this, game, parent);
|
||||
|
||||
if (!game.device.getUserMedia)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
||||
|
||||
this.context = null;
|
||||
this.stream = null;
|
||||
|
||||
this.video = document.createElement('video');
|
||||
this.video.autoplay = true;
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.Webcam.prototype = Object.create(Phaser.Plugin.prototype);
|
||||
Phaser.Plugin.Webcam.prototype.constructor = Phaser.Plugin.Webcam;
|
||||
|
||||
Phaser.Plugin.Webcam.prototype.start = function (width, height, context) {
|
||||
|
||||
// console.log('Webcam start', width, height);
|
||||
|
||||
this.context = context;
|
||||
|
||||
if (!this.stream)
|
||||
{
|
||||
navigator.getUserMedia( { video: { mandatory: { minWidth: width, minHeight: height } } }, this.connectCallback.bind(this), this.errorCallback.bind(this));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.Webcam.prototype.stop = function () {
|
||||
|
||||
if (this.stream)
|
||||
{
|
||||
this.stream.stop();
|
||||
this.stream = null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.Webcam.prototype.connectCallback = function (stream) {
|
||||
|
||||
this.stream = stream;
|
||||
|
||||
this.video.src = window.URL.createObjectURL(this.stream);
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.Webcam.prototype.errorCallback = function (e) {
|
||||
|
||||
console.log('Video Stream rejected', e);
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.Webcam.prototype.grab = function (context, x, y) {
|
||||
|
||||
if (this.stream)
|
||||
{
|
||||
context.drawImage(this.video, x, y);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Phaser.Plugin.Webcam.prototype.update = function () {
|
||||
|
||||
if (this.stream)
|
||||
{
|
||||
this.context.drawImage(this.video, 0, 0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @name Phaser.Plugin.Webcam#active
|
||||
* @property {boolean} active - Is this Webcam plugin capturing a video stream or not?
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(Phaser.Plugin.Webcam.prototype, "active", {
|
||||
|
||||
get: function() {
|
||||
return (this.stream);
|
||||
}
|
||||
|
||||
});
|
3
plugins/where have they gone.txt
Normal file
3
plugins/where have they gone.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
Phaser Plugins used to be bundled in the main Phaser repo, but in order to help with versioning we've moved them to their own repository:
|
||||
|
||||
https://github.com/photonstorm/phaser-plugins
|
|
@ -341,11 +341,16 @@ Phaser.Stage.prototype.visibilityChange = function (event) {
|
|||
*/
|
||||
Phaser.Stage.prototype.setBackgroundColor = function(backgroundColor)
|
||||
{
|
||||
// console.log('setBackgroundColor');
|
||||
this._backgroundColor = backgroundColor || 0x000000;
|
||||
this.backgroundColorSplit = PIXI.hex2rgb(this.backgroundColor);
|
||||
var hex = this._backgroundColor.toString(16);
|
||||
hex = '000000'.substr(0, 6 - hex.length) + hex;
|
||||
this.backgroundColorString = '#' + hex;
|
||||
// console.log(this._backgroundColor);
|
||||
// console.log(this.backgroundColorSplit);
|
||||
// console.log(hex);
|
||||
// console.log(this.backgroundColorString);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -366,7 +371,9 @@ Object.defineProperty(Phaser.Stage.prototype, "backgroundColor", {
|
|||
{
|
||||
if (typeof color === 'string')
|
||||
{
|
||||
// console.log(color);
|
||||
color = Phaser.Color.hexToRGB(color);
|
||||
// console.log(color);
|
||||
}
|
||||
|
||||
this.setBackgroundColor(color);
|
||||
|
|
Loading…
Add table
Reference in a new issue