HumanBreak/src/core/render/container.ts

127 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
import { Camera } from './camera';
import {
ICanvasCachedRenderItem,
IRenderChildable,
RenderItem,
RenderItemPosition,
withCacheRender
} from './item';
export class Container
extends RenderItem
implements ICanvasCachedRenderItem, IRenderChildable
{
children: RenderItem[] = [];
sortedChildren: RenderItem[] = [];
canvas: MotaOffscreenCanvas2D;
/** 是否启用缓存机制,对于特殊场景,内部已经包含了缓存机制,这时就不需要启用了 */
private readonly enableCache: boolean;
/**
* 创建一个容器,容器中可以包含其他渲染对象
* @param type 渲染模式absolute表示绝对位置static表示跟随摄像机移动只对顶层元素有效
* @param cache 是否启用缓存机制
*/
constructor(type: RenderItemPosition = 'static', cache: boolean = true) {
super();
this.canvas = new MotaOffscreenCanvas2D();
this.type = type;
this.canvas.withGameScale(true);
this.enableCache = cache;
}
private renderTo(canvas: MotaOffscreenCanvas2D, camera: Camera) {
const { ctx } = canvas;
this.sortedChildren.forEach(v => {
if (v.hidden) return;
ctx.save();
if (!v.antiAliasing) {
ctx.imageSmoothingEnabled = false;
} else {
ctx.imageSmoothingEnabled = true;
}
v.render(canvas, camera);
ctx.restore();
});
}
render(canvas: MotaOffscreenCanvas2D, camera: Camera): void {
this.emit('beforeRender');
if (this.needUpdate) {
this.cache(this.using);
this.needUpdate = false;
}
if (this.enableCache) {
withCacheRender(this, canvas.canvas, canvas.ctx, camera, c => {
this.renderTo(c, camera);
});
} else {
this.renderTo(canvas, camera);
}
this.writing = void 0;
this.emit('afterRender');
}
size(width: number, height: number) {
this.width = width;
this.height = height;
this.canvas.size(width, height);
this.writing = this.using;
this.update(this);
}
pos(x: number, y: number) {
this.x = x;
this.y = y;
}
/**
* 添加子元素到这个容器上然后在下一个tick执行更新
* @param children 要添加的子元素
*/
appendChild(...children: RenderItem[]) {
children.forEach(v => (v.parent = this));
this.children.push(...children);
this.sortChildren();
this.update(this);
}
removeChild(...child: RenderItem[]): void {
child.forEach(v => {
const index = this.children.indexOf(v);
if (index === -1) return;
this.children.splice(index, 1);
});
this.sortChildren();
this.update(this);
}
sortChildren() {
this.sortedChildren = this.children
.slice()
.sort((a, b) => a.zIndex - b.zIndex);
}
setHD(hd: boolean): void {
this.highResolution = hd;
this.canvas.setHD(hd);
this.update(this);
}
setAntiAliasing(anti: boolean): void {
this.antiAliasing = anti;
this.canvas.setAntiAliasing(anti);
this.update(this);
}
destroy(): void {
super.destroy();
this.children.forEach(v => {
v.destroy();
});
}
}