mirror of
https://github.com/unanmed/HumanBreak.git
synced 2026-11-07 05:05:02 +08:00
楼传
This commit is contained in:
1 parent
71a4551004
commit
b3602d3f21
18 files changed
+1040
-36
No files matched your search
+204
-9
@@ -1,7 +1,7 @@
|
||||
import { has } from '../utils';
|
||||
|
||||
export default function init() {
|
||||
return { splitArea, getMapData };
|
||||
return { splitArea, getMapDrawData };
|
||||
}
|
||||
|
||||
type BFSFromString = `${FloorIds},${number},${number},${Dir}`;
|
||||
@@ -12,7 +12,20 @@ interface MapBFSResult {
|
||||
link: Record<BFSFromString, BFSToString>;
|
||||
}
|
||||
|
||||
interface MapDrawData {
|
||||
locs: Partial<Record<FloorIds, LocArr>>;
|
||||
line: [number, number, number, number][];
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
let area: Record<string, FloorIds[]> = {};
|
||||
|
||||
const bfsCache: Partial<Record<FloorIds, MapBFSResult>> = {};
|
||||
/**
|
||||
* 键的格式:FloorIds,interval,border
|
||||
*/
|
||||
const drawCache: Record<string, MapDrawData> = {};
|
||||
|
||||
const arrow: Partial<Record<AllIds, Dir>> = {
|
||||
leftPortal: 'left',
|
||||
@@ -21,9 +34,125 @@ const arrow: Partial<Record<AllIds, Dir>> = {
|
||||
downPortal: 'down'
|
||||
};
|
||||
|
||||
export function splitArea() {}
|
||||
/**
|
||||
* 切分地图区域
|
||||
*/
|
||||
export function splitArea() {
|
||||
const used: FloorIds[] = [];
|
||||
for (const id of core.floorIds) {
|
||||
if (used.includes(id) || core.status.maps[id].deleted) continue;
|
||||
const data = getMapData(id, true);
|
||||
used.push(...data.maps);
|
||||
if (data.maps.length > 0) {
|
||||
const title = core.status.maps[id].title;
|
||||
area[title] = data.maps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getMapDrawData(floorId: FloorIds) {}
|
||||
export function getArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取地图绘制信息
|
||||
* @param floorId 中心楼层
|
||||
* @param interval 地图间距
|
||||
* @param border 边框宽度
|
||||
* @param noCache 是否不使用缓存
|
||||
*/
|
||||
export function getMapDrawData(
|
||||
floorId: FloorIds,
|
||||
interval: number = 5,
|
||||
border: number = 1,
|
||||
noCache: boolean = false
|
||||
): MapDrawData {
|
||||
const id = `${floorId},${interval},${border}`;
|
||||
if (drawCache[id] && !noCache) return drawCache[id];
|
||||
const { link, maps } = getMapData(floorId, noCache);
|
||||
const locs: Partial<Record<FloorIds, LocArr>> = {};
|
||||
const line: [number, number, number, number][] = [];
|
||||
const center = core.status.maps[floorId];
|
||||
let left = -center.width / 2,
|
||||
right = center.width / 2,
|
||||
top = -center.height / 2,
|
||||
bottom = center.height / 2;
|
||||
for (const [from, to] of Object.entries(link)) {
|
||||
const [fromId, fxs, fys, dir] = from.split(',') as [
|
||||
FloorIds,
|
||||
string,
|
||||
string,
|
||||
Dir
|
||||
];
|
||||
const [toId, txs, tys] = to.split(',') as [FloorIds, string, string];
|
||||
const fromMap = core.status.maps[fromId];
|
||||
const toMap = core.status.maps[toId];
|
||||
const fx = parseInt(fxs),
|
||||
fy = parseInt(fys),
|
||||
tx = parseInt(txs),
|
||||
ty = parseInt(tys);
|
||||
const fw = fromMap.width,
|
||||
fh = fromMap.height;
|
||||
const tw = toMap.width,
|
||||
th = toMap.height;
|
||||
locs[fromId] ??= [0, 0];
|
||||
const [fromX, fromY] = locs[fromId]!;
|
||||
if (!locs[toId]) {
|
||||
const dx = core.utils.scan[dir].x,
|
||||
dy = core.utils.scan[dir].y;
|
||||
const toX =
|
||||
fromX +
|
||||
(fx - fw / 2) -
|
||||
(tx - tw / 2) +
|
||||
(border * 2 + interval) * dx,
|
||||
toY =
|
||||
fromY +
|
||||
(fy - fh / 2) -
|
||||
(ty - th / 2) +
|
||||
(border * 2 + interval) * dy;
|
||||
// 地图位置和连线位置
|
||||
locs[toId] = [toX, toY];
|
||||
}
|
||||
const [toX, toY] = locs[toId]!;
|
||||
line.push([
|
||||
fromX + (fx - fw / 2 + 0.5),
|
||||
fromY + (fy - fh / 2 + 0.5),
|
||||
toX + (tx - tw / 2 + 0.5),
|
||||
toY + (ty - th / 2 + 0.5)
|
||||
]);
|
||||
|
||||
// 计算地图总长宽
|
||||
const l = toX - tw / 2,
|
||||
r = toX + tw / 2,
|
||||
t = toY - th / 2,
|
||||
b = toY + th / 2;
|
||||
if (l < left) left = l;
|
||||
if (r > right) right = r;
|
||||
if (t < top) top = t;
|
||||
if (b > bottom) bottom = b;
|
||||
}
|
||||
|
||||
// 移动位置,居中
|
||||
Object.values(locs).forEach(v => {
|
||||
v[0] -= left;
|
||||
v[1] -= top;
|
||||
});
|
||||
line.forEach(v => {
|
||||
v[0] -= left;
|
||||
v[2] -= left;
|
||||
v[1] -= top;
|
||||
v[3] -= top;
|
||||
});
|
||||
|
||||
left -= 5;
|
||||
right += 5;
|
||||
top -= 5;
|
||||
bottom += 5;
|
||||
|
||||
const res = { locs, line, width: right - left, height: bottom - top };
|
||||
|
||||
return (drawCache[id] = res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 广度优先搜索地图信息
|
||||
@@ -53,12 +182,12 @@ export function getMapData(
|
||||
const block = blocks[loc as LocString];
|
||||
const id = block.event.id;
|
||||
if (id in arrow) {
|
||||
const from = `${now},${loc},${arrow[id]}` as BFSFromString;
|
||||
const to = `${target},${ev.loc![0]},${
|
||||
ev.loc![1]
|
||||
}` as BFSToString;
|
||||
link[from] = to;
|
||||
if (!used[target]) {
|
||||
const from = `${now},${loc},${arrow[id]}` as BFSFromString;
|
||||
const to = `${target},${ev.loc![0]},${
|
||||
ev.loc![1]
|
||||
}` as BFSToString;
|
||||
link[from] = to;
|
||||
queue.push(target);
|
||||
floors.push(target);
|
||||
}
|
||||
@@ -67,8 +196,74 @@ export function getMapData(
|
||||
used[now] = true;
|
||||
}
|
||||
|
||||
return {
|
||||
const res = {
|
||||
maps: floors,
|
||||
link
|
||||
};
|
||||
|
||||
return (bfsCache[floorId] = res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制小地图
|
||||
* @param ctx 画布
|
||||
* @param floorId 中心楼层
|
||||
* @param interval 楼层间距
|
||||
* @param border 边框粗细
|
||||
* @param noCache 是否不使用缓存
|
||||
*/
|
||||
export function drawFlyMap(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
floorId: FloorIds,
|
||||
offset: [number, number],
|
||||
size: [number, number],
|
||||
scale: number = 3,
|
||||
interval: number = 5,
|
||||
border: number = 1,
|
||||
noCache: boolean = false
|
||||
) {
|
||||
const data = getMapDrawData(floorId, interval, border, noCache);
|
||||
const [ox, oy] = offset;
|
||||
const [width, height] = size;
|
||||
const canvas = ctx.canvas;
|
||||
canvas.width = data.width * devicePixelRatio * scale;
|
||||
canvas.height = data.height * devicePixelRatio * scale;
|
||||
ctx.lineWidth = border * devicePixelRatio * scale;
|
||||
ctx.strokeStyle = '#fff';
|
||||
ctx.scale(scale, scale);
|
||||
// 绘制连线
|
||||
data.line.forEach(([x1, y1, x2, y2]) => {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x1, y1);
|
||||
ctx.lineTo(x2, y2);
|
||||
ctx.stroke();
|
||||
});
|
||||
for (const [id, [x, y]] of Object.entries(data.locs) as [
|
||||
FloorIds,
|
||||
LocArr
|
||||
][]) {
|
||||
drawThumbnail(ctx, id, scale, [x, y], offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
function drawThumbnail(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
floorId: FloorIds,
|
||||
scale: number,
|
||||
pos: [number, number],
|
||||
offset: [number, number],
|
||||
size: [number, number]
|
||||
) {
|
||||
const [x, y] = pos;
|
||||
const [ox, oy] = offset;
|
||||
const [width, height] = size;
|
||||
const map = core.status.maps[floorId];
|
||||
if (
|
||||
ox + x * scale + (map.width * scale) / 2 < 0 ||
|
||||
ox + x * scale - (map.width * scale) / 2 > width ||
|
||||
oy + y * scale + (map.height * scale) / 2 < 0 ||
|
||||
oy + y * scale - (map.height * scale) / 2 > height
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user