vyPath is pretty easy to use. Just have the object on the map you want then to navigate and call this:
this.WalkTo(5,3)
Here is a full example of it:
/*
// File: vyPathDemo.dm
// Author: Kristopher A. (Quaint Shanty)
// Description: How vyPath is used
*/
Mob
onLogin()
this.atlasName = 'vyPathIcons'
this.iconName = "Player"
this.setLoc(1, 1, World.mainMap)
this.WalkTo(5,3)
Now, the magic that makes the above code able to work is a ~50 line block of code that makes use of the core pathfinding system:
/*
// File: vyPathHandler.dm
// Author: Kristopher A. (Quaint Shanty)
// Description: Makes use of vyPath to move a Movable along a path
*/
var pathfinder = []
Diob
var pathfindingThread = null
function
//This is just extra if you want to include diagonal movement for shorter paths
//DOES NOT WORK CURRENTLY SINCE stepPos() DOES NOT CUT CORNERS
SimplifyVectors(path /* as Vector2[] */)
var newPath = [] // as Vector2[]
for(var i = 0; i < path.length; i++)
if(i < path.length - 2 && path.length > 2)
var v1 = path[i] // as Vector2
var v2 = path[i + 2] // as Vector2
// Get the diagonals
if((v2.x == v1.x + 1 && v2.y == v1.y + 1) /*Northeast*/ || (v2.x == v1.x - 1 && v2.y == v1.y + 1) /*Northwest*/ || (v2.x == v1.x - 1 && v2.y == v1.y - 1) /*Southwest*/ || (v2.x == v1.x + 1 && v2.y == v1.y - 1) /*Southeast*/)
newPath.push(v1) // Skip the first one and move diagonally to the next one.
i++
continue
newPath.push(v1)
newPath.push(path[path.length - 2])
newPath.push(path[path.length - 1])
return newPath
WalkTo(_x, _y)
if(!_x && !_y && this.pathfindingThread)
Event.interruptThread(this.pathfindingThread)
if(this.pathfindingThread)
Event.interruptThread(this.pathfindingThread)
if(!pathfinder[this.mapName])
pathfinder[this.mapName] = new Diob('Pathfinder', Map.getMapSize(this.mapName).x, Map.getMapSize(this.mapName).y, this.mapName) // as Pathfinder
var pf = pathfinder[this.mapName] // as Pathfinder
var path = pf.FindPath(new Diob('Point', this.xCoord, this.yCoord), new Diob('Point', _x, _y)) // as Vector2[]
//path = this.SimplifyVectors(path)
var p
var x = 0
var y = 0
this.pathfindingThread = thread(1000/60)
if (!p)
p = path[0]
if (!p)
Event.interruptThread(this.pathfindingThread)
return
x = p.x - this.xCoord
y = p.y - this.yCoord
if(!this.stepPos(x * this.stepSize, y * this.stepSize))
// "something is blocking me.. I need to find a new path"
Event.interruptThread(this.pathfindingThread)
this.WalkTo(_x, _y)
if(this.xPos === p.xPos && this.yPos === p.yPos)
path.splice(0, 1)
p = null
And then there is the core of it all. vyPath's core script enables us to generate nodes for a map of any size and easily update it again in real-time to check for changes in the map. It also gather the quickest route possible:
/*
// File: vyPath.dm
// Author: Kristopher A. (Quaint Shanty)
// Description: The core of vyPath that does all sorts of magic to produce nodes and gather the most efficient route
*/
var FLOAT_MAX = 3.402823e038 // 340,282,300,000,000,000,000,000,000,000,000,000,000
Point
var x = 0
var y = 0
var xPos = 0
var yPos = 0
onNew(xLoc, yLoc, xPos, yPos)
if(xLoc)
this.x = xLoc
if(yLoc)
this.y = yLoc
if(xPos)
this.xPos = xPos
if(yPos)
this.yPos = yPos
Vector2
var x = 0
var y = 0
var xPos = 0
var yPos = 0
onNew(_x, _y, xPos, yPos)
if(_x)
this.x = _x
if(_y)
this.y = _y
if(xPos)
this.xPos = xPos
if(yPos)
this.yPos = yPos
SearchNode
var pos = null // as Point
var dense = null
var neighbors = [] // as SearchNode[]
var parent = null // as SearchNode
var inOpenList = null
var inClosedList = null
var distToGoal = null
var distTraveled = null
Pathfinder
var searchNodes = {} // as SearchNode[][]
var openList = [] // as SearchNode[]
var closedList = [] // as SearchNode[]
var levelWidth = null
var levelHeight = null
var map = null
onNew(_width, _height, _map)
if(!_width || !_height || !_map)
delDiob(this)
this.levelWidth = _width
this.levelHeight = _height
this.map = _map
this.InitializeSearchNodes()
function
Heuristic(point1 /* as Point */, point2 /* as Point */)
return Math.abs(point1.x - point2.x) + Math.abs(point1.y - point2.y) // TODO: Try with get_dist().
ResetSearchNodes()
this.openList = []
this.closedList = []
for(var x = 1; x <= this.levelWidth; x++)
for(var y = 1; y <= this.levelHeight; y++)
var node = this.searchNodes[x + ',' + y] // as SearchNode[][]
if(node == null)
continue
node.inOpenList = 0
node.inClosedList = 0
node.distTraveled = FLOAT_MAX
node.distToGoal = FLOAT_MAX
FindBestNode()
var currentTile = this.openList[0] // as SearchNode[]
var smallestDistToGoal = FLOAT_MAX
for(var i = 0; i < this.openList.length; i++)
var oL = this.openList[i] // as SearchNode[]
if(oL.distToGoal < smallestDistToGoal)
currentTile = this.openList[i]
smallestDistToGoal = currentTile.distToGoal
return currentTile
FindFinalPath(startNode /* as SearchNode */, endNode /* as SearchNode */)
this.closedList.push(endNode)
var parentTile = endNode.parent // as SearchNode
while(parentTile != startNode)
this.closedList.push(parentTile)
parentTile = parentTile.parent
var finalPath = [] // as Vector2
for(var i = this.closedList.length - 1; i >= 0; i--)
var cL = this.closedList[i] // as SearchNode[]
finalPath.push(new Diob('Vector2', cL.pos.x, cL.pos.y, cL.pos.xPos, cL.pos.yPos))
return finalPath
FindPath(startPoint /* as Point */ , endPoint /* as Point */)
if(startPoint == endPoint)
return null
this.ResetSearchNodes()
var startNode = this.searchNodes[startPoint.x + ',' + startPoint.y] // as SearchNode[][]
var endNode = this.searchNodes[endPoint.x + ',' + endPoint.y] // as searchNode[][]
startNode.inOpenList = 1
startNode.distToGoal = this.Heuristic(startPoint, endPoint)
startNode.distTraveled = 0
this.openList.push(startNode)
//this.openList.push(endNode)
while(this.openList.length > 0)
var currentNode = this.FindBestNode()
if(currentNode == null)
break
if(currentNode == endNode)
return this.FindFinalPath(startNode, endNode)
for(var i = 0; i < currentNode.neighbors.length; i++)
var neighbor = currentNode.neighbors[i] // as SearchNode[]
if(neighbor == null || !neighbor.dense)
continue
var distTraveled = currentNode.distTraveled + 1
var heuristic = this.Heuristic(neighbor.pos, endPoint)
if(!neighbor.inOpenList && !neighbor.inClosedList)
neighbor.distTraveled = distTraveled
neighbor.distToGoal = distTraveled + heuristic
neighbor.parent = currentNode
neighbor.inOpenList = 1
this.openList.push(neighbor)
else if(neighbor.inOpenList || neighbor.inClosedList)
if(neighbor.distTraveled > distTraveled)
neighbor.distTraveled = distTraveled
neighbor.distToGoal = distTraveled + heuristic
neighbor.parent = currentNode
this.openList.splice(this.openList.indexOf(currentNode), 1)
currentNode.inClosedList = 1
return null
InitializeSearchNodes()
this.searchNodes = {}
for(var x = 1; x <= this.levelWidth; x++)
for(var y = 1; y <= this.levelHeight; y++)
var node = new Diob('SearchNode') // as SearchNode
node.pos = Map.getLoc(x, y, this.map)
node.dense = (node.pos.density == undefined) || (node.pos.density == 0)
if(node.dense)
node.neighbors = []
node.pos = new Diob('Point', node.pos.xCoord, node.pos.yCoord, node.pos.xPos, node.pos.yPos)
this.searchNodes[x + ',' + y] = node
for(var x = 1; x <= this.levelWidth; x++)
for(var y = 1; y <= this.levelHeight; y++)
var node = this.searchNodes[x + ',' + y] // as SearchNode[][]
if(node == null || !node.dense)
continue
var neighbors = [
new Diob('Point', x, y - 1),
new Diob('Point', x, y + 1),
new Diob('Point', x - 1, y),
new Diob('Point', x + 1, y)
] // as Point[4]
for(var i = 0; i < neighbors.length; i++)
var position = neighbors[i] // as Point[]
if(position.x <= 0 || position.x > this.levelWidth || position.y <= 0 || position.y > this.levelHeight)
continue
var neighbor = this.searchNodes[position.x + ',' + position.y]
if(neighbor == null || !neighbor.dense)
continue
node.neighbors[i] = neighbor
You can also view documentation and the full code here under the pathfinding folder:
http://vylocity.com/ide/QuaintShanty/Libraries/
If you have any questions, feel free to shoot me a message or visit the Vylocity chat room.
this.WalkTo(5,3)
Here is a full example of it:
/* // File: vyPathDemo.dm // Author: Kristopher A. (Quaint Shanty) // Description: How vyPath is used */ Mob onLogin() this.atlasName = 'vyPathIcons' this.iconName = "Player" this.setLoc(1, 1, World.mainMap) this.WalkTo(5,3)
Now, the magic that makes the above code able to work is a ~50 line block of code that makes use of the core pathfinding system:
/* // File: vyPathHandler.dm // Author: Kristopher A. (Quaint Shanty) // Description: Makes use of vyPath to move a Movable along a path */ var pathfinder = [] Diob var pathfindingThread = null function //This is just extra if you want to include diagonal movement for shorter paths //DOES NOT WORK CURRENTLY SINCE stepPos() DOES NOT CUT CORNERS SimplifyVectors(path /* as Vector2[] */) var newPath = [] // as Vector2[] for(var i = 0; i < path.length; i++) if(i < path.length - 2 && path.length > 2) var v1 = path[i] // as Vector2 var v2 = path[i + 2] // as Vector2 // Get the diagonals if((v2.x == v1.x + 1 && v2.y == v1.y + 1) /*Northeast*/ || (v2.x == v1.x - 1 && v2.y == v1.y + 1) /*Northwest*/ || (v2.x == v1.x - 1 && v2.y == v1.y - 1) /*Southwest*/ || (v2.x == v1.x + 1 && v2.y == v1.y - 1) /*Southeast*/) newPath.push(v1) // Skip the first one and move diagonally to the next one. i++ continue newPath.push(v1) newPath.push(path[path.length - 2]) newPath.push(path[path.length - 1]) return newPath WalkTo(_x, _y) if(!_x && !_y && this.pathfindingThread) Event.interruptThread(this.pathfindingThread) if(this.pathfindingThread) Event.interruptThread(this.pathfindingThread) if(!pathfinder[this.mapName]) pathfinder[this.mapName] = new Diob('Pathfinder', Map.getMapSize(this.mapName).x, Map.getMapSize(this.mapName).y, this.mapName) // as Pathfinder var pf = pathfinder[this.mapName] // as Pathfinder var path = pf.FindPath(new Diob('Point', this.xCoord, this.yCoord), new Diob('Point', _x, _y)) // as Vector2[] //path = this.SimplifyVectors(path) var p var x = 0 var y = 0 this.pathfindingThread = thread(1000/60) if (!p) p = path[0] if (!p) Event.interruptThread(this.pathfindingThread) return x = p.x - this.xCoord y = p.y - this.yCoord if(!this.stepPos(x * this.stepSize, y * this.stepSize)) // "something is blocking me.. I need to find a new path" Event.interruptThread(this.pathfindingThread) this.WalkTo(_x, _y) if(this.xPos === p.xPos && this.yPos === p.yPos) path.splice(0, 1) p = null
And then there is the core of it all. vyPath's core script enables us to generate nodes for a map of any size and easily update it again in real-time to check for changes in the map. It also gather the quickest route possible:
/* // File: vyPath.dm // Author: Kristopher A. (Quaint Shanty) // Description: The core of vyPath that does all sorts of magic to produce nodes and gather the most efficient route */ var FLOAT_MAX = 3.402823e038 // 340,282,300,000,000,000,000,000,000,000,000,000,000 Point var x = 0 var y = 0 var xPos = 0 var yPos = 0 onNew(xLoc, yLoc, xPos, yPos) if(xLoc) this.x = xLoc if(yLoc) this.y = yLoc if(xPos) this.xPos = xPos if(yPos) this.yPos = yPos Vector2 var x = 0 var y = 0 var xPos = 0 var yPos = 0 onNew(_x, _y, xPos, yPos) if(_x) this.x = _x if(_y) this.y = _y if(xPos) this.xPos = xPos if(yPos) this.yPos = yPos SearchNode var pos = null // as Point var dense = null var neighbors = [] // as SearchNode[] var parent = null // as SearchNode var inOpenList = null var inClosedList = null var distToGoal = null var distTraveled = null Pathfinder var searchNodes = {} // as SearchNode[][] var openList = [] // as SearchNode[] var closedList = [] // as SearchNode[] var levelWidth = null var levelHeight = null var map = null onNew(_width, _height, _map) if(!_width || !_height || !_map) delDiob(this) this.levelWidth = _width this.levelHeight = _height this.map = _map this.InitializeSearchNodes() function Heuristic(point1 /* as Point */, point2 /* as Point */) return Math.abs(point1.x - point2.x) + Math.abs(point1.y - point2.y) // TODO: Try with get_dist(). ResetSearchNodes() this.openList = [] this.closedList = [] for(var x = 1; x <= this.levelWidth; x++) for(var y = 1; y <= this.levelHeight; y++) var node = this.searchNodes[x + ',' + y] // as SearchNode[][] if(node == null) continue node.inOpenList = 0 node.inClosedList = 0 node.distTraveled = FLOAT_MAX node.distToGoal = FLOAT_MAX FindBestNode() var currentTile = this.openList[0] // as SearchNode[] var smallestDistToGoal = FLOAT_MAX for(var i = 0; i < this.openList.length; i++) var oL = this.openList[i] // as SearchNode[] if(oL.distToGoal < smallestDistToGoal) currentTile = this.openList[i] smallestDistToGoal = currentTile.distToGoal return currentTile FindFinalPath(startNode /* as SearchNode */, endNode /* as SearchNode */) this.closedList.push(endNode) var parentTile = endNode.parent // as SearchNode while(parentTile != startNode) this.closedList.push(parentTile) parentTile = parentTile.parent var finalPath = [] // as Vector2 for(var i = this.closedList.length - 1; i >= 0; i--) var cL = this.closedList[i] // as SearchNode[] finalPath.push(new Diob('Vector2', cL.pos.x, cL.pos.y, cL.pos.xPos, cL.pos.yPos)) return finalPath FindPath(startPoint /* as Point */ , endPoint /* as Point */) if(startPoint == endPoint) return null this.ResetSearchNodes() var startNode = this.searchNodes[startPoint.x + ',' + startPoint.y] // as SearchNode[][] var endNode = this.searchNodes[endPoint.x + ',' + endPoint.y] // as searchNode[][] startNode.inOpenList = 1 startNode.distToGoal = this.Heuristic(startPoint, endPoint) startNode.distTraveled = 0 this.openList.push(startNode) //this.openList.push(endNode) while(this.openList.length > 0) var currentNode = this.FindBestNode() if(currentNode == null) break if(currentNode == endNode) return this.FindFinalPath(startNode, endNode) for(var i = 0; i < currentNode.neighbors.length; i++) var neighbor = currentNode.neighbors[i] // as SearchNode[] if(neighbor == null || !neighbor.dense) continue var distTraveled = currentNode.distTraveled + 1 var heuristic = this.Heuristic(neighbor.pos, endPoint) if(!neighbor.inOpenList && !neighbor.inClosedList) neighbor.distTraveled = distTraveled neighbor.distToGoal = distTraveled + heuristic neighbor.parent = currentNode neighbor.inOpenList = 1 this.openList.push(neighbor) else if(neighbor.inOpenList || neighbor.inClosedList) if(neighbor.distTraveled > distTraveled) neighbor.distTraveled = distTraveled neighbor.distToGoal = distTraveled + heuristic neighbor.parent = currentNode this.openList.splice(this.openList.indexOf(currentNode), 1) currentNode.inClosedList = 1 return null InitializeSearchNodes() this.searchNodes = {} for(var x = 1; x <= this.levelWidth; x++) for(var y = 1; y <= this.levelHeight; y++) var node = new Diob('SearchNode') // as SearchNode node.pos = Map.getLoc(x, y, this.map) node.dense = (node.pos.density == undefined) || (node.pos.density == 0) if(node.dense) node.neighbors = [] node.pos = new Diob('Point', node.pos.xCoord, node.pos.yCoord, node.pos.xPos, node.pos.yPos) this.searchNodes[x + ',' + y] = node for(var x = 1; x <= this.levelWidth; x++) for(var y = 1; y <= this.levelHeight; y++) var node = this.searchNodes[x + ',' + y] // as SearchNode[][] if(node == null || !node.dense) continue var neighbors = [ new Diob('Point', x, y - 1), new Diob('Point', x, y + 1), new Diob('Point', x - 1, y), new Diob('Point', x + 1, y) ] // as Point[4] for(var i = 0; i < neighbors.length; i++) var position = neighbors[i] // as Point[] if(position.x <= 0 || position.x > this.levelWidth || position.y <= 0 || position.y > this.levelHeight) continue var neighbor = this.searchNodes[position.x + ',' + position.y] if(neighbor == null || !neighbor.dense) continue node.neighbors[i] = neighbor
You can also view documentation and the full code here under the pathfinding folder: http://vylocity.com/ide/QuaintShanty/Libraries/
If you have any questions, feel free to shoot me a message or visit the Vylocity chat room.