feat: 自动元件连接

This commit is contained in:
unanmed 2024-05-18 23:21:06 +08:00
parent 78efe81423
commit fe57adf6af
7 changed files with 112 additions and 65 deletions

View File

@ -528,6 +528,12 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = {
}).toString(), }).toString(),
"_docs": "绑定贴图", "_docs": "绑定贴图",
"_data": "该图块绑定的贴图,用法详见文档" "_data": "该图块绑定的贴图,用法详见文档"
},
"autotileConnection": {
"_leaf": true,
"_type": "textarea",
"_docs": "自动元件连接",
"_data": "此属性对自动元件有效是一个数组可以填写一些图块id从而让自动元件可以与这些图块连接从而做到自动元件能连门等操作"
} }
} }
}, },

View File

@ -113,7 +113,7 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
"140": {"cls":"npcs","id":"blackTrader","faceIds":{"down":"blueTrader","left":"redMSNpc","right":"blackTrader","up":"N532"}}, "140": {"cls":"npcs","id":"blackTrader","faceIds":{"down":"blueTrader","left":"redMSNpc","right":"blackTrader","up":"N532"}},
"141": {"cls":"autotile","id":"autotile4","script":1}, "141": {"cls":"autotile","id":"autotile4","script":1},
"142": {"cls":"autotile","id":"autotile5"}, "142": {"cls":"autotile","id":"autotile5"},
"143": {"cls":"autotile","id":"autotile6"}, "143": {"cls":"autotile","id":"autotile6","autotileConnection":["A492"]},
"144": {"cls":"autotile","id":"autotile7"}, "144": {"cls":"autotile","id":"autotile7"},
"145": {"cls":"autotile","id":"autotile8"}, "145": {"cls":"autotile","id":"autotile8"},
"146": {"cls":"autotile","id":"autotile9","canPass":true}, "146": {"cls":"autotile","id":"autotile9","canPass":true},

View File

@ -78,13 +78,13 @@ export class Logger {
}); });
} }
if (this.level <= LogLevel.ERROR && this.enabled) { if (this.level <= LogLevel.ERROR && this.enabled) {
console.error(`[ERROR Code ${code}] ${text}`);
if (!main.replayChecking) { if (!main.replayChecking) {
logTip.style.color = 'lightcoral'; logTip.style.color = 'lightcoral';
logTip.style.display = 'block'; logTip.style.display = 'block';
logTip.textContent = `Error thrown, please check in console.`; logTip.textContent = `Error thrown, please check in console.`;
hideTipText(); hideTipText();
} }
throw `[ERROR Code ${code}] ${text}`;
} }
} }

View File

@ -74,6 +74,8 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
/** 渲染信息 */ /** 渲染信息 */
renderable: Map<number, RenderableData | AutotileRenderable> = new Map(); renderable: Map<number, RenderableData | AutotileRenderable> = new Map();
/** 自动元件额外连接信息,用于对非自身图块进行连接 */
autoConn: Map<number, Set<number>> = new Map();
constructor() { constructor() {
super(); super();
@ -91,6 +93,7 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
this.autotile = splitAutotiles(this.idNumberMap); this.autotile = splitAutotiles(this.idNumberMap);
this.images = core.material.images.images; this.images = core.material.images.images;
this.calRenderable(); this.calRenderable();
this.calAutotileConnections();
}); });
} }
@ -109,13 +112,17 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
/** /**
* *
*/ */
calRenderable() { private calRenderable() {
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e; const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
for (const [key, data] of Object.entries(map)) { for (const [key, data] of Object.entries(map)) {
this.calRenderableByNum(parseInt(key)); this.calRenderableByNum(parseInt(key));
} }
} }
/**
*
* @param num
*/
calRenderableByNum( calRenderableByNum(
num: number num: number
): RenderableData | AutotileRenderable | null { ): RenderableData | AutotileRenderable | null {
@ -290,6 +297,38 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
getRenderable(num: number) { getRenderable(num: number) {
return this.renderable.get(num) ?? this.calRenderableByNum(num); return this.renderable.get(num) ?? this.calRenderableByNum(num);
} }
/**
*
*/
private calAutotileConnections() {
const icons = icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1;
const maps = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
Object.keys(icons.autotile).forEach(v => {
const num = this.idNumberMap[v as AllIdsOf<'autotile'>];
const data = maps[num];
const { autotileConnection } = data;
if (!autotileConnection) return;
const list = new Set<AllNumbers>();
autotileConnection.forEach(v => {
if (typeof v === 'number') {
list.add(v);
} else {
list.add(this.idNumberMap[v]);
}
});
this.autoConn.set(num, list);
});
}
/**
*
* @param num
*/
getAutotileConnections(num: number) {
return this.autoConn.get(num);
}
} }
export const texture = new TextureCache(); export const texture = new TextureCache();
@ -302,7 +341,6 @@ const smallAutotile: Record<number, [number, number, number, number]> = {};
function getAutotileIndices() { function getAutotileIndices() {
// 应当从 0 - 255 进行枚举 // 应当从 0 - 255 进行枚举
// 二进制从高位到低位依次是 左上 上 右上 右 右下 下 左下 左 // 二进制从高位到低位依次是 左上 上 右上 右 右下 下 左下 左
// 首先是3x4的
// 有兴趣可以研究下这个算法 // 有兴趣可以研究下这个算法
const get = ( const get = (
target: Record<number, [number, number, number, number]>, target: Record<number, [number, number, number, number]>,

View File

@ -314,6 +314,11 @@ export class Layer extends Container implements IRenderDestroyable {
const tile = texture.autotile; const tile = texture.autotile;
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e; const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
const w = this.mapWidth;
const h = this.mapHeight;
this.autotiles = {};
/** /**
* *
* @param id id * @param id id
@ -323,42 +328,49 @@ export class Layer extends Container implements IRenderDestroyable {
* @param replace2 * @param replace2
*/ */
const check = ( const check = (
index1: number, x1: number,
index2: number, y1: number,
x2: number,
y2: number,
replace1: number, replace1: number,
replace2: number _replace2: number
) => { ) => {
const index1 = x1 + y1 * w;
const index2 = x2 + y2 * w;
this.autotiles[index1] ??= 0;
this.autotiles[index2] ??= 0;
// 与地图边缘,视为连接
if (x2 < 0 || y2 < 0 || x2 >= w || y2 >= h) {
this.autotiles[index1] |= replace1;
return;
}
const num1 = data[index1] as AllNumbersOf<'autotile'>; // 这个一定是自动元件 const num1 = data[index1] as AllNumbersOf<'autotile'>; // 这个一定是自动元件
const num2 = data[index2] as AllNumbersOf<'autotile'>; const num2 = data[index2] as AllNumbersOf<'autotile'>;
// 对于额外连接的情况
const autoConn = texture.getAutotileConnections(num1);
if (autoConn?.has(num2)) {
this.autotiles[index1] |= replace1;
return;
}
const info = map[num2 as Exclude<AllNumbers, 0>]; const info = map[num2 as Exclude<AllNumbers, 0>];
if (info.cls !== 'autotile') { if (!info || info.cls !== 'autotile') {
// 被比较对象不是自动元件 // 被比较对象不是自动元件
this.autotiles[num1] ??= 0; this.autotiles[index1] &= ~replace1;
this.autotiles[num1] &= ~replace1;
} else { } else {
const parent1 = tile[num1].parent;
const parent2 = tile[num2].parent; const parent2 = tile[num2].parent;
if (num2 === num1) { if (num2 === num1) {
// 二者一样,视为连接 // 二者一样,视为连接
this.autotiles[index1] |= replace1; this.autotiles[index1] |= replace1;
this.autotiles[index2] |= replace2;
} else if (parent2?.has(num1)) { } else if (parent2?.has(num1)) {
// 被比较对象是比较对象的父元件,那么比较对象视为连接 // 被比较对象是比较对象的父元件,那么比较对象视为连接
this.autotiles[index1] |= replace1; this.autotiles[index1] |= replace1;
} else if (parent1?.has(num2)) {
// 比较对象是被比较对象的父元件,那么被比较对象视为连接
this.autotiles[index2] |= replace2;
} else { } else {
// 上述条件都不满足,那么不连接 // 上述条件都不满足,那么不连接
this.autotiles[index1] &= ~replace1; this.autotiles[index1] &= ~replace1;
this.autotiles[index2] &= ~replace2;
} }
} }
}; };
const w = this.mapWidth;
const h = this.mapHeight;
for (let nx = x; nx < ex; nx++) { for (let nx = x; nx < ex; nx++) {
for (let ny = y; ny < ey; ny++) { for (let ny = y; ny < ey; ny++) {
if (nx > w || ny > h) continue; if (nx > w || ny > h) continue;
@ -371,26 +383,18 @@ export class Layer extends Container implements IRenderDestroyable {
const { cls } = info; const { cls } = info;
if (cls !== 'autotile') continue; if (cls !== 'autotile') continue;
// 只有最左一列和最上一列需要计算一周,其他的只计算右 右下 下即可
// 太地狱了这个,看看就好 // 太地狱了这个,看看就好
if (nx === x) { // 左上 左 左下
// 左上 左 左下 check(nx, ny, nx - 1, ny - 1, 0b10000000, 0b00001000);
check(index, index - w - 1, 0b10000000, 0b00001000); check(nx, ny, nx - 1, ny, 0b00000001, 0b00010000);
check(index, index - 1, 0b00000001, 0b00010000); check(nx, ny, nx - 1, ny + 1, 0b00000010, 0b00100000);
check(index, index + w - 1, 0b00000010, 0b00100000); // 上 右上
} check(nx, ny, nx, ny - 1, 0b01000000, 0b00000100);
if (ny === y) { check(nx, ny, nx + 1, ny - 1, 0b00100000, 0b00000010);
if (nx !== x) {
check(index, index - w - 1, 0b10000000, 0b00001000);
}
// 上 右上
check(index, index - w, 0b01000000, 0b00000100);
check(index, index - w + 1, 0b00100000, 0b00000010);
}
// 右 右下 下 // 右 右下 下
check(index, index + 1, 0b00010000, 0b00000001); check(nx, ny, nx + 1, ny, 0b00010000, 0b00000001);
check(index, index + w + 1, 0b00001000, 0b10000000); check(nx, ny, nx + 1, ny + 1, 0b00001000, 0b10000000);
check(index, index + w, 0b00000100, 0b01000000); check(nx, ny, nx, ny + 1, 0b00000100, 0b01000000);
} }
} }
} }

View File

@ -154,21 +154,21 @@ Mota.require('var', 'hook').once('reset', () => {
render.appendChild([layer, bgLayer]); render.appendChild([layer, bgLayer]);
layer.bindThis('event'); layer.bindThis('event');
bgLayer.bindThis('bg'); bgLayer.bindThis('bg');
bgLayer.setBackground(650); bgLayer.setBackground(305);
const ani = new Animation(); const ani = new Animation();
ani.ticker.add(() => { // ani.ticker.add(() => {
camera.reset(); // camera.reset();
camera.rotate((ani.angle / 180) * Math.PI); // camera.rotate((ani.angle / 180) * Math.PI);
camera.move(ani.x, ani.y); // camera.move(ani.x, ani.y);
camera.scale(ani.size); // camera.scale(ani.size);
render.update(render); // render.update(render);
}); // });
camera.rotate(Math.PI * 1.23); // camera.rotate(Math.PI * 1.23);
camera.move(230, 380); camera.move(240, 240);
camera.scale(0.7); // camera.scale(0.7);
render.update(); render.update();
// sleep(2000).then(() => { // sleep(2000).then(() => {
@ -176,21 +176,21 @@ Mota.require('var', 'hook').once('reset', () => {
// }); // });
sleep(1000).then(() => { sleep(1000).then(() => {
ani.mode(hyper('sin', 'out')) // ani.mode(hyper('sin', 'out'))
.time(100) // .time(100)
.absolute() // .absolute()
.rotate(30) // .rotate(30)
.move(240, 240); // .move(240, 240);
sleep(100).then(() => { // sleep(100).then(() => {
ani.time(3000).rotate(0); // ani.time(3000).rotate(0);
}); // });
sleep(3100).then(() => { // sleep(3100).then(() => {
ani.time(5000) // ani.time(5000)
.mode(hyper('sin', 'in-out')) // .mode(hyper('sin', 'in-out'))
.rotate(360) // .rotate(360)
.move(200, 480) // .move(200, 480)
.scale(0.5); // .scale(0.5);
}); // });
// ani.mode(shake2(5, hyper('sin', 'in-out')), true) // ani.mode(shake2(5, hyper('sin', 'in-out')), true)
// .time(5000) // .time(5000)
// .shake(1, 0); // .shake(1, 0);

3
src/types/core.d.ts vendored
View File

@ -1417,10 +1417,9 @@ interface MapDataOf<T extends keyof NumberToId> {
cls: ClsOf<NumberToId[T]>; cls: ClsOf<NumberToId[T]>;
bigImage?: ImageIds; bigImage?: ImageIds;
faceIds?: Record<Dir, AllIds>; faceIds?: Record<Dir, AllIds>;
animate?: number; animate?: number;
autotileConnection?: (AllIds | AllNumbers)[];
} }
/** /**