mirror of
https://github.com/gooba42/adventureland.git
synced 2026-10-23 21:21:27 -05:00
Open source
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
function calculate_move(map, cur_x, cur_y, target_x, target_y) {
|
||||
var going_down = cur_y < target_y;
|
||||
var going_right = cur_x < target_x;
|
||||
|
||||
var x_lines = map.x_lines || [];
|
||||
var y_lines = map.y_lines || [];
|
||||
|
||||
var min_x = min(cur_x, target_x);
|
||||
var max_x = max(cur_x, target_x);
|
||||
var min_y = min(cur_y, target_y);
|
||||
var max_y = max(cur_y, target_y);
|
||||
|
||||
var dx = target_x - cur_x;
|
||||
var dy = target_y - cur_y;
|
||||
|
||||
var dydx = dy / (dx + EPS);
|
||||
var dxdy = 1 / dydx;
|
||||
|
||||
for (var i = 0; i < x_lines.length; i++) {
|
||||
var line = x_lines[i];
|
||||
var line_x = line[0];
|
||||
if (max_x < line_x || min_x > line_x || max_y < line[1] || min_y > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var y_intersect = cur_y + (line_x - cur_x) * dydx;
|
||||
|
||||
if (y_intersect < line[1] || y_intersect > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (going_down) {
|
||||
target_y = min(target_y, y_intersect);
|
||||
} else {
|
||||
target_y = max(target_y, y_intersect);
|
||||
}
|
||||
|
||||
if (going_right) {
|
||||
target_x = min(target_x, line_x - 3);
|
||||
} else {
|
||||
target_x = max(target_x, line_x + 3);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < y_lines.length; i++) {
|
||||
var line = y_lines[i];
|
||||
var line_y = line[0];
|
||||
if (max_y < line_y || min_y > line_y || max_x < line[1] || min_x > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var x_intersect = cur_x + (line_y - cur_y) * dxdy;
|
||||
|
||||
if (x_intersect < line[1] || x_intersect > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (going_right) {
|
||||
target_x = min(target_x, x_intersect);
|
||||
} else {
|
||||
target_x = max(target_x, x_intersect);
|
||||
}
|
||||
|
||||
if (going_down) {
|
||||
target_y = min(target_y, line_y - 3);
|
||||
} else {
|
||||
target_y = max(target_y, line_y + 7);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
x: target_x,
|
||||
y: target_y
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
function calculate_move(map, cur_x, cur_y, target_x, target_y) {
|
||||
var going_down = cur_y < target_y;
|
||||
var going_right = cur_x < target_x;
|
||||
|
||||
var x_lines = map.x_lines || [];
|
||||
var y_lines = map.y_lines || [];
|
||||
|
||||
var min_x = min(cur_x, target_x);
|
||||
var max_x = max(cur_x, target_x);
|
||||
var min_y = min(cur_y, target_y);
|
||||
var max_y = max(cur_y, target_y);
|
||||
|
||||
var dx = target_x - cur_x;
|
||||
var dy = target_y - cur_y;
|
||||
|
||||
var dydx = dy / (dx + EPS);
|
||||
var dxdy = 1 / dydx;
|
||||
|
||||
for (var i = 0; i < x_lines.length; i++) {
|
||||
var line = x_lines[i];
|
||||
var line_x = line[0];
|
||||
if (max_x < line_x || min_x > line_x || max_y < line[1] || min_y > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var y_intersect = cur_y + (line_x - cur_x) * dydx;
|
||||
|
||||
if (y_intersect < line[1] || y_intersect > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (going_down) {
|
||||
target_y = min(target_y, y_intersect);
|
||||
max_y = target_y;
|
||||
} else {
|
||||
target_y = max(target_y, y_intersect);
|
||||
min_y = target_y;
|
||||
}
|
||||
|
||||
if (going_right) {
|
||||
target_x = min(target_x, line_x - 3);
|
||||
max_x = target_x;
|
||||
} else {
|
||||
target_x = max(target_x, line_x + 3);
|
||||
min_x = target_x;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < y_lines.length; i++) {
|
||||
var line = y_lines[i];
|
||||
var line_y = line[0];
|
||||
if (max_y < line_y || min_y > line_y || max_x < line[1] || min_x > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var x_intersect = cur_x + (line_y - cur_y) * dxdy;
|
||||
|
||||
if (x_intersect < line[1] || x_intersect > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (going_right) {
|
||||
target_x = min(target_x, x_intersect);
|
||||
max_x = target_x;
|
||||
} else {
|
||||
target_x = max(target_x, x_intersect);
|
||||
min_x = target_x;
|
||||
}
|
||||
|
||||
if (going_down) {
|
||||
target_y = min(target_y, line_y - 3);
|
||||
max_y = target_y;
|
||||
} else {
|
||||
target_y = max(target_y, line_y + 7);
|
||||
min_y = target_y;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
x: target_x,
|
||||
y: target_y
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
function can_move(map, cur_x, cur_y, target_x, target_y) {
|
||||
var x_lines = map.x_lines || [];
|
||||
var y_lines = map.y_lines || [];
|
||||
|
||||
var min_x = min(cur_x, target_x);
|
||||
var max_x = max(cur_x, target_x);
|
||||
var min_y = min(cur_y, target_y);
|
||||
var max_y = max(cur_y, target_y);
|
||||
|
||||
var dx = target_x - cur_x;
|
||||
var dy = target_y - cur_y;
|
||||
|
||||
var dydx = dy / (dx + EPS);
|
||||
var dxdy = 1 / dydx;
|
||||
|
||||
for (var i = 0; i < x_lines.length; i++) {
|
||||
var line = x_lines[i];
|
||||
var line_x = line[0];
|
||||
if (max_x < line_x || min_x > line_x || max_y < line[1] || min_y > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var y_intersect = cur_y + (line_x - cur_x) * dydx;
|
||||
|
||||
if (y_intersect < line[1] || y_intersect > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < y_lines.length; i++) {
|
||||
var line = y_lines[i];
|
||||
var line_y = line[0];
|
||||
if (max_y < line_y || min_y > line_y || max_x < line[1] || min_x > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var x_intersect = cur_x + (line_y - cur_y) * dxdy;
|
||||
|
||||
if (x_intersect < line[1] || x_intersect > line[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
const GRAPH_RESOLUTION = 8;
|
||||
|
||||
class Box {
|
||||
constructor(x1, y1, x2, y2) {
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
}
|
||||
|
||||
width() {
|
||||
return this.x2 - this.x1;
|
||||
}
|
||||
|
||||
height() {
|
||||
return this.y2 - this.y1;
|
||||
}
|
||||
|
||||
contains(x, y) {
|
||||
return (this.x1 < x && x < this.x2 &&
|
||||
this.y1 < y && y < this.y2);
|
||||
}
|
||||
|
||||
intersects(box) {
|
||||
return (this.x1 <= box.x2 &&
|
||||
box.x1 <= this.x2 &&
|
||||
this.y1 <= box.y2 &&
|
||||
box.y1 <= this.y2);
|
||||
}
|
||||
|
||||
static square(cx, cy, side) {
|
||||
let half_side = side / 2;
|
||||
return new Box(cx - half_side, cy - half_side, cx + half_side, cy + half_side);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class NodeTree {
|
||||
constructor(region, obstacles, root, level) {
|
||||
if (!level) {
|
||||
this.level = Math.ceil(Math.log2(region.width() / GRAPH_RESOLUTION));
|
||||
} else {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
if (root) {
|
||||
this.root = root;
|
||||
} else {
|
||||
this.root = this;
|
||||
}
|
||||
|
||||
this.region = region;
|
||||
|
||||
this.x = (region.x1 + region.x2) / 2;
|
||||
this.y = (region.y1 + region.y2) / 2;
|
||||
|
||||
this.obstacles = obstacles;
|
||||
|
||||
this.crossable = true;
|
||||
this.is_leaf = false;
|
||||
|
||||
if (this.obstacles.length == 0) {
|
||||
this.is_leaf = true;
|
||||
} else if (this.level == 0) {
|
||||
this.is_leaf = true;
|
||||
this.crossable = false;
|
||||
}
|
||||
|
||||
this.quads = null;
|
||||
this.neighbors = null;
|
||||
|
||||
this.is_inside = false;
|
||||
|
||||
if (!this.is_leaf) {
|
||||
this.subdivide();
|
||||
}
|
||||
}
|
||||
|
||||
get_quad(x, y) {
|
||||
if (x < this.x && y < this.y) return this.quads[0];
|
||||
else if (x >= this.x && y < this.y) return this.quads[1];
|
||||
else if (x < this.x && y >= this.y) return this.quads[2];
|
||||
return this.quads[3];
|
||||
}
|
||||
|
||||
subdivide() {
|
||||
this.quads = [];
|
||||
|
||||
let l = this.region.x1;
|
||||
let r = this.region.x2;
|
||||
let t = this.region.y1;
|
||||
let b = this.region.y2;
|
||||
|
||||
let x = this.x;
|
||||
let y = this.y;
|
||||
|
||||
let subregions = [
|
||||
new Box(l, t, x, y),
|
||||
new Box(x, t, r, y),
|
||||
new Box(l, y, x, b),
|
||||
new Box(x, y, r, b),
|
||||
];
|
||||
|
||||
let obstacles = this.obstacles;
|
||||
for (let i = 0; i < subregions.length; i++) {
|
||||
let subregion = subregions[i];
|
||||
let subregion_obstacles = [];
|
||||
|
||||
for (let j = 0; j < obstacles.length; j++) {
|
||||
let obstacle = obstacles[j];
|
||||
if (subregion.intersects(obstacle)) {
|
||||
subregion_obstacles.push(obstacle);
|
||||
}
|
||||
}
|
||||
|
||||
this.quads[i] = new NodeTree(subregion, subregion_obstacles, this.root, this.level - 1);
|
||||
}
|
||||
}
|
||||
|
||||
get(x, y) {
|
||||
if (!this.region.contains(x, y)) return null;
|
||||
if (this.is_leaf) return this;
|
||||
return this.get_quad(x, y).get(x, y);
|
||||
}
|
||||
|
||||
get_neighbors() {
|
||||
if (!this.is_leaf) throw new Error('Tried getting neighbors of non-leaf node');
|
||||
if (this.neighbors) return this.neighbors;
|
||||
|
||||
if (!this.crossable) {
|
||||
this.neighbors = [];
|
||||
return this.neighbors;
|
||||
}
|
||||
|
||||
let left = this.region.x1;
|
||||
let right = this.region.x2;
|
||||
let top = this.region.y1;
|
||||
let bottom = this.region.y2;
|
||||
|
||||
let min_size = this.region.width() * (2 ** -this.level);
|
||||
let num_neighbors = 2 ** this.level;
|
||||
|
||||
let neighbor_set = new Set();
|
||||
|
||||
// Top and bottom (and corners).
|
||||
for (let x = -(num_neighbors + 1); x <= (num_neighbors + 1); x += 2) {
|
||||
let real_x = this.x + min_size * (x / 2);
|
||||
|
||||
let neighbor = this.root.get(real_x, top - min_size / 2);
|
||||
if (neighbor) neighbor_set.add(neighbor);
|
||||
|
||||
neighbor = this.root.get(real_x, bottom + min_size / 2);
|
||||
if (neighbor) neighbor_set.add(neighbor);
|
||||
}
|
||||
|
||||
// Left and right.
|
||||
for (let y = -(num_neighbors - 1); y <= (num_neighbors - 1); y += 2) {
|
||||
let real_y = this.y + min_size * (y / 2);
|
||||
|
||||
let neighbor = this.root.get(left - min_size / 2, real_y);
|
||||
if (neighbor) neighbor_set.add(neighbor);
|
||||
|
||||
neighbor = this.root.get(right + min_size / 2, real_y);
|
||||
if (neighbor) neighbor_set.add(neighbor);
|
||||
}
|
||||
|
||||
this.neighbors = [...neighbor_set];
|
||||
|
||||
return this.neighbors;
|
||||
}
|
||||
|
||||
flood_fill() {
|
||||
if (this.is_inside) return;
|
||||
this.is_inside = true;
|
||||
|
||||
for (let neighbor of this.get_neighbors()) {
|
||||
neighbor.flood_fill();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function calculate_size(actual_size) {
|
||||
let cur_size = GRAPH_RESOLUTION;
|
||||
|
||||
while (cur_size < actual_size) {
|
||||
cur_size *= 2;
|
||||
}
|
||||
|
||||
return cur_size;
|
||||
}
|
||||
|
||||
function initialize_graph(map_name) {
|
||||
let map_data = G.maps[map_name].data;
|
||||
|
||||
let min_x = Infinity;
|
||||
let max_x = -Infinity;
|
||||
let min_y = Infinity;
|
||||
let max_y = -Infinity;
|
||||
|
||||
|
||||
let obstacles = [];
|
||||
|
||||
for (let line of map_data.x_lines) {
|
||||
min_x = Math.min(min_x, line[0]);
|
||||
max_x = Math.max(max_x, line[0]);
|
||||
obstacles.push(new Box(
|
||||
line[0] - 3,
|
||||
line[1] - 3,
|
||||
line[0] + 3,
|
||||
line[2] + 7
|
||||
));
|
||||
}
|
||||
|
||||
for (let line of map_data.y_lines) {
|
||||
min_y = Math.min(min_y, line[0]);
|
||||
max_y = Math.max(max_y, line[0]);
|
||||
obstacles.push(new Box(
|
||||
line[1] - 3,
|
||||
line[0] - 3,
|
||||
line[2] + 3,
|
||||
line[0] + 7
|
||||
));
|
||||
}
|
||||
|
||||
let largest_side = Math.max(max_x - min_x, max_y - min_y);
|
||||
let side = calculate_size(largest_side);
|
||||
|
||||
let center_x = (max_x + min_x) / 2;
|
||||
let center_y = (max_y + min_y) / 2;
|
||||
let region = Box.square(center_x, center_y, side);
|
||||
|
||||
let map_tree = new NodeTree(region, obstacles);
|
||||
|
||||
let spawns = G.maps[map_name].spawns;
|
||||
for (let [x, y] of spawns) {
|
||||
map_tree.get(x, y).flood_fill();
|
||||
}
|
||||
|
||||
return map_tree;
|
||||
}
|
||||
Reference in New Issue
Block a user