Implemented basic A* pathfinding and player chasing. Still has bugs.

This commit is contained in:
2014-06-15 23:14:20 -07:00
parent 8f6186dbf1
commit d605f15578
6 changed files with 240 additions and 740 deletions

View File

@@ -277,7 +277,7 @@
"visible":true,
"width":0,
"x":320,
"y":480
"y":521
},
{
"gid":3544,
@@ -285,6 +285,7 @@
"name":"BigTopCustomer2",
"properties":
{
"sprite_canmove":"true",
"sprite_group":"townsfolk-female",
"sprite_name":"townsfolk-female-2"
},
@@ -300,6 +301,7 @@
"name":"BigTopCustomer2",
"properties":
{
"sprite_canmove":"false",
"sprite_group":"townsfolk-male",
"sprite_name":"townsfolk-male-3"
},

View File

@@ -5,8 +5,7 @@
<title>Moonlight Skulk (Working Title)</title>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="js/phaser.js"></script>
<script type="text/javascript" src="js/PathFinderPlugin.js"></script>
<script type="text/javascript" src="js/easystar-0.1.5.js"></script>
<script type="text/javascript" src="js/pathfinding-browser.min.js"></script>
<style type="text/css">
body {
margin: 0;

View File

@@ -1,110 +0,0 @@
/**
* Constructor.
*
* @param parent
* @constructor
*/
Phaser.Plugin.PathFinderPlugin = function (parent) {
if (typeof EasyStar !== 'object') {
throw new Error("Easystar is not defined!");
}
this.parent = parent;
this._easyStar = new EasyStar.js();
this._grid = null;
this._callback = null;
this._prepared = false;
this._walkables = [0];
};
Phaser.Plugin.PathFinderPlugin.prototype = Object.create(Phaser.Plugin.prototype);
Phaser.Plugin.PathFinderPlugin.prototype.constructor = Phaser.Plugin.PathFinderPlugin;
/**
* Set Grid for Pathfinding.
*
* @param grid Mapdata as a two dimensional array.
* @param walkables Tiles which are walkable. Every other tile is marked as blocked.
* @param iterationsPerCount
*/
Phaser.Plugin.PathFinderPlugin.prototype.setGrid = function (grid, walkables, iterationsPerCount) {
iterationsPerCount = iterationsPerCount || null;
this._grid = [];
for (var i = 0; i < grid.length; i++)
{
this._grid[i] = []
for (var j = 0; j < grid[i].length; j++)
{
if (grid[i][j])
this._grid[i][j] = grid[i][j].index
else
this._grid[i][j] = 0
}
}
this._walkables = walkables;
this._easyStar.setGrid(this._grid);
this._easyStar.setAcceptableTiles(this._walkables);
// initiate all walkable tiles with cost 1 so they will be walkable even if they are not on the grid map, jet.
for (var i = 0; i < walkables.length; i++)
{
this.setTileCost(walkables[i], 1);
}
if (iterationsPerCount !== null) {
this._easyStar.setIterationsPerCalculation(iterationsPerCount);
}
};
/**
* Sets the tile cost for a particular tile type.
*
* @param {Number} The tile type to set the cost for.
* @param {Number} The multiplicative cost associated with the given tile.
*/
Phaser.Plugin.PathFinderPlugin.prototype.setTileCost = function (tileType, cost) {
this._easyStar.setTileCost(tileType, cost);
}
/**
* Set callback function (Uh, really?)
* @param callback
*/
Phaser.Plugin.PathFinderPlugin.prototype.setCallbackFunction = function (callback) {
this._callback = callback;
};
/**
* Prepare pathcalculation for easystar.
*
* @param from array 0: x-coords, 1: y-coords ([x,y])
* @param to array 0: x-coords, 1: y-coords ([x,y])
*/
Phaser.Plugin.PathFinderPlugin.prototype.preparePathCalculation = function (from, to) {
if (this._callback === null || typeof this._callback !== "function") {
throw new Error("No Callback set!");
}
var startX = from[0],
startY = from[1],
destinationX = to[0],
destinationY = to[1];
this._easyStar.findPath(startX, startY, destinationX, destinationY, this._callback);
this._prepared = true;
};
/**
* Start path calculation.
*/
Phaser.Plugin.PathFinderPlugin.prototype.calculatePath = function () {
if (this._prepared === null) {
throw new Error("no Calculation prepared!");
}
this._easyStar.calculate();
};

View File

@@ -1,555 +0,0 @@
//For require.js
if (typeof define === "function" && define.amd) {
define("easystar", [], function() {
return EasyStar;
});
}
//For browserify and node.js
if (typeof module !== 'undefined' && module.exports) {
module.exports = EasyStar;
}
//NameSpace
var EasyStar = EasyStar || {};
/**
* A simple Node that represents a single tile on the grid.
* @param {Object} parent The parent node.
* @param {Number} x The x position on the grid.
* @param {Number} y The y position on the grid.
* @param {Number} costSoFar How far this node is in moves*cost from the start.
* @param {Number} simpleDistanceToTarget Manhatten distance to the end point.
**/
EasyStar.Node = function(parent, x, y, costSoFar, simpleDistanceToTarget) {
this.parent = parent;
this.x = x;
this.y = y;
this.costSoFar = costSoFar;
this.simpleDistanceToTarget = simpleDistanceToTarget;
/**
* @return {Number} Best guess distance of a cost using this node.
**/
this.bestGuessDistance = function() {
return this.costSoFar + this.simpleDistanceToTarget;
}
};
//Constants
EasyStar.Node.OPEN_LIST = 0;
EasyStar.Node.CLOSED_LIST = 1;
/**
* This is an improved Priority Queue data type implementation that can be used to sort any object type.
* It uses a technique called a binary heap.
*
* For more on binary heaps see: http://en.wikipedia.org/wiki/Binary_heap
*
* @param {String} criteria The criteria by which to sort the objects.
* This should be a property of the objects you're sorting.
*
* @param {Number} heapType either PriorityQueue.MAX_HEAP or PriorityQueue.MIN_HEAP.
**/
EasyStar.PriorityQueue = function(criteria,heapType) {
this.length = 0; //The current length of heap.
var queue = [];
var isMax = false;
//Constructor
if (heapType==EasyStar.PriorityQueue.MAX_HEAP) {
isMax = true;
} else if (heapType==EasyStar.PriorityQueue.MIN_HEAP) {
isMax = false;
} else {
throw heapType + " not supported.";
}
/**
* Inserts the value into the heap and sorts it.
*
* @param value The object to insert into the heap.
**/
this.insert = function(value) {
if (!value.hasOwnProperty(criteria)) {
throw "Cannot insert " + value + " because it does not have a property by the name of " + criteria + ".";
}
queue.push(value);
this.length++;
bubbleUp(this.length-1);
}
/**
* Peeks at the highest priority element.
*
* @return the highest priority element
**/
this.getHighestPriorityElement = function() {
return queue[0];
}
/**
* Removes and returns the highest priority element from the queue.
*
* @return the highest priority element
**/
this.shiftHighestPriorityElement = function() {
if (this.length === 0) {
throw ("There are no more elements in your priority queue.");
} else if (this.length === 1) {
var onlyValue = queue[0];
queue = [];
this.length = 0;
return onlyValue;
}
var oldRoot = queue[0];
var newRoot = queue.pop();
this.length--;
queue[0] = newRoot;
swapUntilQueueIsCorrect(0);
return oldRoot;
}
var bubbleUp = function(index) {
if (index===0) {
return;
}
var parent = getParentOf(index);
if (evaluate(index,parent)) {
swap(index,parent);
bubbleUp(parent);
} else {
return;
}
}
var swapUntilQueueIsCorrect = function(value) {
var left = getLeftOf(value);
var right = getRightOf(value);
if (evaluate(left,value)) {
swap(value,left);
swapUntilQueueIsCorrect(left);
} else if (evaluate(right,value)) {
swap(value,right);
swapUntilQueueIsCorrect(right);
} else if (value==0) {
return;
} else {
swapUntilQueueIsCorrect(0);
}
}
var swap = function(self,target) {
var placeHolder = queue[self];
queue[self] = queue[target];
queue[target] = placeHolder;
}
var evaluate = function(self,target) {
if (queue[target]===undefined||queue[self]===undefined) {
return false;
}
var selfValue;
var targetValue;
//Check if the criteria should be the result of a function call.
if (typeof queue[self][criteria] === 'function') {
selfValue = queue[self][criteria]();
targetValue = queue[target][criteria]();
} else {
selfValue = queue[self][criteria];
targetValue = queue[target][criteria];
}
if (isMax) {
if (selfValue > targetValue) {
return true;
} else {
return false;
}
} else {
if (selfValue < targetValue) {
return true;
} else {
return false;
}
}
}
var getParentOf = function(index) {
return Math.floor(index/2)-1;
}
var getLeftOf = function(index) {
return index*2 + 1;
}
var getRightOf = function(index) {
return index*2 + 2;
}
};
//Constants
EasyStar.PriorityQueue.MAX_HEAP = 0;
EasyStar.PriorityQueue.MIN_HEAP = 1;
/**
* Represents a single instance of EasyStar.
* A path that is in the queue to eventually be found.
*/
EasyStar.instance = function() {
this.isDoneCalculating = true;
this.pointsToAvoid = {};
this.startX;
this.callback;
this.startY;
this.endX;
this.endY;
this.nodeHash = {};
this.openList;
};
/**
* EasyStar.js
* github.com/prettymuchbryce/EasyStarJS
* Licensed under the MIT license.
*
* Implementation By Bryce Neal (@prettymuchbryce)
**/
EasyStar.js = function() {
var STRAIGHT_COST = 10;
var DIAGONAL_COST = 14;
var pointsToAvoid = {};
var collisionGrid;
var costMap = {};
var iterationsSoFar;
var instances = [];
var iterationsPerCalculation = Number.MAX_VALUE;
var acceptableTiles;
var diagonalsEnabled = false;
/**
* Sets the collision grid that EasyStar uses.
*
* @param {Array|Number} tiles An array of numbers that represent
* which tiles in your grid should be considered
* acceptable, or "walkable".
**/
this.setAcceptableTiles = function(tiles) {
if (tiles instanceof Array) {
//Array
acceptableTiles = tiles;
} else if (!isNaN(parseFloat(tiles)) && isFinite(tiles)) {
//Number
acceptableTiles = [tiles];
}
};
/**
* Enable diagonal pathfinding.
*/
this.enableDiagonals = function() {
diagonalsEnabled = true;
}
/**
* Disable diagonal pathfinding.
*/
this.disableDiagonals = function() {
diagonalsEnabled = false;
}
/**
* Sets the collision grid that EasyStar uses.
*
* @param {Array} grid The collision grid that this EasyStar instance will read from.
* This should be a 2D Array of Numbers.
**/
this.setGrid = function(grid) {
collisionGrid = grid;
//Setup cost map
for (var y = 0; y < collisionGrid.length; y++) {
for (var x = 0; x < collisionGrid[0].length; x++) {
if (!costMap[collisionGrid[y][x]]) {
costMap[collisionGrid[y][x]] = 1
}
}
}
};
/**
* Sets the tile cost for a particular tile type.
*
* @param {Number} The tile type to set the cost for.
* @param {Number} The multiplicative cost associated with the given tile.
**/
this.setTileCost = function(tileType, cost) {
costMap[tileType] = cost;
};
/**
* Sets the number of search iterations per calculation.
* A lower number provides a slower result, but more practical if you
* have a large tile-map and don't want to block your thread while
* finding a path.
*
* @param {Number} iterations The number of searches to prefrom per calculate() call.
**/
this.setIterationsPerCalculation = function(iterations) {
iterationsPerCalculation = iterations;
};
/**
* Avoid a particular point on the grid,
* regardless of whether or not it is an acceptable tile.
*
* @param {Number} x The x value of the point to avoid.
* @param {Number} y The y value of the point to avoid.
**/
this.avoidAdditionalPoint = function(x, y) {
pointsToAvoid[x + "_" + y] = 1;
};
/**
* Stop avoiding a particular point on the grid.
*
* @param {Number} x The x value of the point to stop avoiding.
* @param {Number} y The y value of the point to stop avoiding.
**/
this.stopAvoidingAdditionalPoint = function(x, y) {
delete pointsToAvoid[x + "_" + y];
};
/**
* Stop avoiding all additional points on the grid.
**/
this.stopAvoidingAllAdditionalPoints = function() {
pointsToAvoid = {};
};
/**
* Find a path.
*
* @param {Number} startX The X position of the starting point.
* @param {Number} startY The Y position of the starting point.
* @param {Number} endX The X position of the ending point.
* @param {Number} endY The Y position of the ending point.
* @param {Function} callback A function that is called when your path
* is found, or no path is found.
*
**/
this.findPath = function(startX, startY ,endX, endY, callback) {
//No acceptable tiles were set
if (acceptableTiles === undefined) {
throw "You can't set a path without first calling setAcceptableTiles() on EasyStar.";
}
//No grid was set
if (collisionGrid === undefined) {
throw "You can't set a path without first calling setGrid() on EasyStar.";
}
//Start or endpoint outside of scope.
if (startX < 0 || startY < 0 || endX < 0 || endX < 0 ||
startX > collisionGrid[0].length-1 || startY > collisionGrid.length-1 ||
endX > collisionGrid[0].length-1 || endY > collisionGrid.length-1) {
throw "Your start or end point is outside the scope of your grid.";
}
//Start and end are the same tile.
if (startX===endX && startY===endY) {
callback([]);
}
//End point is not an acceptable tile.
var endTile = collisionGrid[endY][endX];
var isAcceptable = false;
for (var i = 0; i < acceptableTiles.length; i++) {
if (endTile === acceptableTiles[i]) {
isAcceptable = true;
break;
}
}
if (isAcceptable === false) {
callback(null);
return;
}
//Create the instance
var instance = new EasyStar.instance();
instance.openList = new EasyStar.PriorityQueue("bestGuessDistance",EasyStar.PriorityQueue.MIN_HEAP);
instance.isDoneCalculating = false;
instance.nodeHash = {};
instance.startX = startX;
instance.startY = startY;
instance.endX = endX;
instance.endY = endY;
instance.callback = callback;
instance.openList.insert(coordinateToNode(instance, instance.startX,
instance.startY, null, STRAIGHT_COST));
instances.push(instance);
};
/**
* This method steps through the A* Algorithm in an attempt to
* find your path(s). It will search 4 tiles for every calculation.
* You can change the number of calculations done in a call by using
* easystar.setIteratonsPerCalculation().
**/
this.calculate = function() {
if (instances.length === 0 || collisionGrid === undefined || acceptableTiles === undefined) {
return;
}
for (iterationsSoFar = 0; iterationsSoFar < iterationsPerCalculation; iterationsSoFar++) {
if (instances.length === 0) {
return;
}
//Couldn't find a path.
if (instances[0].openList.length===0) {
instances[0].callback(null);
instances.shift();
continue;
}
var searchNode = instances[0].openList.shiftHighestPriorityElement();
searchNode.list = EasyStar.Node.CLOSED_LIST;
if (searchNode.y > 0) {
checkAdjacentNode(instances[0], searchNode, 0, -1, STRAIGHT_COST *
costMap[collisionGrid[searchNode.y-1][searchNode.x]]);
if (instances[0].isDoneCalculating===true) {
instances.shift();
continue;
}
}
if (searchNode.x < collisionGrid[0].length-1) {
checkAdjacentNode(instances[0], searchNode, 1, 0, STRAIGHT_COST *
costMap[collisionGrid[searchNode.y][searchNode.x+1]]);
if (instances[0].isDoneCalculating===true) {
instances.shift();
continue;
}
}
if (searchNode.y < collisionGrid.length-1) {
checkAdjacentNode(instances[0], searchNode, 0, 1, STRAIGHT_COST *
costMap[collisionGrid[searchNode.y+1][searchNode.x]]);
if (instances[0].isDoneCalculating===true) {
instances.shift();
continue;
}
}
if (searchNode.x > 0) {
checkAdjacentNode(instances[0], searchNode, -1, 0, STRAIGHT_COST *
costMap[collisionGrid[searchNode.y][searchNode.x-1]]);
if (instances[0].isDoneCalculating===true) {
instances.shift();
continue;
}
}
if (diagonalsEnabled) {
if (searchNode.x > 0 && searchNode.y > 0) {
checkAdjacentNode(instances[0], searchNode, -1, -1, DIAGONAL_COST *
costMap[collisionGrid[searchNode.y-1][searchNode.x-1]]);
if (instances[0].isDoneCalculating===true) {
instances.shift();
continue;
}
}
if (searchNode.x < collisionGrid[0].length-1 && searchNode.y < collisionGrid.length-1) {
checkAdjacentNode(instances[0], searchNode, 1, 1, DIAGONAL_COST *
costMap[collisionGrid[searchNode.y+1][searchNode.x+1]]);
if (instances[0].isDoneCalculating===true) {
instances.shift();
continue;
}
}
if (searchNode.x < collisionGrid[0].length-1 && searchNode.y > 0) {
checkAdjacentNode(instances[0], searchNode, 1, -1, DIAGONAL_COST *
costMap[collisionGrid[searchNode.y-1][searchNode.x+1]]);
if (instances[0].isDoneCalculating===true) {
instances.shift();
continue;
}
}
if (searchNode.x > 0 && searchNode.y < collisionGrid.length-1) {
checkAdjacentNode(instances[0], searchNode, -1, 1, DIAGONAL_COST *
costMap[collisionGrid[searchNode.y+1][searchNode.x-1]]);
if (instances[0].isDoneCalculating===true) {
instances.shift();
continue;
}
}
}
}
};
//Private methods follow
var checkAdjacentNode = function(instance, searchNode, x, y, cost) {
var adjacentCoordinateX = searchNode.x+x;
var adjacentCoordinateY = searchNode.y+y;
if (instance.endX === adjacentCoordinateX && instance.endY === adjacentCoordinateY) {
instance.isDoneCalculating = true;
var path = [];
var pathLen = 0;
path[pathLen] = {x: adjacentCoordinateX, y: adjacentCoordinateY};
pathLen++;
path[pathLen] = {x: searchNode.x, y:searchNode.y};
pathLen++;
var parent = searchNode.parent;
while (parent!=null) {
path[pathLen] = {x: parent.x, y:parent.y};
pathLen++;
parent = parent.parent;
}
path.reverse();
instance.callback(path);
}
if (pointsToAvoid[adjacentCoordinateX + "_" + adjacentCoordinateY] === undefined) {
for (var i = 0; i < acceptableTiles.length; i++) {
if (collisionGrid[adjacentCoordinateY][adjacentCoordinateX] === acceptableTiles[i]) {
var node = coordinateToNode(instance, adjacentCoordinateX,
adjacentCoordinateY, searchNode, cost);
if (node.list === undefined) {
node.list = EasyStar.Node.OPEN_LIST;
instance.openList.insert(node);
} else if (node.list === EasyStar.Node.OPEN_LIST) {
if (searchNode.costSoFar + cost < node.costSoFar) {
node.costSoFar = searchNode.costSoFar + cost;
node.parent = searchNode;
}
}
break;
}
}
}
};
//Helpers
var coordinateToNode = function(instance, x, y, parent, cost) {
if (instance.nodeHash[x + "_" + y]!==undefined) {
return instance.nodeHash[x + "_" + y];
}
var simpleDistanceToTarget = getDistance(x, y, instance.endX, instance.endY);
if (parent!==null) {
var costSoFar = parent.costSoFar + cost;
} else {
costSoFar = simpleDistanceToTarget;
}
var node = new EasyStar.Node(parent,x,y,costSoFar,simpleDistanceToTarget);
instance.nodeHash[x + "_" + y] = node;
return node;
};
var getDistance = function(x1,y1,x2,y2) {
return Math.sqrt(Math.abs(x2-x1)*Math.abs(x2-x1) + Math.abs(y2-y1)*Math.abs(y2-y1)) * STRAIGHT_COST;
};
}

View File

@@ -1,3 +1,12 @@
SPEED_WALKING = 8;
SPEED_RUNNING = 14;
// Millisecond durations per tweens, per tile
TWEEN_DURATION_PERTILE_RUNNING = 160;
TWEEN_DURATION_PERTILE_WALKING = 224;
TWEEN_DURATION_PERPIXEL_RUNNING = 5;
TWEEN_DURATION_PERPIXEL_WALKING = 7;
STATE_NONE = 0;
STATE_UNAWARE = 1 << 1;
STATE_CONCERNED = 1 << 2;
@@ -33,6 +42,7 @@ SPRITE_TOWNSFOLK_GUARD1 = 9;
SPRITE_TOWNSFOLK_GUARD2 = 10;
var pathfinder = null;
var pathfinder_grid = null;
var game = new Phaser.Game(640, 480, Phaser.AUTO, '');
@@ -623,6 +633,21 @@ var moonlightDialog = {
}
};
// Return new array with duplicate values removed
function array_unique(arr) {
var a = [];
var l = arr.length;
for(var i=0; i<l; i++) {
for(var j=i+1; j<l; j++) {
// If arr[i] is found later in the array
if (arr[i] === arr[j])
j = ++i;
}
a.push(arr[i]);
}
return a;
}
function stringSize(str, font)
{
var width = 0;
@@ -696,8 +721,6 @@ var AISprite = function(game, x, y, key, frame) {
var hyp = Math.sqrt(Number(xd * xd) + Number(yd * yd));
if ( hyp > this.view_distance ) {
if ( debug == true )
console.log(spr + " is too far away");
return false;
}
@@ -853,38 +876,136 @@ var AISprite = function(game, x, y, key, frame) {
this.bubble_text.position.y = ty;
}
this.blocked = function() {
function f() {
if ( hasState(this, STATE_FACE_LEFT) &&
this.body.blocked.left == true )
return true;
if ( hasState(this, STATE_FACE_RIGHT) &&
this.body.blocked.right == true )
return true;
if ( hasState(this, STATE_FACE_DOWN) &&
this.body.blocked.down == true )
return true;
if ( hasState(this, STATE_FACE_UP) &&
this.body.blocked.up == true )
return true;
return false;
}
console.log("this.blocked? " + f());
return f();
}
this.path_set = function(target, force) {
force = ( typeof force == undefined ? false : force );
if ( force == false &&
this.path.length > 0 &&
this.path_index < this.path_maximum_steps ) {
return false;
}
this.path = [];
this.path_index = 0;
tpath = pathfinder.findPath(
parseInt(this.x/32),
parseInt(this.y/32),
parseInt(target.x/32),
parseInt(target.y/32),
pathfinder_grid.clone()
);
prevpoint = [this.x, this.y];
for ( var i = 0 ; i < tpath.length ; i++ ) {
if ( (prevpoint[0]+prevpoint[1]) == ((tpath[i][0]*32)+(tpath[i][1]*32)) )
continue;
this.path.push(new Phaser.Line(prevpoint[0], prevpoint[1],
tpath[i][0]*32, tpath[i][1]*32));
prevpoint = [tpath[i][0]*32, tpath[i][1]*32];
}
console.log("New path");
console.log(this.path);
return true;
}
this.path_tween_start = function()
{
this.path_tweens = [];
prevpos = [this.x, this.y]
for ( var i = 0;
i < Math.min(this.path_maximum_steps, this.path.length) ;
i++ ) {
pl = this.path[i];
movingstate = STATE_MOVING;
if ( pl.end.x < prevpos[0]) {
movingstate = movingstate | STATE_FACE_LEFT;
} else if ( pl.end.x > prevpos[0] ) {
movingstate = movingstate | STATE_FACE_RIGHT;
}
if ( pl.end.y < prevpos[1] ) {
movingstate = movingstate | STATE_FACE_UP;
} else if ( pl.end.y > prevpos[1] ) {
movingstate = movingstate | STATE_FACE_DOWN;
}
prevpos = [pl.end.x, pl.end.y];
tween = game.add.tween(this);
tween.movingstate = movingstate;
this.path_tweens.push(tween);
tween.to(
{x: (pl.end.x), y: (pl.end.y)},
(TWEEN_DURATION_PERPIXEL_WALKING * pl.length),
null);
tween.onStart.add(function() {
setMovingState(this._object, this.movingstate);
setSpriteMovement(this._object, false);
}, tween);
tween.onComplete.add(function() {
this._object.path_index += 1;
setMovingState(this._object, getFaceState(this._object));
setSpriteMovement(this._object, false);
}, tween);
if ( i > 0 ) {
this.path_tweens[i-1].onComplete.add(tween.start,
tween);
}
}
console.log(this.path_tweens);
if ( this.path_tweens.length > 0 )
this.path_tweens[0].start();
}
this.path_tween_stop = function()
{
this.path_tweens.forEach(function(x) {
x.stop();
game.tweens.remove(x);
}, this);
}
this.action_chaseplayer = function()
{
var newpath = []
var movingstate = STATE_NONE;
pathfinder.setCallbackFunction(function(path) {
newpath = (path || []);
});
this.path = newpath;
pathfinder.preparePathCalculation([0,0], [player.x/32, player.y/32]);
pathfinder.calculatePath();
if ( this.path[0].x < this.x ) {
movingstate = STATE_FACE_LEFT | STATE_MOVING | STATE_RUNNING;
} else if ( this.path[0].x > this.x ) {
movingstate = STATE_FACE_RIGHT | STATE_MOVING | STATE_RUNNING;
} else if ( this.path[0].y < this.y ) {
movingstate = STATE_FACE_UP | STATE_MOVING | STATE_RUNNING;
} else if ( this.path[0].y > this.y ) {
movingstate = STATE_FACE_DOWN | STATE_MOVING | STATE_RUNNING;
if ( game.physics.arcade.collide(this, player) )
return;
if ( this.path_index >= this.path.length ) {
this.path_tween_stop();
this.path_set(player, true);
this.path_tween_start();
} else {
movingstate = (this.state & STATES_FACE);
if ( this.path_set(player, this.blocked(true)) )
this.path_tween_start();
}
setMovingState(this, movingstate);
return;
}
this.action_reportplayer = function()
{
console.log("I AM REPORTING THE PLAYER");
setSpriteMovement(this);
}
this.action_huntplayer = function()
{
console.log("I AM HUNTING FOR THE PLAYER");
setSpriteMovement(this);
}
this.action_wander = function()
@@ -952,7 +1073,6 @@ var AISprite = function(game, x, y, key, frame) {
} else {
this.action_wander();
}
setSpriteMovement(this);
}
this.update_new_values = function() {
@@ -968,6 +1088,7 @@ var AISprite = function(game, x, y, key, frame) {
this.collide_with_map = parseBoolean(this.collide_with_map);
this.carries_light = parseBoolean(this.carries_light);
this.path_maximum_steps = parseInt(this.path_maximum_steps);
this.loadTexture(this.sprite_name, 0);
addAnimation(this, 'bipedwalkleft');
addAnimation(this, 'bipedwalkright');
@@ -997,6 +1118,11 @@ var AISprite = function(game, x, y, key, frame) {
Phaser.Sprite.call(this, game, x, y, null);
game.physics.arcade.enable(this);
this.body.immovable = true;
pathfinder_grid = [];
this.walkables = [];
this.path = [];
this.path_tweens = [];
this.path_maximum_steps = 4;
this.awareness_change_enabled = true;
this.lightmeter = 1.0;
this.sprite_can_see_lightmeter = 0.3;
@@ -1040,14 +1166,13 @@ var GameState = function(game) {
GameState.prototype.create = function()
{
this.pathfinding_grid = []
this.map = this.add.tilemap('map');
for (var k in moonlightSettings['map']['tilesets']) {
var ts = moonlightSettings['map']['tilesets'][k];
this.map.addTilesetImage(ts['name']);
}
this.map_collision_layers = [];
pfgrid = [];
for (var ln in moonlightSettings['map']['layers']) {
lp = moonlightSettings['map']['layers'][ln];
@@ -1061,6 +1186,7 @@ GameState.prototype.create = function()
);
if ( lp['inject_sprites'] == true ) {
this.aiSprites = game.add.group();
this.aiSprites.debug = true;
this.map.createFromObjects('AI', 3544, 'player', 0, true, false, this.aiSprites, AISprite);
this.aiSprites.forEach(function(spr) {
spr.update_new_values();
@@ -1071,16 +1197,18 @@ GameState.prototype.create = function()
};
if ( lp['collides'] == true ) {
this.map_collision_layers.push(layer);
for (var i = 0; i < layer.data.length; i++)
console.log(layer);
for (var i = 0; i < layer.layer.data.length; i++)
{
if ( this.pathfinding_grid.length <= i )
this.pathfinding_grid[i] = [];
for (var j = 0; j < layer.data[i].length; j++)
if ( i >= pfgrid.length )
pfgrid[i] = [];
for (var j = 0; j < layer.layer.data[i].length; j++)
{
if (layer.data[i][j])
this.pathfinding_grid[i][j] = layer.data[i][j].index;
else
this.pathfinding_grid[i][j] = 0;
if (layer.layer.data[i][j].index > 0) {
pfgrid[i][j] = 1;
} else if ( pfgrid[i][j] != 1 ) {
pfgrid[i][j] = 0;
}
}
}
}
@@ -1088,12 +1216,19 @@ GameState.prototype.create = function()
}
}
pathfinder = game.plugins.add(Phaser.Plugin.PathFinderPlugin);
pathfinder.setGrid(map.layers[0].data, walkables);
console.log(pfgrid)
pathfinder_grid = new PF.Grid(this.map.width,
this.map.height,
pfgrid);
pathfinder = new PF.AStarFinder({allowDiagonal: false});
console.log(pathfinder_grid);
console.log(pathfinder);
this.physics.arcade.enable(player);
player.body.center = new Phaser.Point(player.body.width / 2, player.body.height + player.body.halfHeight);
player.body.collideWorldBounds = true;
player.body.immovable = true;
addAnimation(player, 'bipedwalkleft');
addAnimation(player, 'bipedwalkright');
@@ -1195,6 +1330,20 @@ GameState.prototype.updateShadowTexture = function() {
this.shadowTexture.dirty = true;
};
function getFaceState(spr)
{
return ( hasState(spr, STATE_FACE_LEFT) ||
hasState(spr, STATE_FACE_RIGHT) ||
hasState(spr, STATE_FACE_DOWN) ||
hasState(spr, STATE_FACE_UP) );
}
function getMoveState(spr)
{
return ( hasState(spr, STATE_MOVING) ||
hasState(spr, STATE_RUNNING) );
}
function delState(spr, state)
{
if ( hasState(spr, state) )
@@ -1266,41 +1415,49 @@ function parseBoolean(val)
return ( val == 'true' || val == true );
}
function setSpriteMovement(spr)
function setSpriteMovement(spr, velocity)
{
var x = 0;
var y = 0;
var dir = spriteFacing(spr);
velocity = ( typeof velocity == undefined ? velocity : [SPEED_WALKING,
SPEED_RUNNING] );
spr.body.setSize(16, 16, 8, 16);
if ( hasState(spr, STATE_RUNNING) ) {
x = 200;
y = 200;
if ( velocity !== false )
velocity = velocity[1];
console.log("Playing bipedrun" + dir);
spr.animations.play("bipedrun" + dir);
} else if ( hasState(spr, STATE_MOVING) ) {
x = 75;
y = 75;
if ( velocity !== false )
velocity = velocity[0];
console.log("Playing bipedwalk" + dir);
spr.animations.play("bipedwalk" + dir);
} else {
spr.body.velocity.x = 0;
spr.body.velocity.y = 0;
if ( velocity !== false ) {
spr.body.velocity.x = 0;
spr.body.velocity.y = 0;
}
spr.animations.stop();
return;
}
if ( dir == "left" ) {
spr.body.velocity.x = -x;
spr.body.velocity.y = 0;
} else if ( dir == "right" ) {
spr.body.velocity.x = x;
spr.body.velocity.y = 0;
} else if ( dir == "up" ) {
spr.body.velocity.x = 0;
spr.body.velocity.y = -y;
} else if ( dir == "down" ) {
spr.body.velocity.x = 0;
spr.body.velocity.y = y;
if ( velocity !== false ) {
if ( dir == "left" ) {
spr.body.velocity.x = -(velocity * velocity);
spr.body.velocity.y = 0;
} else if ( dir == "right" ) {
spr.body.velocity.x = (velocity * velocity);
spr.body.velocity.y = 0;
} else if ( dir == "up" ) {
spr.body.velocity.x = 0;
spr.body.velocity.y = -(velocity * velocity);
} else if ( dir == "down" ) {
spr.body.velocity.x = 0;
spr.body.velocity.y = (velocity * velocity);
}
}
}
@@ -1416,18 +1573,32 @@ GameState.prototype.update = function()
this.aiSprites.forEach(_inner_collide, this);
this.updateShadowTexture();
// function _draw_viewrect(x) {
// var r = x.viewRectangle();
// if ( r == null )
// return;
// this.shadowTexture.context.fillStyle = 'rgb(128, 128, 128)';
// this.shadowTexture.context.fillRect(r.left,
// r.top,
// r.width,
// r.height);
// if ( this.aiSprites.debug == true ) {
// function _draw_viewrect(x) {
// var r = x.viewRectangle();
// if ( r == null )
// return;
// this.shadowTexture.context.fillStyle = 'rgb(128, 128, 128)';
// this.shadowTexture.context.fillRect(r.left,
// r.top,
// r.width,
// r.height);
// }
// this.aiSprites.forEach(_draw_viewrect, this);
// function _draw_aipath(x) {
// var p = x.path;
// if ( p == null )
// return;
// this.shadowTexture.context.fillStyle = 'rgb(255, 128, 128)';
// p.forEach(function(r) {
// this.shadowTexture.context.fillRect(r.start.x,
// r.start.y,
// r.end.x - r.start.x,
// r.end.y - r.start.y);
// }, this);
// }
// this.aiSprites.forEach(_draw_aipath, this);
// }
// this.aiSprites.forEach(_draw_viewrect, this);
if (game.time.fps !== 0) {
this.fpsText.setText(game.time.fps + ' FPS');
}
@@ -1443,15 +1614,13 @@ var Boot = function(game) {
Boot.prototype.preload = function()
{
console.log("Boot.preload");
game.load.image('preloader', 'gfx/ui/preloader.png');
};
Boot.prototype.create = function()
{
console.log("Boot.create");
this.input.maxPointers = 1;
this.stage.disableVisibilityChange = true;
this.stage.disableVisibilityChange = false;
this.stage.scale.pageAlignHoritzontally = true;
game.state.start('preloader', true, false);
}
@@ -1461,7 +1630,6 @@ var Preloader = function(game) {
Preloader.prototype.preload = function()
{
console.log("Preloader.preload");
this.preloadBar = game.add.sprite(0, 0, 'preloader');
this.preloadBar.anchor.setTo(0.5, 0.5);
this.preloadBar.x = game.camera.x + (game.camera.width / 2);
@@ -1489,12 +1657,10 @@ Preloader.prototype.preload = function()
moonlightSettings['map']['path'],
null,
Phaser.Tilemap.TILED_JSON);
}
Preloader.prototype.create = function()
{
console.log("Preloader.create");
function goalready() {
this.preloadBar.destroy();
game.state.start('game', true, false);
@@ -1504,11 +1670,8 @@ Preloader.prototype.create = function()
tween.onComplete.add(goalready, this);
}
console.log("Adding boot");
game.state.add('boot', Boot, false);
console.log("Adding preloader");
game.state.add('preloader', Preloader, false);
console.log("Adding game");
game.state.add('game', GameState, false);
game.state.start('boot');

File diff suppressed because one or more lines are too long