mirror of
https://github.com/unanmed/HumanBreak.git
synced 2026-11-01 07:24:30 +08:00
refactor: 换用新的缩放方案
This commit is contained in:
1 parent
a3115fff60
commit
e4a6a136ed
39 files changed
+239
-345
No files matched your search
@@ -1,5 +1,4 @@
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { logger } from '@motajs/common';
|
||||
|
||||
interface OffscreenCanvasEvent {
|
||||
/** 当被动触发resize时(例如core.domStyle.scale变化、窗口大小变化)时触发,使用size函数并不会触发 */
|
||||
@@ -7,16 +6,12 @@ interface OffscreenCanvasEvent {
|
||||
}
|
||||
|
||||
export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
||||
static list: Set<MotaOffscreenCanvas2D> = new Set();
|
||||
|
||||
canvas: HTMLCanvasElement;
|
||||
ctx: CanvasRenderingContext2D;
|
||||
|
||||
width: number;
|
||||
height: number;
|
||||
|
||||
/** 是否自动跟随样板的core.domStyle.scale进行缩放 */
|
||||
autoScale: boolean = false;
|
||||
/** 是否是高清画布 */
|
||||
highResolution: boolean = true;
|
||||
/** 是否启用抗锯齿 */
|
||||
@@ -27,12 +22,6 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
||||
/** 更新标识符,如果发生变化则说明画布被动清空 */
|
||||
symbol: number = 0;
|
||||
|
||||
private _freezed: boolean = false;
|
||||
/** 当前画布是否被冻结 */
|
||||
get freezed() {
|
||||
return this._freezed;
|
||||
}
|
||||
|
||||
private _active: boolean = true;
|
||||
get active() {
|
||||
return this._active;
|
||||
@@ -46,65 +35,52 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
||||
*/
|
||||
constructor(alpha: boolean = true, canvas?: HTMLCanvasElement) {
|
||||
super();
|
||||
// console.trace();
|
||||
|
||||
this.canvas = canvas ?? document.createElement('canvas');
|
||||
this.ctx = this.canvas.getContext('2d', { alpha })!;
|
||||
this.width = this.canvas.width / devicePixelRatio;
|
||||
this.height = this.canvas.height / devicePixelRatio;
|
||||
}
|
||||
|
||||
MotaOffscreenCanvas2D.list.add(this);
|
||||
/**
|
||||
* 设置画布的缩放比
|
||||
* @param scale 缩放比
|
||||
*/
|
||||
setScale(scale: number) {
|
||||
if (scale === this.scale) {
|
||||
this.clear();
|
||||
return;
|
||||
}
|
||||
this.scale = scale;
|
||||
let ratio = this.highResolution ? devicePixelRatio : 1;
|
||||
ratio *= this.scale;
|
||||
this.canvas.width = this.width * ratio;
|
||||
this.canvas.height = this.height * ratio;
|
||||
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
this.ctx.scale(ratio, ratio);
|
||||
this.ctx.imageSmoothingEnabled = this.antiAliasing;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置画布的大小
|
||||
*/
|
||||
size(width: number, height: number) {
|
||||
if (this._freezed) {
|
||||
logger.warn(33);
|
||||
return;
|
||||
}
|
||||
const w = Math.max(width, 1);
|
||||
const h = Math.max(height, 1);
|
||||
let ratio = this.highResolution ? devicePixelRatio : 1;
|
||||
const scale = core.domStyle.scale;
|
||||
if (this.autoScale) {
|
||||
ratio *= scale;
|
||||
}
|
||||
this.scale = ratio;
|
||||
ratio *= this.scale;
|
||||
this.canvas.width = w * ratio;
|
||||
this.canvas.height = h * ratio;
|
||||
this.width = w;
|
||||
this.height = height;
|
||||
this.height = h;
|
||||
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
this.ctx.scale(ratio, ratio);
|
||||
this.ctx.imageSmoothingEnabled = this.antiAliasing;
|
||||
if (this.canvas.isConnected) {
|
||||
this.canvas.style.width = `${w * scale}px`;
|
||||
this.canvas.style.height = `${h * scale}px`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前画布是否跟随样板的 core.domStyle.scale 一同进行缩放
|
||||
*/
|
||||
withGameScale(auto: boolean) {
|
||||
if (this._freezed) {
|
||||
logger.warn(33);
|
||||
return;
|
||||
}
|
||||
this.autoScale = auto;
|
||||
this.size(this.width, this.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前画布是否为高清画布
|
||||
*/
|
||||
setHD(hd: boolean) {
|
||||
if (this._freezed) {
|
||||
logger.warn(33);
|
||||
return;
|
||||
}
|
||||
this.highResolution = hd;
|
||||
this.size(this.width, this.height);
|
||||
}
|
||||
@@ -113,10 +89,6 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
||||
* 设置当前画布的抗锯齿设置
|
||||
*/
|
||||
setAntiAliasing(anti: boolean) {
|
||||
if (this._freezed) {
|
||||
logger.warn(33);
|
||||
return;
|
||||
}
|
||||
this.antiAliasing = anti;
|
||||
this.ctx.imageSmoothingEnabled = anti;
|
||||
}
|
||||
@@ -125,56 +97,12 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
||||
* 清空画布
|
||||
*/
|
||||
clear() {
|
||||
if (this._freezed) {
|
||||
logger.warn(33);
|
||||
return;
|
||||
}
|
||||
this.ctx.save();
|
||||
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
this.ctx.restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除这个画布
|
||||
*/
|
||||
delete() {
|
||||
this.canvas.remove();
|
||||
this.ctx.reset();
|
||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
this._freezed = true;
|
||||
MotaOffscreenCanvas2D.list.delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 冻结这个画布的属性,之后便不能被修改,同时会从画布列表中删去。
|
||||
*/
|
||||
freeze() {
|
||||
this._freezed = true;
|
||||
MotaOffscreenCanvas2D.list.delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使此画布生效,使用前请务必调用此函数,生效后会跟随游戏的放缩比例更改大小,但会导致不会被垃圾回收
|
||||
*/
|
||||
activate() {
|
||||
if (this._active || this._freezed) return;
|
||||
MotaOffscreenCanvas2D.list.add(this);
|
||||
if (this.autoScale) {
|
||||
this.size(this.width, this.height);
|
||||
this.symbol++;
|
||||
this.emit('resize');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使此画布失效,当这个画布暂时不会被使用时请务必调用此函数,失效后若没有对此画布的引用,那么会自动垃圾回收
|
||||
*/
|
||||
deactivate() {
|
||||
if (!this._active || this._freezed) return;
|
||||
MotaOffscreenCanvas2D.list.delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制一个离屏Canvas2D对象,一般用于缓存等操作
|
||||
* @param canvas 被复制的MotaOffscreenCanvas2D对象
|
||||
@@ -183,7 +111,6 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
||||
static clone(canvas: MotaOffscreenCanvas2D): MotaOffscreenCanvas2D {
|
||||
const newCanvas = new MotaOffscreenCanvas2D();
|
||||
newCanvas.setHD(canvas.highResolution);
|
||||
newCanvas.withGameScale(canvas.autoScale);
|
||||
newCanvas.size(canvas.width, canvas.height);
|
||||
newCanvas.ctx.drawImage(
|
||||
canvas.canvas,
|
||||
@@ -192,23 +119,6 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
||||
canvas.width,
|
||||
canvas.height
|
||||
);
|
||||
newCanvas.freeze();
|
||||
return newCanvas;
|
||||
}
|
||||
|
||||
static refreshAll(force: boolean = false) {
|
||||
this.list.forEach(v => {
|
||||
if (force || v.autoScale) {
|
||||
v.size(v.width, v.height);
|
||||
v.symbol++;
|
||||
v.emit('resize');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
requestAnimationFrame(() => {
|
||||
MotaOffscreenCanvas2D.refreshAll();
|
||||
});
|
||||
});
|
||||
@@ -42,6 +42,11 @@ export class Container<E extends EContainerEvent = EContainerEvent>
|
||||
});
|
||||
}
|
||||
|
||||
onResize(scale: number): void {
|
||||
this.sortedChildren.forEach(v => v.onResize(scale));
|
||||
super.onResize(scale);
|
||||
}
|
||||
|
||||
requestSort() {
|
||||
if (!this.needSort) {
|
||||
this.needSort = true;
|
||||
|
||||
@@ -184,6 +184,11 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
|
||||
this.init();
|
||||
}
|
||||
|
||||
onResize(scale: number): void {
|
||||
this.sizeGL(this.width, this.height);
|
||||
super.onResize(scale);
|
||||
}
|
||||
|
||||
setHD(hd: boolean): void {
|
||||
super.setHD(hd);
|
||||
this.sizeGL(this.width, this.height);
|
||||
@@ -196,7 +201,7 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
|
||||
|
||||
private sizeGL(width: number, height: number) {
|
||||
const ratio = this.highResolution ? devicePixelRatio : 1;
|
||||
const scale = ratio * core.domStyle.scale;
|
||||
const scale = ratio * this.cache.scale;
|
||||
this.canvas.width = width * scale;
|
||||
this.canvas.height = height * scale;
|
||||
}
|
||||
|
||||
@@ -132,6 +132,14 @@ export interface IRenderTickerSupport {
|
||||
hasTicker(id: number): boolean;
|
||||
}
|
||||
|
||||
export interface IRenderEvent {
|
||||
/**
|
||||
* 当触发缩放事件时,此函数执行的内容
|
||||
* @param scale 缩放至的缩放比
|
||||
*/
|
||||
onResize(scale: number): void;
|
||||
}
|
||||
|
||||
export interface IRenderVueSupport {
|
||||
/**
|
||||
* 在 jsx, vue 中当属性改变后触发此函数,用于处理响应式等情况
|
||||
@@ -185,6 +193,10 @@ export interface IRenderTreeRoot {
|
||||
hoverElement(element: RenderItem): void;
|
||||
}
|
||||
|
||||
interface RenderItemCanvasData {
|
||||
autoScale: boolean;
|
||||
}
|
||||
|
||||
export interface ERenderItemEvent extends ERenderItemActionEvent {
|
||||
beforeRender: [transform: Transform];
|
||||
afterRender: [transform: Transform];
|
||||
@@ -213,7 +225,8 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
||||
IRenderTickerSupport,
|
||||
IRenderChildable,
|
||||
IRenderVueSupport,
|
||||
ITransformUpdatable
|
||||
ITransformUpdatable,
|
||||
IRenderEvent
|
||||
{
|
||||
/** 渲染的全局ticker */
|
||||
static ticker: Ticker = new Ticker();
|
||||
@@ -332,6 +345,11 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
||||
readonly transformFallThrough: boolean = false;
|
||||
/** 这个渲染元素使用到的所有画布 */
|
||||
protected readonly canvases: Set<MotaOffscreenCanvas2D> = new Set();
|
||||
/** 这个渲染元素每个画布的配置信息 */
|
||||
private readonly canvasMap: Map<
|
||||
MotaOffscreenCanvas2D,
|
||||
RenderItemCanvasData
|
||||
> = new Map();
|
||||
//#endregion
|
||||
|
||||
//#region 交互事件
|
||||
@@ -371,11 +389,8 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
||||
|
||||
this._transform.bind(this);
|
||||
this.cache = this.requireCanvas();
|
||||
this.cache.withGameScale(true);
|
||||
if (!enableCache) {
|
||||
this.cache.withGameScale(false);
|
||||
this.cache.size(1, 1);
|
||||
this.cache.freeze();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,10 +454,12 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
||||
/**
|
||||
* 申请一个 `MotaOffscreenCanvas2D`,即申请一个画布
|
||||
* @param alpha 是否启用画布的 alpha 通道
|
||||
* @param autoScale 是否自动跟随缩放
|
||||
*/
|
||||
protected requireCanvas(alpha: boolean = true) {
|
||||
requireCanvas(alpha: boolean = true, autoScale: boolean = false) {
|
||||
const canvas = new MotaOffscreenCanvas2D(alpha);
|
||||
this.canvases.add(canvas);
|
||||
this.canvasMap.set(canvas, { autoScale });
|
||||
return canvas;
|
||||
}
|
||||
|
||||
@@ -450,9 +467,20 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
||||
* 删除由 `requireCanvas` 申请的画布,当画布不再使用时,可以用该方法删除画布
|
||||
* @param canvas 要删除的画布
|
||||
*/
|
||||
protected deleteCanvas(canvas: MotaOffscreenCanvas2D) {
|
||||
if (!this.canvases.delete(canvas)) return;
|
||||
canvas.delete();
|
||||
deleteCanvas(canvas: MotaOffscreenCanvas2D) {
|
||||
this.canvases.delete(canvas);
|
||||
this.canvasMap.delete(canvas);
|
||||
}
|
||||
|
||||
//#region 事件处理
|
||||
|
||||
onResize(scale: number): void {
|
||||
this.cache.setScale(scale);
|
||||
this.canvases.forEach(v => {
|
||||
if (this.canvasMap.get(v)?.autoScale) {
|
||||
v.setScale(scale);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//#region 修改元素属性
|
||||
@@ -736,7 +764,6 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
||||
this.update();
|
||||
this.checkRoot();
|
||||
this._root?.connect(this);
|
||||
this.canvases.forEach(v => v.activate());
|
||||
this._transform.bind(this);
|
||||
}
|
||||
|
||||
@@ -751,7 +778,6 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
||||
this._parent = void 0;
|
||||
parent.requestSort();
|
||||
parent.update();
|
||||
this.canvases.forEach(v => v.deactivate());
|
||||
this._transform.bind();
|
||||
if (!success) return false;
|
||||
this._root?.disconnect(this);
|
||||
@@ -1257,8 +1283,6 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
||||
this.remove();
|
||||
this.emit('destroy');
|
||||
this.removeAllListeners();
|
||||
this.cache.delete();
|
||||
this.canvases.forEach(v => v.delete());
|
||||
this.canvases.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ export interface MotaRendererConfig {
|
||||
export class MotaRenderer extends Container implements IRenderTreeRoot {
|
||||
static list: Map<string, MotaRenderer> = new Map();
|
||||
|
||||
/** 缩放比 */
|
||||
private scale: number = 1;
|
||||
|
||||
/** 所有连接到此根元素的渲染元素的 id 到元素自身的映射 */
|
||||
protected idMap: Map<string, RenderItem> = new Map();
|
||||
|
||||
@@ -79,7 +82,6 @@ export class MotaRenderer extends Container implements IRenderTreeRoot {
|
||||
}
|
||||
this.target = new MotaOffscreenCanvas2D(config.alpha ?? true, canvas);
|
||||
this.size(config.width, config.height);
|
||||
this.target.withGameScale(true);
|
||||
this.target.setAntiAliasing(false);
|
||||
|
||||
this.setAnchor(0.5, 0.5);
|
||||
@@ -98,6 +100,31 @@ export class MotaRenderer extends Container implements IRenderTreeRoot {
|
||||
this.listen();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置这个渲染器的缩放比
|
||||
* @param scale 缩放比
|
||||
*/
|
||||
setScale(scale: number) {
|
||||
this.scale = scale;
|
||||
this.onResize(scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取这个渲染器的缩放比
|
||||
*/
|
||||
getScale() {
|
||||
return this.scale;
|
||||
}
|
||||
|
||||
onResize(scale: number): void {
|
||||
this.target.setScale(scale);
|
||||
const width = this.target.width * scale;
|
||||
const height = this.target.height * scale;
|
||||
this.target.canvas.style.width = `${width}px`;
|
||||
this.target.canvas.style.height = `${height}px`;
|
||||
super.onResize(scale);
|
||||
}
|
||||
|
||||
private getMountCanvas(canvas: string | HTMLCanvasElement) {
|
||||
if (typeof canvas === 'string') {
|
||||
return document.querySelector(canvas) as HTMLCanvasElement;
|
||||
@@ -576,7 +603,6 @@ export class MotaRenderer extends Container implements IRenderTreeRoot {
|
||||
destroy() {
|
||||
super.destroy();
|
||||
MotaRenderer.list.delete(this.id);
|
||||
this.target.delete();
|
||||
this.abort?.abort();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { TimingFn } from 'mutate-animate';
|
||||
// import { RenderAdapter } from './adapter';
|
||||
// import { FloorViewport } from './preset/viewport';
|
||||
import { JSX } from 'vue/jsx-runtime';
|
||||
import { DefineComponent, DefineSetupFnComponent } from 'vue';
|
||||
import { MotaOffscreenCanvas2D } from './canvas2d';
|
||||
@@ -14,10 +12,10 @@ export type Props<
|
||||
> = T extends keyof JSX.IntrinsicElements
|
||||
? JSX.IntrinsicElements[T]
|
||||
: T extends DefineSetupFnComponent<any>
|
||||
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
||||
: T extends DefineComponent
|
||||
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
||||
: unknown;
|
||||
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
||||
: T extends DefineComponent
|
||||
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
||||
: unknown;
|
||||
|
||||
export type ElementLocator = [
|
||||
x?: number,
|
||||
|
||||
Reference in new issue
Block a user