Migrate project from typing_practiceweb
This commit is contained in:
224
html5-tower-defense-master/src/js/td-walk.js
Normal file
224
html5-tower-defense-master/src/js/td-walk.js
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user