Files
d1kt/html5-tower-defense-master/src/js/td-walk.js

225 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2011.
*
* Author: oldj <oldj.wu@gmail.com>
* Blog: http://oldj.net/
*
* Last Update: 2011/1/10 5:22:52
*/
// _TD.a.push begin
_TD.a.push(function (TD) {
/**
* 使用 A* 算法Dijkstra算法寻找从 (x1, y1) 到 (x2, y2) 最短的路线
*
*/
TD.FindWay = function (w, h, x1, y1, x2, y2, f_passable) {
this.m = [];
this.w = w;
this.h = h;
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.way = [];
this.len = this.w * this.h;
this.is_blocked = this.is_arrived = false;
this.fPassable = typeof f_passable == "function" ? f_passable : function () {
return true;
};
this._init();
};
TD.FindWay.prototype = {
_init: function () {
if (this.x1 == this.x2 && this.y1 == this.y2) {
// 如果输入的坐标已经是终点了
this.is_arrived = true;
this.way = [
[this.x1, this.y1]
];
return;
}
for (var i = 0; i < this.len; i++)
this.m[i] = -2; // -2 表示未探索过,-1 表示不可到达
this.x = this.x1;
this.y = this.y1;
this.distance = 0;
this.current = [
[this.x, this.y]
]; // 当前一步探索的格子
this.setVal(this.x, this.y, 0);
while (this.next()) {
}
},
getVal: function (x, y) {
var p = y * this.w + x;
return p < this.len ? this.m[p] : -1;
},
setVal: function (x, y, v) {
var p = y * this.w + x;
if (p > this.len) return false;
this.m[p] = v;
},
/**
* 得到指定坐标的邻居即从指定坐标出发1 步之内可以到达的格子
* 目前返回的是指定格子的上、下、左、右四个邻格
* @param x {Number}
* @param y {Number}
*/
getNeighborsOf: function (x, y) {
var nbs = [];
if (y > 0) nbs.push([x, y - 1]);
if (x < this.w - 1) nbs.push([x + 1, y]);
if (y < this.h - 1) nbs.push([x, y + 1]);
if (x > 0) nbs.push([x - 1, y]);
return nbs;
},
/**
* 取得当前一步可到达的 n 个格子的所有邻格
*/
getAllNeighbors: function () {
var nbs = [], nb1, i, c, l = this.current.length;
for (i = 0; i < l; i++) {
c = this.current[i];
nb1 = this.getNeighborsOf(c[0], c[1]);
nbs = nbs.concat(nb1);
}
return nbs;
},
/**
* 从终点倒推,寻找从起点到终点最近的路径
* 此处的实现是,从终点开始,从当前格子的邻格中寻找值最低(且大于 0的格子
* 直到到达起点。
* 这个实现需要反复地寻找邻格,有时邻格中有多个格子的值都为最低,这时就从中
* 随机选取一个。还有一种实现方式是在一开始的遍历中,给每一个到达过的格子添加
* 一个值,指向它的来时的格子(父格子)。
*/
findWay: function () {
var x = this.x2,
y = this.y2,
nb, max_len = this.len,
nbs_len,
nbs, i, l, v, min_v = -1,
closest_nbs;
while ((x != this.x1 || y != this.y1) && min_v != 0 &&
this.way.length < max_len) {
this.way.unshift([x, y]);
nbs = this.getNeighborsOf(x, y);
nbs_len = nbs.length;
closest_nbs = [];
// 在邻格中寻找最小的 v
min_v = -1;
for (i = 0; i < nbs_len; i++) {
v = this.getVal(nbs[i][0], nbs[i][1]);
if (v < 0) continue;
if (min_v < 0 || min_v > v)
min_v = v;
}
// 找出所有 v 最小的邻格
for (i = 0; i < nbs_len; i++) {
nb = nbs[i];
if (min_v == this.getVal(nb[0], nb[1])) {
closest_nbs.push(nb);
}
}
// 从 v 最小的邻格中随机选取一个作为当前格子
l = closest_nbs.length;
i = l > 1 ? Math.floor(Math.random() * l) : 0;
nb = closest_nbs[i];
x = nb[0];
y = nb[1];
}
},
/**
* 到达终点
*/
arrive: function () {
this.current = [];
this.is_arrived = true;
this.findWay();
},
/**
* 道路被阻塞
*/
blocked: function () {
this.current = [];
this.is_blocked = true;
},
/**
* 下一次迭代
* @return {Boolean} 如果返回值为 true ,表示未到达终点,并且道路
* 未被阻塞,可以继续迭代;否则表示不必继续迭代
*/
next: function () {
var neighbors = this.getAllNeighbors(), nb,
l = neighbors.length,
valid_neighbors = [],
x, y,
i, v;
this.distance++;
for (i = 0; i < l; i++) {
nb = neighbors[i];
x = nb[0];
y = nb[1];
if (this.getVal(x, y) != -2) continue; // 当前格子已探索过
//grid = this.map.getGrid(x, y);
//if (!grid) continue;
if (this.fPassable(x, y)) {
// 可通过
/**
* 从起点到当前格子的耗费
* 这儿只是简单地把从起点到当前格子需要走几步作为耗费
* 比较复杂的情况下,可能还需要考虑不同的路面耗费也会不同,
* 比如沼泽地的耗费比平地要多。不过现在的版本中路况没有这么复杂,
* 先不考虑。
*/
v = this.distance;
valid_neighbors.push(nb);
} else {
// 不可通过或有建筑挡着
v = -1;
}
this.setVal(x, y, v);
if (x == this.x2 && y == this.y2) {
this.arrive();
return false;
}
}
if (valid_neighbors.length == 0) {
this.blocked();
return false
}
this.current = valid_neighbors;
return true;
}
};
}); // _TD.a.push end