mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-31 23:29:27 +08:00
feat: 地图渲染基本完成
This commit is contained in:
parent
117bd94928
commit
78efe81423
@ -40,7 +40,7 @@ var enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 =
|
|||||||
"angel": {"name":"天使","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
"angel": {"name":"天使","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||||
"elemental": {"name":"元素生物","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
"elemental": {"name":"元素生物","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||||
"steelGuard": {"name":"铁守卫","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[18],"value":20},
|
"steelGuard": {"name":"铁守卫","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[18],"value":20},
|
||||||
"evilBat": {"name":"邪恶蝙蝠","hp":1000,"atk":800,"def":350,"money":1,"exp":40,"point":0,"special":[2],"bigImage":"bear.png"},
|
"evilBat": {"name":"邪恶蝙蝠","hp":1000,"atk":800,"def":350,"money":1,"exp":40,"point":0,"special":[2],"bigImage":null},
|
||||||
"frozenSkeleton": {"name":"冻死骨","hp":7500,"atk":2500,"def":1000,"money":2,"exp":90,"point":0,"special":[1,20],"crit":500,"ice":10,"description":"弱小,无助,哀嚎,这就是残酷的现实。哪怕你身处极寒之中,也难有人对你伸出援手。人类总会帮助他人,但在这绝望的环境下,人类的本性便暴露无遗。这一个个精致却又无情的骷髅,便是那些在极寒之中死去的冤魂。"},
|
"frozenSkeleton": {"name":"冻死骨","hp":7500,"atk":2500,"def":1000,"money":2,"exp":90,"point":0,"special":[1,20],"crit":500,"ice":10,"description":"弱小,无助,哀嚎,这就是残酷的现实。哪怕你身处极寒之中,也难有人对你伸出援手。人类总会帮助他人,但在这绝望的环境下,人类的本性便暴露无遗。这一个个精致却又无情的骷髅,便是那些在极寒之中死去的冤魂。"},
|
||||||
"silverSlimelord": {"name":"银怪王","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
"silverSlimelord": {"name":"银怪王","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||||
"goldSlimelord": {"name":"金怪王","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
"goldSlimelord": {"name":"金怪王","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"special":[]},
|
||||||
|
@ -32,6 +32,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = {
|
|||||||
// 初始化地图
|
// 初始化地图
|
||||||
core.status.floorId = floorId;
|
core.status.floorId = floorId;
|
||||||
core.status.maps = maps;
|
core.status.maps = maps;
|
||||||
|
core.extractBlocks(floorId);
|
||||||
core.maps._resetFloorImages();
|
core.maps._resetFloorImages();
|
||||||
// 初始化怪物和道具
|
// 初始化怪物和道具
|
||||||
core.material.enemys = core.enemys.getEnemys();
|
core.material.enemys = core.enemys.getEnemys();
|
||||||
|
@ -73,7 +73,7 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
|
|||||||
"83": {"cls":"animates","id":"redDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"redKey":1}},"name":"红门"},
|
"83": {"cls":"animates","id":"redDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"redKey":1}},"name":"红门"},
|
||||||
"84": {"cls":"animates","id":"greenDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"greenKey":1}},"name":"绿门"},
|
"84": {"cls":"animates","id":"greenDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"greenKey":1}},"name":"绿门"},
|
||||||
"85": {"cls":"animates","id":"specialDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"specialKey":1}},"name":"机关门"},
|
"85": {"cls":"animates","id":"specialDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"specialKey":1}},"name":"机关门"},
|
||||||
"86": {"cls":"animates","id":"steelDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"steelKey":1}},"name":"铁门","bigImage":"bear.png"},
|
"86": {"cls":"animates","id":"steelDoor","trigger":"openDoor","animate":1,"doorInfo":{"time":160,"openSound":"door.mp3","closeSound":"door.mp3","keys":{"steelKey":1}},"name":"铁门","bigImage":null},
|
||||||
"87": {"cls":"terrains","id":"upFloor","canPass":true},
|
"87": {"cls":"terrains","id":"upFloor","canPass":true},
|
||||||
"88": {"cls":"terrains","id":"downFloor","canPass":true},
|
"88": {"cls":"terrains","id":"downFloor","canPass":true},
|
||||||
"89": {"cls":"animates","id":"portal","canPass":true},
|
"89": {"cls":"animates","id":"portal","canPass":true},
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { EmitableEvent, EventEmitter } from '../common/eventEmitter';
|
import { EmitableEvent, EventEmitter } from '../common/eventEmitter';
|
||||||
|
import { logger } from '../common/logger';
|
||||||
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
||||||
|
import { SizedCanvasImageSource } from './preset/misc';
|
||||||
|
|
||||||
// 经过测试(https://www.measurethat.net/Benchmarks/Show/30741/1/drawimage-img-vs-canvas-vs-bitmap-cropping-fix-loading)
|
// 经过测试(https://www.measurethat.net/Benchmarks/Show/30741/1/drawimage-img-vs-canvas-vs-bitmap-cropping-fix-loading)
|
||||||
// 得出结论,ImageBitmap和Canvas的绘制性能不如Image,于是直接画Image就行,所以缓存基本上就是存Image
|
// 得出结论,ImageBitmap和Canvas的绘制性能不如Image,于是直接画Image就行,所以缓存基本上就是存Image
|
||||||
@ -39,6 +41,27 @@ interface TextureRequire {
|
|||||||
images: Record<ImageIds, HTMLImageElement>;
|
images: Record<ImageIds, HTMLImageElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface RenderableDataBase {
|
||||||
|
/** 图块的总帧数 */
|
||||||
|
frame: number;
|
||||||
|
/** 对应图块属性的动画帧数,-1表示没有设定 */
|
||||||
|
animate: number;
|
||||||
|
/** 是否是大怪物 */
|
||||||
|
bigImage: boolean;
|
||||||
|
render: [x: number, y: number, width: number, height: number][];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RenderableData extends RenderableDataBase {
|
||||||
|
image: SizedCanvasImageSource;
|
||||||
|
autotile: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutotileRenderable extends RenderableDataBase {
|
||||||
|
image: Record<string, SizedCanvasImageSource>;
|
||||||
|
autotile: true;
|
||||||
|
bigImage: false;
|
||||||
|
}
|
||||||
|
|
||||||
interface TextureCacheEvent extends EmitableEvent {}
|
interface TextureCacheEvent extends EmitableEvent {}
|
||||||
|
|
||||||
class TextureCache extends EventEmitter<TextureCacheEvent> {
|
class TextureCache extends EventEmitter<TextureCacheEvent> {
|
||||||
@ -49,6 +72,9 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
|
|||||||
|
|
||||||
idNumberMap!: IdToNumber;
|
idNumberMap!: IdToNumber;
|
||||||
|
|
||||||
|
/** 渲染信息 */
|
||||||
|
renderable: Map<number, RenderableData | AutotileRenderable> = new Map();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.material = imageMap as Record<ImageMapKeys, HTMLImageElement>;
|
this.material = imageMap as Record<ImageMapKeys, HTMLImageElement>;
|
||||||
@ -64,6 +90,7 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
|
|||||||
this.tileset = core.material.images.tilesets;
|
this.tileset = core.material.images.tilesets;
|
||||||
this.autotile = splitAutotiles(this.idNumberMap);
|
this.autotile = splitAutotiles(this.idNumberMap);
|
||||||
this.images = core.material.images.images;
|
this.images = core.material.images.images;
|
||||||
|
this.calRenderable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +105,191 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
|
|||||||
): TextureRequire[T][K] {
|
): TextureRequire[T][K] {
|
||||||
return this[type][key];
|
return this[type][key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算每个图块的可渲染信息
|
||||||
|
*/
|
||||||
|
calRenderable() {
|
||||||
|
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
|
||||||
|
for (const [key, data] of Object.entries(map)) {
|
||||||
|
this.calRenderableByNum(parseInt(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
calRenderableByNum(
|
||||||
|
num: number
|
||||||
|
): RenderableData | AutotileRenderable | null {
|
||||||
|
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
|
||||||
|
const enemys = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80;
|
||||||
|
const icons = icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1;
|
||||||
|
|
||||||
|
/** 特判空图块与空气墙 */
|
||||||
|
if (num === 0 || num === 17) return null;
|
||||||
|
|
||||||
|
// 额外素材
|
||||||
|
if (num >= 10000) {
|
||||||
|
const offset = core.getTilesetOffset(num);
|
||||||
|
if (!offset) return null;
|
||||||
|
const { image, x, y } = offset;
|
||||||
|
const data: RenderableData = {
|
||||||
|
image: this.tileset[image],
|
||||||
|
frame: 1,
|
||||||
|
render: [[x * 32, y * 32, 32, 32]],
|
||||||
|
animate: 0,
|
||||||
|
autotile: false,
|
||||||
|
bigImage: false
|
||||||
|
};
|
||||||
|
this.renderable.set(num, data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = map[num as Exclude<AllNumbers, 0>];
|
||||||
|
// 地狱般的分支if
|
||||||
|
if (data) {
|
||||||
|
let { cls, faceIds, bigImage, id, animate } = data;
|
||||||
|
if (cls === 'enemys' || cls === 'enemy48') {
|
||||||
|
// 怪物需要特殊处理,因为它的大怪物信息不在 maps 里面
|
||||||
|
({ bigImage, faceIds } = enemys[id as EnemyIds]);
|
||||||
|
}
|
||||||
|
if (bigImage) {
|
||||||
|
const image = core.material.images.images[bigImage];
|
||||||
|
if (!image) {
|
||||||
|
logger.warn(
|
||||||
|
10,
|
||||||
|
`Cannot resolve big image of enemy '${id}'.`
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let line = 0;
|
||||||
|
if (faceIds) {
|
||||||
|
const arr = ['down', 'left', 'right', 'up'];
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
if (faceIds[arr[i] as Dir] === id) {
|
||||||
|
line = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const totalLines = image.width / image.height >= 2 ? 1 : 4;
|
||||||
|
const w = Math.round(image.width / 4);
|
||||||
|
const h = Math.round(image.height / totalLines);
|
||||||
|
const y = h * line;
|
||||||
|
const data: RenderableData = {
|
||||||
|
image,
|
||||||
|
frame: 4,
|
||||||
|
render: [
|
||||||
|
[0, y, w, h],
|
||||||
|
[w, y, w, h],
|
||||||
|
[w * 2, y, w, h],
|
||||||
|
[w * 3, y, w, h]
|
||||||
|
],
|
||||||
|
animate: (animate ?? 0) - 1,
|
||||||
|
autotile: false,
|
||||||
|
bigImage: true
|
||||||
|
};
|
||||||
|
this.renderable.set(num, data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
// enemy48和npc48都应该视为大怪物
|
||||||
|
if (cls === 'enemy48' || cls === 'npc48') {
|
||||||
|
const img = core.material.images[cls];
|
||||||
|
// @ts-ignore
|
||||||
|
const line = icons[cls][id];
|
||||||
|
const w = 32;
|
||||||
|
const h = 48;
|
||||||
|
const y = h * line;
|
||||||
|
const data: RenderableData = {
|
||||||
|
image: img,
|
||||||
|
frame: 4,
|
||||||
|
render: [
|
||||||
|
[0, y, w, h],
|
||||||
|
[w, y, w, h],
|
||||||
|
[w * 2, y, w, h],
|
||||||
|
[w * 3, y, w, h]
|
||||||
|
],
|
||||||
|
animate: (animate ?? 0) - 1,
|
||||||
|
autotile: false,
|
||||||
|
bigImage: true
|
||||||
|
};
|
||||||
|
this.renderable.set(num, data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
// 自动元件
|
||||||
|
if (cls === 'autotile') {
|
||||||
|
const auto = this.autotile[num as AllNumbersOf<'autotile'>];
|
||||||
|
const cell = 32;
|
||||||
|
const render: [number, number, number, number][] = [];
|
||||||
|
if (auto.frame >= 1) {
|
||||||
|
render.push([0, 0, cell, cell]);
|
||||||
|
}
|
||||||
|
if (auto.frame >= 3) {
|
||||||
|
render.push(
|
||||||
|
[cell, 0, cell, cell],
|
||||||
|
[cell * 2, 0, cell, cell]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (auto.frame >= 4) {
|
||||||
|
render.push([cell * 3, 0, cell, cell]);
|
||||||
|
}
|
||||||
|
const data: AutotileRenderable = {
|
||||||
|
image: auto.cache,
|
||||||
|
frame: auto.frame,
|
||||||
|
render,
|
||||||
|
autotile: true,
|
||||||
|
bigImage: false,
|
||||||
|
animate: (animate ?? 0) - 1
|
||||||
|
};
|
||||||
|
this.renderable.set(num, data);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
const image =
|
||||||
|
core.material.images[
|
||||||
|
cls as Exclude<Cls, 'tileset' | 'autotile'>
|
||||||
|
];
|
||||||
|
const frame = core.getAnimateFrames(cls);
|
||||||
|
const cell = 32;
|
||||||
|
// @ts-ignore
|
||||||
|
const offset = (icons[cls][id] as number) * cell;
|
||||||
|
const render: [number, number, number, number][] = [
|
||||||
|
[0, offset, cell, cell]
|
||||||
|
];
|
||||||
|
if (frame === 2) {
|
||||||
|
render.push([cell, offset, cell, cell]);
|
||||||
|
}
|
||||||
|
if (frame === 4) {
|
||||||
|
render.push(
|
||||||
|
[cell, offset, cell, cell],
|
||||||
|
[cell * 2, offset, cell, cell],
|
||||||
|
[cell * 3, offset, cell, cell]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const data: RenderableData = {
|
||||||
|
image,
|
||||||
|
frame: frame,
|
||||||
|
render,
|
||||||
|
autotile: false,
|
||||||
|
bigImage: false,
|
||||||
|
animate: (animate ?? 0) - 1
|
||||||
|
};
|
||||||
|
this.renderable.set(num, data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warn(
|
||||||
|
11,
|
||||||
|
`Cannot resolve material ${num}. Material not exists.`
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取一个图块的渲染信息,自动元件会特别标明autotile属性
|
||||||
|
* @param num 图块数字
|
||||||
|
*/
|
||||||
|
getRenderable(num: number) {
|
||||||
|
return this.renderable.get(num) ?? this.calRenderableByNum(num);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const texture = new TextureCache();
|
export const texture = new TextureCache();
|
||||||
|
@ -26,6 +26,10 @@ export class Container extends RenderItem implements ICanvasCachedRenderItem {
|
|||||||
camera: Camera
|
camera: Camera
|
||||||
): void {
|
): void {
|
||||||
this.emit('beforeRender');
|
this.emit('beforeRender');
|
||||||
|
if (this.needUpdate) {
|
||||||
|
this.cache(this.writing);
|
||||||
|
this.needUpdate = false;
|
||||||
|
}
|
||||||
withCacheRender(this, canvas, ctx, camera, c => {
|
withCacheRender(this, canvas, ctx, camera, c => {
|
||||||
this.sortedChildren.forEach(v => {
|
this.sortedChildren.forEach(v => {
|
||||||
if (!v.antiAliasing) {
|
if (!v.antiAliasing) {
|
||||||
|
@ -77,7 +77,7 @@ interface IRenderConfig {
|
|||||||
setHD(hd: boolean): void;
|
setHD(hd: boolean): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置当前渲染原始是否启用抗锯齿
|
* 设置当前渲染元素是否启用抗锯齿
|
||||||
* @param anti 是否抗锯齿
|
* @param anti 是否抗锯齿
|
||||||
*/
|
*/
|
||||||
setAntiAliasing(anti: boolean): void;
|
setAntiAliasing(anti: boolean): void;
|
||||||
@ -135,7 +135,7 @@ export abstract class RenderItem
|
|||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.using = '@default';
|
// this.using = '@default';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -194,21 +194,7 @@ export abstract class RenderItem
|
|||||||
update(item?: RenderItem): void {
|
update(item?: RenderItem): void {
|
||||||
if (this.needUpdate) return;
|
if (this.needUpdate) return;
|
||||||
this.needUpdate = true;
|
this.needUpdate = true;
|
||||||
requestAnimationFrame(() => {
|
this.parent?.update(item);
|
||||||
this.needUpdate = false;
|
|
||||||
if (!this.parent) return;
|
|
||||||
this.cache(this.writing);
|
|
||||||
this.refresh(item);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 立刻更新这个组件,不延迟到下一个tick
|
|
||||||
*/
|
|
||||||
protected refresh(item?: RenderItem) {
|
|
||||||
this.emit('beforeUpdate', item);
|
|
||||||
this.parent?.refresh(item);
|
|
||||||
this.emit('afterUpdate', item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setHD(hd: boolean): void {
|
setHD(hd: boolean): void {
|
||||||
@ -223,7 +209,7 @@ export abstract class RenderItem
|
|||||||
|
|
||||||
setZIndex(zIndex: number) {
|
setZIndex(zIndex: number) {
|
||||||
this.zIndex = zIndex;
|
this.zIndex = zIndex;
|
||||||
(this.parent as Container).sortChildren?.();
|
(this.parent as Container)?.sortChildren?.();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,7 @@ import { Camera } from '../camera';
|
|||||||
import { TimingFn } from 'mutate-animate';
|
import { TimingFn } from 'mutate-animate';
|
||||||
import { IRenderDestroyable, RenderItem } from '../item';
|
import { IRenderDestroyable, RenderItem } from '../item';
|
||||||
import { logger } from '@/core/common/logger';
|
import { logger } from '@/core/common/logger';
|
||||||
import { texture } from '../cache';
|
import { AutotileRenderable, RenderableData, texture } from '../cache';
|
||||||
import { SizedCanvasImageSource } from './misc';
|
|
||||||
import { glMatrix } from 'gl-matrix';
|
import { glMatrix } from 'gl-matrix';
|
||||||
|
|
||||||
interface LayerCacheItem {
|
interface LayerCacheItem {
|
||||||
@ -14,24 +13,12 @@ interface LayerCacheItem {
|
|||||||
canvas: HTMLCanvasElement;
|
canvas: HTMLCanvasElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LayerRenderableData {
|
interface LayerMovingRenderable extends RenderableData {
|
||||||
image: SizedCanvasImageSource;
|
|
||||||
frame: number;
|
|
||||||
render: [x: number, y: number, width: number, height: number][];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LayerMovingRenderable extends LayerRenderableData {
|
|
||||||
zIndex: number;
|
zIndex: number;
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BigImageData {
|
|
||||||
image: HTMLImageElement;
|
|
||||||
line: number;
|
|
||||||
totalLines: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface NeedRenderData {
|
interface NeedRenderData {
|
||||||
/** 需要渲染的地图内容 */
|
/** 需要渲染的地图内容 */
|
||||||
res: Set<number>;
|
res: Set<number>;
|
||||||
@ -82,7 +69,7 @@ interface MovingBlock {
|
|||||||
/** 目标纵坐标 */
|
/** 目标纵坐标 */
|
||||||
y: number;
|
y: number;
|
||||||
/** 渲染信息 */
|
/** 渲染信息 */
|
||||||
render: LayerRenderableData;
|
render: RenderableData | AutotileRenderable;
|
||||||
/** 当前的纵深 */
|
/** 当前的纵深 */
|
||||||
nowZ: number;
|
nowZ: number;
|
||||||
}
|
}
|
||||||
@ -124,10 +111,6 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
layer?: FloorLayer;
|
layer?: FloorLayer;
|
||||||
/** 渲染数据 */
|
/** 渲染数据 */
|
||||||
renderData: number[] = [];
|
renderData: number[] = [];
|
||||||
/** 可以直接被渲染的内容 */
|
|
||||||
renderable: Map<number, LayerRenderableData> = new Map();
|
|
||||||
/** 移动层中可以直接被渲染的内容 */
|
|
||||||
movingRenderable: LayerMovingRenderable[] = [];
|
|
||||||
/** 自动元件的连接信息,键表示图块在渲染数据中的索引,值表示连接信息,是个8位二进制 */
|
/** 自动元件的连接信息,键表示图块在渲染数据中的索引,值表示连接信息,是个8位二进制 */
|
||||||
autotiles: Record<number, number> = {};
|
autotiles: Record<number, number> = {};
|
||||||
/** 楼层宽度 */
|
/** 楼层宽度 */
|
||||||
@ -136,8 +119,6 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
mapHeight: number = 0;
|
mapHeight: number = 0;
|
||||||
/** 每个图块的大小 */
|
/** 每个图块的大小 */
|
||||||
cellSize: number = 32;
|
cellSize: number = 32;
|
||||||
/** moving层的缓存信息,从低位到高位依次是第1帧至第4帧 */
|
|
||||||
movingCached: number = 0b0000;
|
|
||||||
|
|
||||||
/** 背景图块 */
|
/** 背景图块 */
|
||||||
background: AllNumbers = 0;
|
background: AllNumbers = 0;
|
||||||
@ -152,28 +133,33 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
restWidth: 0
|
restWidth: 0
|
||||||
};
|
};
|
||||||
blockSize: number = core._WIDTH_;
|
blockSize: number = core._WIDTH_;
|
||||||
|
|
||||||
/** 正在移动的图块 */
|
/** 正在移动的图块 */
|
||||||
moving: MovingBlock[] = [];
|
moving: MovingBlock[] = [];
|
||||||
/** 大怪物(大图块)信息,键是图块在渲染数据中的索引,值是大怪物所用图片 */
|
/** 大怪物渲染信息 */
|
||||||
bigImage: Map<number, BigImageData> = new Map();
|
bigImages: Map<number, LayerMovingRenderable> = new Map();
|
||||||
|
/** 移动层的渲染信息 */
|
||||||
|
movingRenderable: LayerMovingRenderable[] = [];
|
||||||
|
/** 下一此渲染时是否需要更新移动层的渲染信息 */
|
||||||
|
needUpdateMoving: boolean = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super('absolute');
|
super('absolute');
|
||||||
|
|
||||||
this.setHD(false);
|
// this.setHD(false);
|
||||||
this.setAntiAliasing(false);
|
this.setAntiAliasing(false);
|
||||||
this.size(core._PX_, core._PY_);
|
this.size(core._PX_, core._PY_);
|
||||||
|
|
||||||
this.staticMap.setHD(false);
|
this.staticMap.setHD(false);
|
||||||
this.staticMap.setAntiAliasing(false);
|
// this.staticMap.setAntiAliasing(false);
|
||||||
this.staticMap.withGameScale(false);
|
this.staticMap.withGameScale(false);
|
||||||
this.staticMap.size(core._PX_, core._PY_);
|
this.staticMap.size(core._PX_, core._PY_);
|
||||||
this.movingMap.setHD(false);
|
this.movingMap.setHD(false);
|
||||||
this.movingMap.setAntiAliasing(false);
|
// this.movingMap.setAntiAliasing(false);
|
||||||
this.movingMap.withGameScale(false);
|
this.movingMap.withGameScale(false);
|
||||||
this.movingMap.size(core._PX_, core._PY_);
|
this.movingMap.size(core._PX_, core._PY_);
|
||||||
this.backMap.setHD(false);
|
this.backMap.setHD(false);
|
||||||
this.backMap.setAntiAliasing(false);
|
// this.backMap.setAntiAliasing(false);
|
||||||
this.backMap.withGameScale(false);
|
this.backMap.withGameScale(false);
|
||||||
this.backMap.size(core._PX_, core._PY_);
|
this.backMap.size(core._PX_, core._PY_);
|
||||||
this.main.setAntiAliasing(false);
|
this.main.setAntiAliasing(false);
|
||||||
@ -211,7 +197,7 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
generateBackground() {
|
generateBackground() {
|
||||||
const num = this.background;
|
const num = this.background;
|
||||||
|
|
||||||
const data = this.getRenderableByNum(num);
|
const data = texture.getRenderable(num);
|
||||||
this.backImage = [];
|
this.backImage = [];
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
@ -231,7 +217,7 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
temp.withGameScale(false);
|
temp.withGameScale(false);
|
||||||
temp.size(w, h);
|
temp.size(w, h);
|
||||||
|
|
||||||
const img = data.image;
|
const img = data.autotile ? data.image[0b11111111] : data.image;
|
||||||
tempCtx.drawImage(img, sx, sy, w, h, 0, 0, w, h);
|
tempCtx.drawImage(img, sx, sy, w, h, 0, 0, w, h);
|
||||||
const pattern = ctx.createPattern(temp.canvas, 'repeat');
|
const pattern = ctx.createPattern(temp.canvas, 'repeat');
|
||||||
if (!pattern) continue;
|
if (!pattern) continue;
|
||||||
@ -256,8 +242,6 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
y: number = 0,
|
y: number = 0,
|
||||||
calAutotile: boolean = true
|
calAutotile: boolean = true
|
||||||
) {
|
) {
|
||||||
console.trace();
|
|
||||||
|
|
||||||
if (data.length % width !== 0) {
|
if (data.length % width !== 0) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
8,
|
8,
|
||||||
@ -286,251 +270,38 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (calAutotile) this.calAutotiles(x, y, width, height);
|
if (calAutotile) this.calAutotiles(x, y, width, height);
|
||||||
this.updateBigImages(x, y, width, height);
|
// this.updateBigImages(x, y, width, height);
|
||||||
this.updateRenderableData(x, y, width, height);
|
// this.updateRenderableData(x, y, width, height);
|
||||||
this.updateBlocks(x, y, width, height);
|
this.updateBlocks(x, y, width, height);
|
||||||
this.update(this);
|
this.update(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新给定区域内的大怪物信息
|
* 更新大怪物的渲染信息
|
||||||
*/
|
*/
|
||||||
updateBigImages(x: number, y: number, width: number, height: number) {
|
updateBigImages(x: number, y: number, width: number, height: number) {
|
||||||
const ex = Math.min(x + width, this.mapWidth);
|
const ex = x + width;
|
||||||
const ey = Math.min(y + height, this.mapHeight);
|
const ey = y + height;
|
||||||
const size = this.blockSize;
|
const w = this.mapWidth;
|
||||||
const images = this.bigImage;
|
|
||||||
const data = this.renderData;
|
const data = this.renderData;
|
||||||
const enemys = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80;
|
|
||||||
const icons = icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1;
|
|
||||||
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
|
|
||||||
|
|
||||||
for (let nx = Math.max(x, 0); nx < ex; nx++) {
|
for (let nx = x; nx < ex; nx++) {
|
||||||
for (let ny = Math.max(y, 0); ny < ey; ny++) {
|
for (let ny = y; ny < ey; ny++) {
|
||||||
const index = ny * size + nx;
|
const index = ny * w + nx;
|
||||||
images.delete(index);
|
this.bigImages.delete(index);
|
||||||
const num = data[index];
|
const num = data[index];
|
||||||
|
const renderable = texture.getRenderable(num);
|
||||||
// 如果不存在图块或图块是空气墙,跳过
|
if (!renderable || !renderable.bigImage) continue;
|
||||||
if (num === 0 || num === 17 || num >= 10000) continue;
|
this.bigImages.set(index, {
|
||||||
|
...renderable,
|
||||||
let { cls, id, bigImage, faceIds } =
|
x: nx,
|
||||||
map[num as Exclude<AllNumbers, 0>];
|
y: ny,
|
||||||
if (cls === 'enemys' || cls === 'enemy48') {
|
zIndex: ny
|
||||||
// 怪物需要特殊处理,因为它的大怪物信息不在 maps 里面
|
|
||||||
({ bigImage, faceIds } = enemys[id as EnemyIds]);
|
|
||||||
}
|
|
||||||
if (bigImage) {
|
|
||||||
const image = core.material.images.images[bigImage];
|
|
||||||
if (!image) {
|
|
||||||
logger.warn(
|
|
||||||
10,
|
|
||||||
`Cannot resolve big image of enemy '${id}'.`
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let line = 0;
|
|
||||||
if (faceIds) {
|
|
||||||
const arr = ['down', 'left', 'right', 'up'];
|
|
||||||
for (let i = 0; i < arr.length; i++) {
|
|
||||||
if (faceIds[arr[i] as Dir] === id) {
|
|
||||||
line = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const totalLines = image.width / image.height >= 2 ? 1 : 4;
|
|
||||||
images.set(index, {
|
|
||||||
image,
|
|
||||||
line,
|
|
||||||
totalLines
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (cls === 'enemy48' || cls === 'npc48') {
|
|
||||||
// 32 * 48 视为大怪物
|
|
||||||
const img = core.material.images[cls];
|
|
||||||
const totalLines = Math.round(img.height / 48);
|
|
||||||
// @ts-ignore
|
|
||||||
const line = icons[cls][id];
|
|
||||||
images.set(index, {
|
|
||||||
image: img,
|
|
||||||
line,
|
|
||||||
totalLines
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
this.needUpdateMoving = true;
|
||||||
* 根据图块数字获取渲染信息
|
|
||||||
* @param num 图块数字
|
|
||||||
*/
|
|
||||||
getRenderableByNum(num: number): LayerRenderableData | null {
|
|
||||||
const cell = this.cellSize;
|
|
||||||
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
|
|
||||||
const icons = icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1;
|
|
||||||
const auto = texture.autotile;
|
|
||||||
|
|
||||||
if (num >= 10000) {
|
|
||||||
// 额外素材
|
|
||||||
const offset = core.getTilesetOffset(num);
|
|
||||||
if (!offset) return null;
|
|
||||||
const { image, x, y } = offset;
|
|
||||||
return {
|
|
||||||
image: core.material.images.tilesets[image],
|
|
||||||
frame: 1,
|
|
||||||
render: [[x * cell, y * cell, cell, cell]]
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
if (num === 0 || num === 17) return null;
|
|
||||||
const { cls, id } = map[num as Exclude<AllNumbers, 0>];
|
|
||||||
// 普通素材
|
|
||||||
if (cls !== 'autotile') {
|
|
||||||
const image =
|
|
||||||
core.material.images[
|
|
||||||
cls as Exclude<Cls, 'tileset' | 'autotile'>
|
|
||||||
];
|
|
||||||
const frame = core.getAnimateFrames(cls);
|
|
||||||
// @ts-ignore
|
|
||||||
const offset = (icons[cls][id] as number) * cell;
|
|
||||||
const render: [number, number, number, number][] = [
|
|
||||||
[0, offset, cell, cell]
|
|
||||||
];
|
|
||||||
if (frame === 2) {
|
|
||||||
render.push([cell, offset, cell, cell]);
|
|
||||||
}
|
|
||||||
if (frame === 4) {
|
|
||||||
render.push(
|
|
||||||
[cell, offset, cell, cell],
|
|
||||||
[cell * 2, offset, cell, cell],
|
|
||||||
[cell * 3, offset, cell, cell]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
image,
|
|
||||||
frame,
|
|
||||||
render
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// 自动元件
|
|
||||||
const tile = auto[num as AllNumbersOf<'autotile'>];
|
|
||||||
const image = tile.cache[0b11111111];
|
|
||||||
const frame = tile.frame;
|
|
||||||
const render: [number, number, number, number][] = [
|
|
||||||
[0, 0, cell, cell]
|
|
||||||
];
|
|
||||||
if (frame === 4) {
|
|
||||||
render.push(
|
|
||||||
[cell, 0, cell, cell],
|
|
||||||
[cell * 2, 0, cell, cell],
|
|
||||||
[cell * 3, 0, cell, cell]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
image,
|
|
||||||
frame,
|
|
||||||
render
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据索引及横坐标获取对应的位置图块的渲染信息
|
|
||||||
* @param x 横坐标
|
|
||||||
* @param index 索引
|
|
||||||
*/
|
|
||||||
getRenderableData(
|
|
||||||
x: number,
|
|
||||||
_y: number,
|
|
||||||
index: number
|
|
||||||
): LayerRenderableData | LayerMovingRenderable | null {
|
|
||||||
const data = this.renderData;
|
|
||||||
const cell = this.cellSize;
|
|
||||||
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
|
|
||||||
const icons = icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1;
|
|
||||||
const auto = texture.autotile;
|
|
||||||
|
|
||||||
const bigImage = this.bigImage.get(index);
|
|
||||||
if (bigImage) {
|
|
||||||
// 对于大怪物
|
|
||||||
const img = bigImage.image;
|
|
||||||
const w = Math.round(img.width / 4);
|
|
||||||
const h = Math.round(img.height / bigImage.totalLines);
|
|
||||||
const y = h * bigImage.line;
|
|
||||||
return {
|
|
||||||
image: bigImage.image,
|
|
||||||
frame: 4,
|
|
||||||
render: [
|
|
||||||
[0, y, w, h],
|
|
||||||
[w, y, w, h],
|
|
||||||
[w * 2, y, w, h],
|
|
||||||
[w * 3, y, w, h]
|
|
||||||
],
|
|
||||||
x: x,
|
|
||||||
y: y,
|
|
||||||
zIndex: y
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// 对于普通图块
|
|
||||||
const num = data[index];
|
|
||||||
if (num >= 10000) {
|
|
||||||
// 额外素材
|
|
||||||
return this.getRenderableByNum(num);
|
|
||||||
} else {
|
|
||||||
if (num === 0 || num === 17) return null;
|
|
||||||
const { cls } = map[num as Exclude<AllNumbers, 0>];
|
|
||||||
// 普通素材
|
|
||||||
if (cls !== 'autotile') {
|
|
||||||
return this.getRenderableByNum(num);
|
|
||||||
} else {
|
|
||||||
// 自动元件
|
|
||||||
const tile = auto[num as AllNumbersOf<'autotile'>];
|
|
||||||
const link = this.autotiles[index];
|
|
||||||
const image = tile.cache[link];
|
|
||||||
const frame = tile.frame;
|
|
||||||
const render: [number, number, number, number][] = [
|
|
||||||
[0, 0, cell, cell]
|
|
||||||
];
|
|
||||||
if (frame === 4) {
|
|
||||||
render.push(
|
|
||||||
[cell, 0, cell, cell],
|
|
||||||
[cell * 2, 0, cell, cell],
|
|
||||||
[cell * 3, 0, cell, cell]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
image,
|
|
||||||
frame,
|
|
||||||
render
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新给定区域内的绘制信息
|
|
||||||
*/
|
|
||||||
updateRenderableData(x: number, y: number, width: number, height: number) {
|
|
||||||
const ex = Math.min(x + width, this.mapWidth);
|
|
||||||
const ey = Math.min(y + height, this.mapHeight);
|
|
||||||
const size = this.blockSize;
|
|
||||||
|
|
||||||
for (let nx = Math.max(x, 0); nx < ex; nx++) {
|
|
||||||
for (let ny = Math.max(y, 0); ny < ey; ny++) {
|
|
||||||
const index = ny * size + nx;
|
|
||||||
const bigImage = this.bigImage.get(index);
|
|
||||||
const data = this.getRenderableData(nx, ny, index);
|
|
||||||
if (!data) continue;
|
|
||||||
if (bigImage) {
|
|
||||||
this.movingRenderable.push(data as LayerMovingRenderable);
|
|
||||||
} else {
|
|
||||||
this.renderable.set(index, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -590,12 +361,11 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
|
|
||||||
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 > w) continue;
|
if (nx > w || ny > h) continue;
|
||||||
const index = nx + ny * h;
|
const index = nx + ny * w;
|
||||||
const num = data[index];
|
const num = data[index];
|
||||||
// 特判空气墙与空图块
|
// 特判空气墙与空图块
|
||||||
if (num === 17 || num >= 10000 || num <= 0) continue;
|
if (num === 0 || num === 17 || num >= 10000) continue;
|
||||||
console.log(this);
|
|
||||||
|
|
||||||
const info = map[num as Exclude<AllNumbers, 0>];
|
const info = map[num as Exclude<AllNumbers, 0>];
|
||||||
const { cls } = info;
|
const { cls } = info;
|
||||||
@ -683,8 +453,8 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
const size = this.blockSize;
|
const size = this.blockSize;
|
||||||
|
|
||||||
this.blockData = {
|
this.blockData = {
|
||||||
width: Math.floor(this.mapWidth / size),
|
width: Math.ceil(this.mapWidth / size),
|
||||||
height: Math.floor(this.mapHeight / size),
|
height: Math.ceil(this.mapHeight / size),
|
||||||
restWidth: this.mapWidth % size,
|
restWidth: this.mapWidth % size,
|
||||||
restHeight: this.mapHeight % size
|
restHeight: this.mapHeight % size
|
||||||
};
|
};
|
||||||
@ -808,21 +578,31 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
* @param camera 摄像机
|
* @param camera 摄像机
|
||||||
*/
|
*/
|
||||||
calNeedRender(camera: Camera): NeedRenderData {
|
calNeedRender(camera: Camera): NeedRenderData {
|
||||||
const w = core._WIDTH_;
|
|
||||||
const h = core._HEIGHT_;
|
|
||||||
const size = this.blockSize;
|
|
||||||
const { width } = this.blockData;
|
|
||||||
const cell = this.cellSize;
|
const cell = this.cellSize;
|
||||||
|
const w = (core._WIDTH_ * cell) / 2;
|
||||||
|
const h = (core._HEIGHT_ * cell) / 2;
|
||||||
|
const size = this.blockSize;
|
||||||
|
|
||||||
const [x1, y1] = Camera.transformed(camera, 0, 0);
|
// -1是因为宽度是core._PX_,从0开始的话,末尾索引就是core._PX_ - 1
|
||||||
const [x2, y2] = Camera.transformed(camera, w * cell, 0);
|
const [x1, y1] = Camera.untransformed(camera, -w, -h);
|
||||||
const [x3, y3] = Camera.transformed(camera, w * cell, h * cell);
|
const [x2, y2] = Camera.untransformed(camera, w - 1, -h);
|
||||||
const [x4, y4] = Camera.transformed(camera, 0, h * cell);
|
const [x3, y3] = Camera.untransformed(camera, w - 1, h - 1);
|
||||||
|
const [x4, y4] = Camera.untransformed(camera, -w, h - 1);
|
||||||
|
|
||||||
const res: Set<number> = new Set();
|
const res: Set<number> = new Set();
|
||||||
/** 一个纵坐标对应的所有横坐标,用于填充 */
|
/** 一个纵坐标对应的所有横坐标,用于填充 */
|
||||||
const xyMap: Map<number, number[]> = new Map();
|
const xyMap: Map<number, number[]> = new Map();
|
||||||
|
|
||||||
|
const pushXY = (x: number, y: number) => {
|
||||||
|
let arr = xyMap.get(y);
|
||||||
|
if (!arr) {
|
||||||
|
arr = [];
|
||||||
|
xyMap.set(y, arr);
|
||||||
|
}
|
||||||
|
arr.push(x);
|
||||||
|
return arr;
|
||||||
|
};
|
||||||
|
|
||||||
[
|
[
|
||||||
[x1, y1, x2, y2],
|
[x1, y1, x2, y2],
|
||||||
[x2, y2, x3, y3],
|
[x2, y2, x3, y3],
|
||||||
@ -837,43 +617,26 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
const dy = ty - fy;
|
const dy = ty - fy;
|
||||||
const k = dy / dx;
|
const k = dy / dx;
|
||||||
|
|
||||||
// console.log(fx, fy, tx, ty);
|
|
||||||
|
|
||||||
// 斜率无限的时候,竖直
|
// 斜率无限的时候,竖直
|
||||||
if (!isFinite(k)) {
|
if (!isFinite(k)) {
|
||||||
const min = k < 0 ? ty : fy;
|
const min = k < 0 ? ty : fy;
|
||||||
const max = k < 0 ? fy : ty;
|
const max = k < 0 ? fy : ty;
|
||||||
const [x, y] = this.getBlockXYByLoc(fx, min);
|
const [x, y] = this.getBlockXYByLoc(fx, min);
|
||||||
|
|
||||||
// 在地图左侧或右侧时,将每个纵坐标对应的横坐标填充为0
|
|
||||||
|
|
||||||
const p = x < 0 ? 0 : x >= width ? width - 1 : x;
|
|
||||||
const [, ey] = this.getBlockXYByLoc(fx, max);
|
const [, ey] = this.getBlockXYByLoc(fx, max);
|
||||||
for (let i = y; i <= ey; i++) {
|
for (let i = y; i <= ey; i++) {
|
||||||
let arr = xyMap.get(i);
|
pushXY(x, i);
|
||||||
if (!arr) {
|
|
||||||
arr = [];
|
|
||||||
xyMap.set(i, arr);
|
|
||||||
}
|
}
|
||||||
arr.push(p);
|
|
||||||
}
|
|
||||||
// console.log(y, ey, p);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [fbx, fby] = this.getBlockXYByLoc(fx, fy);
|
const [fbx, fby] = this.getBlockXYByLoc(fx, fy);
|
||||||
|
|
||||||
// 当斜率为0时
|
// 当斜率为0时
|
||||||
if (glMatrix.equals(k, 0)) {
|
if (glMatrix.equals(k, 0)) {
|
||||||
const [ex] = this.getBlockXYByLoc(tx, fy);
|
const [ex] = this.getBlockXYByLoc(tx, fy);
|
||||||
let arr = xyMap.get(fby);
|
pushXY(fby, fbx).push(ex);
|
||||||
if (!arr) {
|
|
||||||
arr = [];
|
|
||||||
xyMap.set(fby, arr);
|
|
||||||
}
|
|
||||||
arr.push(fbx, ex);
|
|
||||||
// console.log(fbx, ex);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,54 +644,52 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
if (Math.abs(k) >= 1) {
|
if (Math.abs(k) >= 1) {
|
||||||
// 斜率大于一,y方向递增
|
// 斜率大于一,y方向递增
|
||||||
const d = Math.sign(dy) * size;
|
const d = Math.sign(dy) * size;
|
||||||
const f = dx > 0 ? fby * size : (fby + 1) * size;
|
const f = fby * size;
|
||||||
const dir = dy > 0;
|
const dir = dy > 0;
|
||||||
|
|
||||||
|
const ex = Math.floor(tx / size);
|
||||||
|
const ey = Math.floor(ty / size);
|
||||||
|
pushXY(ex, ey);
|
||||||
|
|
||||||
let now = f;
|
let now = f;
|
||||||
let last = fbx;
|
let last = fbx;
|
||||||
let ny = fby;
|
let ny = fby;
|
||||||
do {
|
do {
|
||||||
const bx = Math.floor(fx + (now - fy) / k);
|
const bx = Math.floor((fx + (now - fy) / k) / size);
|
||||||
let arr = xyMap.get(ny);
|
pushXY(bx, ny);
|
||||||
if (!arr) {
|
|
||||||
arr = [];
|
|
||||||
xyMap.set(ny, arr);
|
|
||||||
}
|
|
||||||
if (bx !== last) {
|
if (bx !== last) {
|
||||||
arr.push(last);
|
if (dir) pushXY(bx, ny - Math.sign(dy));
|
||||||
|
else pushXY(last, ny);
|
||||||
}
|
}
|
||||||
arr.push(bx);
|
|
||||||
last = bx;
|
last = bx;
|
||||||
ny++;
|
ny += Math.sign(dy);
|
||||||
} while (dir ? (now += d) < ty : (now += d) > ty);
|
now += d;
|
||||||
|
} while (dir ? ny <= ey : ny >= ey);
|
||||||
} else {
|
} else {
|
||||||
// 斜率小于一,x方向递增
|
// 斜率小于一,x方向递增
|
||||||
const d = Math.sign(dx) * size;
|
const d = Math.sign(dx) * size;
|
||||||
const f = dx > 0 ? fbx * size : (fbx + 1) * size;
|
const f = fbx * size;
|
||||||
const dir = dx > 0;
|
const dir = dx > 0;
|
||||||
|
|
||||||
|
const ex = Math.floor(tx / size);
|
||||||
|
const ey = Math.floor(ty / size);
|
||||||
|
pushXY(ex, ey);
|
||||||
|
|
||||||
let now = f;
|
let now = f;
|
||||||
let last = fby;
|
let last = fby;
|
||||||
let nx = fbx;
|
let nx = fbx;
|
||||||
do {
|
do {
|
||||||
const by = Math.floor(fy + k * (now - fx));
|
const by = Math.floor((fy + k * (now - fx)) / size);
|
||||||
|
|
||||||
if (by !== last) {
|
if (by !== last) {
|
||||||
let arr = xyMap.get(last);
|
if (dir) pushXY(nx - Math.sign(dx), by);
|
||||||
if (!arr) {
|
else pushXY(nx, last);
|
||||||
arr = [];
|
|
||||||
xyMap.set(last, arr);
|
|
||||||
}
|
}
|
||||||
arr.push(nx);
|
pushXY(nx, by);
|
||||||
}
|
last = by;
|
||||||
let arr = xyMap.get(nx);
|
nx += Math.sign(dx);
|
||||||
if (!arr) {
|
now += d;
|
||||||
arr = [];
|
} while (dir ? nx <= ex : nx >= ex);
|
||||||
xyMap.set(by, arr);
|
|
||||||
}
|
|
||||||
arr.push(nx);
|
|
||||||
nx++;
|
|
||||||
} while (dir ? (now += d) < tx : (now += d) > tx);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -939,6 +700,7 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
if (x.length === 1) {
|
if (x.length === 1) {
|
||||||
const index = y * bw + x[0];
|
const index = y * bw + x[0];
|
||||||
|
|
||||||
|
if (!back.some(v => v[0] === x[0] && v[1] === y))
|
||||||
back.push([x[0], y]);
|
back.push([x[0], y]);
|
||||||
if (index < 0 || index >= bw * bh) return;
|
if (index < 0 || index >= bw * bh) return;
|
||||||
res.add(index);
|
res.add(index);
|
||||||
@ -949,17 +711,44 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
for (let i = min; i <= max; i++) {
|
for (let i = min; i <= max; i++) {
|
||||||
const index = y * bw + i;
|
const index = y * bw + i;
|
||||||
|
|
||||||
|
if (!back.some(v => v[0] === i && v[1] === y))
|
||||||
back.push([i, y]);
|
back.push([i, y]);
|
||||||
if (index < 0 || index >= bw * bh) continue;
|
if (index < 0 || index >= bw * bh) continue;
|
||||||
res.add(index);
|
res.add(index);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// console.log([...res], xyMap);
|
|
||||||
|
|
||||||
return { res, back };
|
return { res, back };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新移动层的渲染信息
|
||||||
|
*/
|
||||||
|
updateMovingRenderable() {
|
||||||
|
this.movingRenderable = [];
|
||||||
|
this.movingRenderable.push(...this.bigImages.values());
|
||||||
|
this.moving.forEach(v => {
|
||||||
|
if (!v.render.autotile) {
|
||||||
|
this.movingRenderable.push({
|
||||||
|
...v.render,
|
||||||
|
x: v.x,
|
||||||
|
y: v.y,
|
||||||
|
zIndex: v.nowZ
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.movingRenderable.push({
|
||||||
|
...v.render,
|
||||||
|
x: v.x,
|
||||||
|
y: v.y,
|
||||||
|
zIndex: v.nowZ,
|
||||||
|
image: v.render.image[0b00000000],
|
||||||
|
autotile: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.movingRenderable.sort((a, b) => a.zIndex - b.zIndex);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染当前地图
|
* 渲染当前地图
|
||||||
*/
|
*/
|
||||||
@ -968,6 +757,8 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
this.movingMap.clear();
|
this.movingMap.clear();
|
||||||
this.backMap.clear();
|
this.backMap.clear();
|
||||||
|
|
||||||
|
if (this.needUpdateMoving) this.updateMovingRenderable();
|
||||||
|
|
||||||
this.renderBack(camera, need);
|
this.renderBack(camera, need);
|
||||||
this.renderStatic(camera, need);
|
this.renderStatic(camera, need);
|
||||||
this.renderMoving(camera);
|
this.renderMoving(camera);
|
||||||
@ -981,10 +772,9 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
protected renderBack(camera: Camera, need: NeedRenderData) {
|
protected renderBack(camera: Camera, need: NeedRenderData) {
|
||||||
const cell = this.cellSize;
|
const cell = this.cellSize;
|
||||||
const frame = (RenderItem.animatedFrame % 4) + 1;
|
const frame = (RenderItem.animatedFrame % 4) + 1;
|
||||||
const { width } = this.blockData;
|
|
||||||
const blockSize = this.blockSize;
|
const blockSize = this.blockSize;
|
||||||
const { back } = need;
|
const { back } = need;
|
||||||
const { ctx, canvas } = this.backMap;
|
const { ctx } = this.backMap;
|
||||||
|
|
||||||
const mat = camera.mat;
|
const mat = camera.mat;
|
||||||
const a = mat[0];
|
const a = mat[0];
|
||||||
@ -1020,16 +810,14 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
*/
|
*/
|
||||||
protected renderStatic(camera: Camera, need: NeedRenderData) {
|
protected renderStatic(camera: Camera, need: NeedRenderData) {
|
||||||
const cell = this.cellSize;
|
const cell = this.cellSize;
|
||||||
const renderable = this.renderable;
|
|
||||||
const frame = (RenderItem.animatedFrame % 4) + 1;
|
const frame = (RenderItem.animatedFrame % 4) + 1;
|
||||||
const { width } = this.blockData;
|
const { width } = this.blockData;
|
||||||
const blockSize = this.blockSize;
|
const blockSize = this.blockSize;
|
||||||
const { ctx, canvas } = this.staticMap;
|
const { ctx } = this.staticMap;
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
const { res: render } = need;
|
const { res: render } = need;
|
||||||
// console.log(render);
|
|
||||||
const mat = camera.mat;
|
const mat = camera.mat;
|
||||||
const a = mat[0];
|
const a = mat[0];
|
||||||
const b = mat[1];
|
const b = mat[1];
|
||||||
@ -1061,8 +849,8 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ex = sx + blockSize;
|
const ex = Math.min(sx + blockSize, this.mapWidth);
|
||||||
const ey = sy + blockSize;
|
const ey = Math.min(sy + blockSize, this.mapHeight);
|
||||||
|
|
||||||
const temp = new MotaOffscreenCanvas2D();
|
const temp = new MotaOffscreenCanvas2D();
|
||||||
temp.setAntiAliasing(false);
|
temp.setAntiAliasing(false);
|
||||||
@ -1074,17 +862,28 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
for (let nx = sx; nx < ex; nx++) {
|
for (let nx = sx; nx < ex; nx++) {
|
||||||
for (let ny = sy; ny < ey; ny++) {
|
for (let ny = sy; ny < ey; ny++) {
|
||||||
const blockIndex = nx + ny * this.mapWidth;
|
const blockIndex = nx + ny * this.mapWidth;
|
||||||
const data = renderable.get(blockIndex);
|
const num = this.renderData[blockIndex];
|
||||||
if (!data) continue;
|
if (num === 0 || num === 17) continue;
|
||||||
|
const data = texture.getRenderable(num);
|
||||||
|
if (!data || data.bigImage) continue;
|
||||||
const f = frame % data.frame;
|
const f = frame % data.frame;
|
||||||
const i = frame === 4 && data.frame === 3 ? 1 : f;
|
const i =
|
||||||
const [sx, sy, w, h] = data.render[i];
|
data.animate === -1
|
||||||
const px = nx * cell;
|
? frame === 4 && data.frame === 3
|
||||||
const py = ny * cell;
|
? 1
|
||||||
const image = data.image;
|
: f
|
||||||
|
: data.animate;
|
||||||
temp.ctx.drawImage(image, sx, sy, w, h, px, py, w, h);
|
const [isx, isy, w, h] = data.render[i];
|
||||||
|
const px = (nx - sx) * cell;
|
||||||
|
const py = (ny - sy) * cell;
|
||||||
|
const { image, autotile } = data;
|
||||||
|
if (!autotile) {
|
||||||
|
temp.ctx.drawImage(image, isx, isy, w, h, px, py, w, h);
|
||||||
|
} else {
|
||||||
|
const link = this.autotiles[blockIndex];
|
||||||
|
const i = image[link];
|
||||||
|
temp.ctx.drawImage(i, isx, isy, w, h, px, py, w, h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.drawImage(
|
ctx.drawImage(
|
||||||
@ -1126,10 +925,6 @@ export class Layer extends Container implements IRenderDestroyable {
|
|||||||
const r =
|
const r =
|
||||||
Math.max(a, b, c, d) ** 2 * Math.max(core._PX_, core._PY_) * 2;
|
Math.max(a, b, c, d) ** 2 * Math.max(core._PX_, core._PY_) * 2;
|
||||||
|
|
||||||
this.movingRenderable.sort((a, b) => {
|
|
||||||
return a.zIndex - b.zIndex;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.movingRenderable.forEach(v => {
|
this.movingRenderable.forEach(v => {
|
||||||
const { x, y, image, frame: blockFrame, render } = v;
|
const { x, y, image, frame: blockFrame, render } = v;
|
||||||
const f = frame % 4;
|
const f = frame % 4;
|
||||||
|
@ -149,11 +149,11 @@ Mota.require('var', 'hook').once('reset', () => {
|
|||||||
const camera = render.camera;
|
const camera = render.camera;
|
||||||
render.mount();
|
render.mount();
|
||||||
|
|
||||||
layer.zIndex = 2;
|
layer.setZIndex(2);
|
||||||
bgLayer.zIndex = 1;
|
bgLayer.setZIndex(1);
|
||||||
render.appendChild([layer, bgLayer]);
|
render.appendChild([layer, bgLayer]);
|
||||||
layer.bindThis('event', true);
|
layer.bindThis('event');
|
||||||
bgLayer.bindThis('bg', true);
|
bgLayer.bindThis('bg');
|
||||||
bgLayer.setBackground(650);
|
bgLayer.setBackground(650);
|
||||||
|
|
||||||
const ani = new Animation();
|
const ani = new Animation();
|
||||||
@ -161,17 +161,35 @@ Mota.require('var', 'hook').once('reset', () => {
|
|||||||
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(240, 240);
|
camera.move(ani.x, ani.y);
|
||||||
|
camera.scale(ani.size);
|
||||||
render.update(render);
|
render.update(render);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
camera.rotate(Math.PI * 1.23);
|
||||||
|
camera.move(230, 380);
|
||||||
|
camera.scale(0.7);
|
||||||
|
render.update();
|
||||||
|
|
||||||
|
// sleep(2000).then(() => {
|
||||||
|
// render.update();
|
||||||
|
// });
|
||||||
|
|
||||||
sleep(1000).then(() => {
|
sleep(1000).then(() => {
|
||||||
ani.mode(hyper('sin', 'out')).time(100).absolute().rotate(30);
|
ani.mode(hyper('sin', 'out'))
|
||||||
|
.time(100)
|
||||||
|
.absolute()
|
||||||
|
.rotate(30)
|
||||||
|
.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).mode(hyper('tan', 'in-out')).rotate(3600);
|
ani.time(5000)
|
||||||
|
.mode(hyper('sin', 'in-out'))
|
||||||
|
.rotate(360)
|
||||||
|
.move(200, 480)
|
||||||
|
.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)
|
||||||
|
@ -25,6 +25,10 @@ export class Sprite extends RenderItem implements ICanvasCachedRenderItem {
|
|||||||
camera: Camera
|
camera: Camera
|
||||||
): void {
|
): void {
|
||||||
this.emit('beforeRender');
|
this.emit('beforeRender');
|
||||||
|
if (this.needUpdate) {
|
||||||
|
this.cache(this.writing);
|
||||||
|
this.needUpdate = false;
|
||||||
|
}
|
||||||
withCacheRender(this, canvas, ctx, camera, canvas => {
|
withCacheRender(this, canvas, ctx, camera, canvas => {
|
||||||
this.renderFn(canvas, camera);
|
this.renderFn(canvas, camera);
|
||||||
});
|
});
|
||||||
|
2
src/types/core.d.ts
vendored
2
src/types/core.d.ts
vendored
@ -1419,6 +1419,8 @@ interface MapDataOf<T extends keyof NumberToId> {
|
|||||||
bigImage?: ImageIds;
|
bigImage?: ImageIds;
|
||||||
|
|
||||||
faceIds?: Record<Dir, AllIds>;
|
faceIds?: Record<Dir, AllIds>;
|
||||||
|
|
||||||
|
animate?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user