mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-11-27 22:03:00 +08:00
feat: 地图渲染动画效果
This commit is contained in:
parent
ebaa35ea5b
commit
a5ecc45d9b
@ -44,6 +44,8 @@ export class MapRender extends RenderItem {
|
|||||||
this.renderer.setCellSize(CELL_WIDTH, CELL_HEIGHT);
|
this.renderer.setCellSize(CELL_WIDTH, CELL_HEIGHT);
|
||||||
this.renderer.setRenderSize(MAP_WIDTH, MAP_HEIGHT);
|
this.renderer.setRenderSize(MAP_WIDTH, MAP_HEIGHT);
|
||||||
|
|
||||||
|
this.delegateTicker(time => this.renderer.tick(time));
|
||||||
|
|
||||||
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,8 +75,6 @@ export class MapRender extends RenderItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected render(canvas: MotaOffscreenCanvas2D): void {
|
protected render(canvas: MotaOffscreenCanvas2D): void {
|
||||||
console.log('----- render start -----');
|
|
||||||
|
|
||||||
console.time('map-element-render');
|
console.time('map-element-render');
|
||||||
this.renderer.render(this.gl);
|
this.renderer.render(this.gl);
|
||||||
|
|
||||||
|
|||||||
@ -315,10 +315,8 @@ export class MapRenderer
|
|||||||
return a.zIndex - b.zIndex;
|
return a.zIndex - b.zIndex;
|
||||||
});
|
});
|
||||||
this.sortedLayers.forEach((v, i) => this.layerIndexMap.set(v, i));
|
this.sortedLayers.forEach((v, i) => this.layerIndexMap.set(v, i));
|
||||||
this.forEachHook((hook, controller) => {
|
|
||||||
hook.onUpdate?.(controller);
|
|
||||||
});
|
|
||||||
this.layerListDirty = true;
|
this.layerListDirty = true;
|
||||||
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateAllLayers() {
|
private updateAllLayers() {
|
||||||
@ -381,6 +379,7 @@ export class MapRenderer
|
|||||||
this.contextData.backgroundHeight
|
this.contextData.backgroundHeight
|
||||||
);
|
);
|
||||||
this.layerAllDirty = true;
|
this.layerAllDirty = true;
|
||||||
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
@ -421,19 +420,25 @@ export class MapRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
configBackground(config: Partial<IMapBackgroundConfig>): void {
|
configBackground(config: Partial<IMapBackgroundConfig>): void {
|
||||||
|
let needUpdate = false;
|
||||||
if (!isNil(config.renderWidth)) {
|
if (!isNil(config.renderWidth)) {
|
||||||
|
needUpdate = true;
|
||||||
this.backRenderWidth = config.renderWidth;
|
this.backRenderWidth = config.renderWidth;
|
||||||
}
|
}
|
||||||
if (!isNil(config.renderHeight)) {
|
if (!isNil(config.renderHeight)) {
|
||||||
|
needUpdate = true;
|
||||||
this.backRenderHeight = config.renderHeight;
|
this.backRenderHeight = config.renderHeight;
|
||||||
}
|
}
|
||||||
if (!isNil(config.repeatX)) {
|
if (!isNil(config.repeatX)) {
|
||||||
|
needUpdate = true;
|
||||||
this.backRepeatModeX = config.repeatX;
|
this.backRepeatModeX = config.repeatX;
|
||||||
}
|
}
|
||||||
if (!isNil(config.repeatY)) {
|
if (!isNil(config.repeatY)) {
|
||||||
|
needUpdate = true;
|
||||||
this.backRepeatModeY = config.repeatY;
|
this.backRepeatModeY = config.repeatY;
|
||||||
}
|
}
|
||||||
if (!isNil(config.useImageSize)) {
|
if (!isNil(config.useImageSize)) {
|
||||||
|
needUpdate = true;
|
||||||
this.backUseImageSize = config.useImageSize;
|
this.backUseImageSize = config.useImageSize;
|
||||||
}
|
}
|
||||||
if (!isNil(config.frameSpeed)) {
|
if (!isNil(config.frameSpeed)) {
|
||||||
@ -445,6 +450,9 @@ export class MapRenderer
|
|||||||
this.contextData.backgroundWidth,
|
this.contextData.backgroundWidth,
|
||||||
this.contextData.backgroundHeight
|
this.contextData.backgroundHeight
|
||||||
);
|
);
|
||||||
|
if (needUpdate) {
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getBackgroundConfig(): Readonly<IMapBackgroundConfig> {
|
getBackgroundConfig(): Readonly<IMapBackgroundConfig> {
|
||||||
@ -475,6 +483,7 @@ export class MapRenderer
|
|||||||
this.sortedLayers.forEach(v => {
|
this.sortedLayers.forEach(v => {
|
||||||
this.vertex.updateArea(v, 0, 0, this.mapWidth, this.mapHeight);
|
this.vertex.updateArea(v, 0, 0, this.mapWidth, this.mapHeight);
|
||||||
});
|
});
|
||||||
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
setCellSize(width: number, height: number): void {
|
setCellSize(width: number, height: number): void {
|
||||||
@ -483,6 +492,7 @@ export class MapRenderer
|
|||||||
this.sortedLayers.forEach(v => {
|
this.sortedLayers.forEach(v => {
|
||||||
this.vertex.updateArea(v, 0, 0, this.mapWidth, this.mapHeight);
|
this.vertex.updateArea(v, 0, 0, this.mapWidth, this.mapHeight);
|
||||||
});
|
});
|
||||||
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
configRendering(config: Partial<IMapRenderConfig>): void {
|
configRendering(config: Partial<IMapRenderConfig>): void {
|
||||||
@ -511,9 +521,7 @@ export class MapRenderer
|
|||||||
this.frameSpeed = config.frameSpeed;
|
this.frameSpeed = config.frameSpeed;
|
||||||
}
|
}
|
||||||
if (needUpdate) {
|
if (needUpdate) {
|
||||||
this.sortedLayers.forEach(v => {
|
this.requestUpdate();
|
||||||
this.vertex.updateArea(v, 0, 0, this.mapWidth, this.mapHeight);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1188,9 +1196,7 @@ export class MapRenderer
|
|||||||
);
|
);
|
||||||
this.backgroundPending = false;
|
this.backgroundPending = false;
|
||||||
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
||||||
this.forEachHook((hook, controller) => {
|
this.requestUpdate();
|
||||||
hook.onUpdate?.(controller);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): void {
|
render(): void {
|
||||||
@ -1200,7 +1206,6 @@ export class MapRenderer
|
|||||||
logger.error(31);
|
logger.error(31);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.time('render-map');
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
backVAO,
|
backVAO,
|
||||||
@ -1221,7 +1226,6 @@ export class MapRenderer
|
|||||||
insTexDataAttribLocation: texData
|
insTexDataAttribLocation: texData
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
console.time('layer-check');
|
|
||||||
// 图层检查
|
// 图层检查
|
||||||
if (this.layerSizeDirty) {
|
if (this.layerSizeDirty) {
|
||||||
this.vertex.resizeMap();
|
this.vertex.resizeMap();
|
||||||
@ -1236,28 +1240,18 @@ export class MapRenderer
|
|||||||
this.layerAllDirty = false;
|
this.layerAllDirty = false;
|
||||||
}
|
}
|
||||||
this.vertex.checkRebuild();
|
this.vertex.checkRebuild();
|
||||||
console.timeEnd('layer-check');
|
|
||||||
|
|
||||||
console.time('texture-check');
|
|
||||||
|
|
||||||
// 数据检查
|
// 数据检查
|
||||||
this.checkTexture(gl, data);
|
this.checkTexture(gl, data);
|
||||||
this.checkTileVertexArray(gl, data);
|
this.checkTileVertexArray(gl, data);
|
||||||
|
|
||||||
console.timeEnd('texture-check');
|
|
||||||
|
|
||||||
console.time('update-block-cache');
|
|
||||||
|
|
||||||
const area = this.viewport.getRenderArea();
|
const area = this.viewport.getRenderArea();
|
||||||
area.blockList.forEach(v => {
|
area.blockList.forEach(v => {
|
||||||
this.vertex.updateBlockCache(v);
|
this.vertex.updateBlockCache(v);
|
||||||
v.data.render();
|
v.data.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
console.timeEnd('update-block-cache');
|
|
||||||
|
|
||||||
if (area.dirty.length > 0) {
|
if (area.dirty.length > 0) {
|
||||||
console.time('upload-block-buffer');
|
|
||||||
// 如果需要更新顶点数组...
|
// 如果需要更新顶点数组...
|
||||||
const array = this.vertex.getVertexArray();
|
const array = this.vertex.getVertexArray();
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, instancedBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, instancedBuffer);
|
||||||
@ -1272,11 +1266,9 @@ export class MapRenderer
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||||
console.timeEnd('upload-block-buffer');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 背景
|
// 背景
|
||||||
console.time('render-call');
|
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||||
gl.useProgram(backProgram);
|
gl.useProgram(backProgram);
|
||||||
if (this.needUpdateBackgroundFrame) {
|
if (this.needUpdateBackgroundFrame) {
|
||||||
@ -1333,8 +1325,6 @@ export class MapRenderer
|
|||||||
});
|
});
|
||||||
gl.bindVertexArray(null);
|
gl.bindVertexArray(null);
|
||||||
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
gl.bindTexture(gl.TEXTURE_2D_ARRAY, null);
|
||||||
console.timeEnd('render-call');
|
|
||||||
console.timeEnd('render-map');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
@ -1357,9 +1347,7 @@ export class MapRenderer
|
|||||||
h: number
|
h: number
|
||||||
) {
|
) {
|
||||||
this.vertex.updateArea(layer, x, y, w, h);
|
this.vertex.updateArea(layer, x, y, w, h);
|
||||||
this.forEachHook((hook, controller) => {
|
this.requestUpdate();
|
||||||
hook.onUpdate?.(controller);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1371,9 +1359,7 @@ export class MapRenderer
|
|||||||
*/
|
*/
|
||||||
updateLayerBlock(layer: IMapLayer, block: number, x: number, y: number) {
|
updateLayerBlock(layer: IMapLayer, block: number, x: number, y: number) {
|
||||||
this.vertex.updateBlock(layer, block, x, y);
|
this.vertex.updateBlock(layer, block, x, y);
|
||||||
this.forEachHook((hook, controller) => {
|
this.requestUpdate();
|
||||||
hook.onUpdate?.(controller);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
@ -1414,6 +1400,7 @@ export class MapRenderer
|
|||||||
map.set(v, item);
|
map.set(v, item);
|
||||||
});
|
});
|
||||||
this.vertex.reduceMoving(half, map);
|
this.vertex.reduceMoving(half, map);
|
||||||
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1453,6 +1440,7 @@ export class MapRenderer
|
|||||||
this.movingBlock.add(moving);
|
this.movingBlock.add(moving);
|
||||||
this.movingIndexMap.set(index, moving);
|
this.movingIndexMap.set(index, moving);
|
||||||
this.vertex.updateMoving(moving, true);
|
this.vertex.updateMoving(moving, true);
|
||||||
|
this.requestUpdate();
|
||||||
return moving;
|
return moving;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1469,6 +1457,7 @@ export class MapRenderer
|
|||||||
this.movingBlock.delete(block);
|
this.movingBlock.delete(block);
|
||||||
this.movingIndexMap.delete(block.index);
|
this.movingIndexMap.delete(block.index);
|
||||||
this.vertex.deleteMoving(block);
|
this.vertex.deleteMoving(block);
|
||||||
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
hasMoving(moving: IMovingBlock): boolean {
|
hasMoving(moving: IMovingBlock): boolean {
|
||||||
@ -1495,18 +1484,26 @@ export class MapRenderer
|
|||||||
|
|
||||||
//#region 其他方法
|
//#region 其他方法
|
||||||
|
|
||||||
|
private requestUpdate() {
|
||||||
|
this.forEachHook((hook, controller) => {
|
||||||
|
hook.onUpdate?.(controller);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getTimestamp(): number {
|
getTimestamp(): number {
|
||||||
return this.timestamp;
|
return this.timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
tick(timestamp: number) {
|
tick(timestamp: number) {
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
|
let update = false;
|
||||||
|
|
||||||
// 移动数组
|
// 移动数组
|
||||||
const expandDT = timestamp - this.lastExpandTime;
|
const expandDT = timestamp - this.lastExpandTime;
|
||||||
if (expandDT > MOVING_TOLERANCE * 1000) {
|
if (expandDT > MOVING_TOLERANCE * 1000) {
|
||||||
this.reduceMoving();
|
this.reduceMoving();
|
||||||
this.lastExpandTime = timestamp;
|
this.lastExpandTime = timestamp;
|
||||||
|
update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 背景
|
// 背景
|
||||||
@ -1516,13 +1513,16 @@ export class MapRenderer
|
|||||||
this.backgroundFrame %= this.backgroundFrameCount;
|
this.backgroundFrame %= this.backgroundFrameCount;
|
||||||
this.backLastFrame = timestamp;
|
this.backLastFrame = timestamp;
|
||||||
this.needUpdateBackgroundFrame = true;
|
this.needUpdateBackgroundFrame = true;
|
||||||
|
update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 地图帧动画
|
// 地图帧动画
|
||||||
const frameDT = timestamp - this.lastFrameTime;
|
const frameDT = timestamp - this.lastFrameTime;
|
||||||
if (frameDT > this.frameSpeed) {
|
if (frameDT > this.frameSpeed) {
|
||||||
|
this.lastFrameTime = timestamp;
|
||||||
this.frameCounter++;
|
this.frameCounter++;
|
||||||
this.needUpdateFrameCounter = true;
|
this.needUpdateFrameCounter = true;
|
||||||
|
update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 图块移动
|
// 图块移动
|
||||||
@ -1533,14 +1533,17 @@ export class MapRenderer
|
|||||||
if (move) toUpdate.push(v);
|
if (move) toUpdate.push(v);
|
||||||
});
|
});
|
||||||
this.vertex.updateMovingList(toUpdate, false);
|
this.vertex.updateMovingList(toUpdate, false);
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTransform(): void {
|
updateTransform(): void {
|
||||||
this.needUpdateTransform = true;
|
this.needUpdateTransform = true;
|
||||||
this.forEachHook((hook, controller) => {
|
this.requestUpdate();
|
||||||
hook.onUpdate?.(controller);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|||||||
@ -426,6 +426,12 @@ export interface IMapRenderer extends IHookable<IMapRendererHooks> {
|
|||||||
* @param y 图块纵坐标
|
* @param y 图块纵坐标
|
||||||
*/
|
*/
|
||||||
setTileAlpha(layer: IMapLayer, alpha: number, x: number, y: number): void;
|
setTileAlpha(layer: IMapLayer, alpha: number, x: number, y: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进行一帧更新
|
||||||
|
* @param timestamp 时间戳
|
||||||
|
*/
|
||||||
|
tick(timestamp: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapVertexArray {
|
export interface IMapVertexArray {
|
||||||
|
|||||||
@ -59,45 +59,29 @@ export class MapViewport implements IMapViewportController {
|
|||||||
if (widthOne && heightOne) {
|
if (widthOne && heightOne) {
|
||||||
// 只能看到一个分块
|
// 只能看到一个分块
|
||||||
const block = this.vertex.block.getBlockByLoc(blockLeft, blockTop)!;
|
const block = this.vertex.block.getBlockByLoc(blockLeft, blockTop)!;
|
||||||
if (block.data.dirty || block.data.renderDirty) {
|
|
||||||
blockList.push(block);
|
blockList.push(block);
|
||||||
}
|
|
||||||
} else if (widthOne) {
|
} else if (widthOne) {
|
||||||
// 看到的区域分块宽度是 1
|
// 看到的区域分块宽度是 1
|
||||||
for (let ny = blockTop; ny <= blockBottom; ny++) {
|
for (let ny = blockTop; ny <= blockBottom; ny++) {
|
||||||
const block = this.vertex.block.getBlockByLoc(blockLeft, ny)!;
|
const block = this.vertex.block.getBlockByLoc(blockLeft, ny)!;
|
||||||
if (block.data.dirty || block.data.renderDirty) {
|
|
||||||
blockList.push(block);
|
blockList.push(block);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (heightOne) {
|
} else if (heightOne) {
|
||||||
// 看到的区域分块高度是 1
|
// 看到的区域分块高度是 1
|
||||||
for (let nx = blockLeft; nx <= blockRight; nx++) {
|
for (let nx = blockLeft; nx <= blockRight; nx++) {
|
||||||
const block = this.vertex.block.getBlockByLoc(nx, blockTop)!;
|
const block = this.vertex.block.getBlockByLoc(nx, blockTop)!;
|
||||||
if (block.data.dirty || block.data.renderDirty) {
|
|
||||||
blockList.push(block);
|
blockList.push(block);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// 看到的区域分块宽高都不是 1
|
// 看到的区域分块宽高都不是 1
|
||||||
// 使用这种方式的话,索引在换行之前都是连续的,方便整合
|
// 使用这种方式的话,索引在换行之前都是连续的,方便整合
|
||||||
for (let ny = blockTop; ny <= blockBottom; ny++) {
|
for (let ny = blockTop; ny <= blockBottom; ny++) {
|
||||||
const first = this.vertex.block.getBlockByLoc(blockLeft, ny)!;
|
for (let nx = blockLeft; nx <= blockRight; nx++) {
|
||||||
const last = this.vertex.block.getBlockByLoc(blockRight, ny)!;
|
|
||||||
if (first.data.dirty) {
|
|
||||||
blockList.push(first);
|
|
||||||
}
|
|
||||||
if (last.data.dirty && first !== last) {
|
|
||||||
blockList.push(last);
|
|
||||||
}
|
|
||||||
for (let nx = blockLeft + 1; nx < blockRight; nx++) {
|
|
||||||
const block = this.vertex.block.getBlockByLoc(nx, ny)!;
|
const block = this.vertex.block.getBlockByLoc(nx, ny)!;
|
||||||
if (block.data.dirty) {
|
|
||||||
blockList.push(block);
|
blockList.push(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (blockList.length > 0) {
|
if (blockList.length > 0) {
|
||||||
if (blockList.length === 1) {
|
if (blockList.length === 1) {
|
||||||
@ -143,7 +127,7 @@ export class MapViewport implements IMapViewportController {
|
|||||||
return {
|
return {
|
||||||
render: renderArea,
|
render: renderArea,
|
||||||
dirty: updateArea,
|
dirty: updateArea,
|
||||||
blockList
|
blockList: blockList.filter(v => v.data.dirty)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user