From fdc08406b9c30fe873a0aab4b50f569828dfa9a1 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Tue, 20 Aug 2024 00:01:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9B=BE=E5=9D=97=E7=A7=BB=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/hero.ts | 175 -------------------------------- src/core/render/preset/hero.ts | 65 +++++++----- src/core/render/preset/layer.ts | 143 ++++++++++++++++---------- 3 files changed, 127 insertions(+), 256 deletions(-) delete mode 100644 src/core/render/hero.ts diff --git a/src/core/render/hero.ts b/src/core/render/hero.ts deleted file mode 100644 index 7b3ca75..0000000 --- a/src/core/render/hero.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { Ticker } from 'mutate-animate'; -import { MotaCanvas2D } from '../fx/canvas2d'; -import { EventEmitter } from '../common/eventEmitter'; -import { debounce } from 'lodash-es'; - -// 重写样板的勇士绘制 - -const canvas = MotaCanvas2D.for('@hero', false); - -Mota.require('var', 'loading').once('coreInit', () => { - canvas.withGameScale(true); - canvas.setHD(false); - canvas.size(480, 480); - canvas.pos(0, 0); - canvas.css(`z-index: 40`); - canvas.canvas.classList.add('no-anti-aliasing'); - canvas.setTarget(core.dom.gameDraw); - canvas.mount(); -}); - -const DIR_INDEX: Record = { - down: 0, - left: 1, - right: 2, - up: 3 -}; - -interface HeroDrawItem { - id: AllIds | 'hero'; - image: HTMLCanvasElement; -} - -interface HeroDrawing extends HeroDrawItem { - x: number; - y: number; - dir: Dir; -} - -interface HeroRendererEvent { - beforeDraw: () => void; - afterDraw: () => void; -} - -const resetMoving = debounce((render: HeroRenderer) => { - render.moving = 0; -}, 500); - -export class HeroRenderer extends EventEmitter { - followers: HeroDrawItem[] = []; - hero!: HeroDrawItem; - - /** 移动状态 */ - moving: number = 0; - /** 移动过程中的偏移 */ - offset: number = 0; - /** 勇士绘制时的alpha通道 */ - alpha: number = 1; - - ticker: Ticker = new Ticker(); - - /** 是否是后退状态 */ - private back: boolean = false; - /** 是否正在移动 */ - private isMoving: boolean = false; - /** 上一次换腿(?的时间 */ - private lastMoving: number = 0; - - constructor() { - super(); - - Mota.require('var', 'loading').once('coreInit', () => { - this.ticker.add(time => { - if (core.status.heroMoving < 0 || !this.isMoving) return; - if (time - this.lastMoving > core.values.moveSpeed) { - this.lastMoving = time; - this.moving++; - this.moving %= 4; - } - this.draw(); - }); - }); - } - - /** - * 设置勇士绘制信息 - */ - setHero() { - const image = core.material.images.hero; - const canvas = new MotaCanvas2D(); - canvas.setHD(false); - canvas.size(image.width, image.height); - canvas.ctx.drawImage(image, 0, 0); - this.hero = { - id: 'hero', - image: canvas.canvas - }; - } - - /** - * 执行绘制 - */ - draw() { - if (!core.isPlaying()) return; - return; - const { ctx, canvas: can } = canvas; - const { x, y, direction: dir } = core.status.hero.loc; - ctx.clearRect(0, 0, can.width, can.height); - ctx.globalAlpha = this.alpha; - - this.emit('beforeDraw'); - - const data: HeroDrawing[] = []; - data.push({ ...this.hero, x, y, dir }); - core.status.hero.followers.forEach((v, i) => { - const { id, image } = this.followers[i]; - data.push({ x: v.x, y: v.y, dir: v.direction, id, image }); - }); - - const { offsetX: ox, offsetY: oy } = core.bigmap; - const sgn = this.back ? -1 : 1; - const offset = this.offset * sgn; - - const frame = this.isMoving ? this.moving % 4 : 0; - - data.forEach(v => { - // hero offset x - const hox = offset * core.utils.scan[v.dir].x; - const hoy = offset * core.utils.scan[v.dir].y; - const cx = v.x * 32 + 16 - ox + hox; - const cy = v.y * 32 + 16 - oy + hoy; - const { width, height } = v.image; - const pw = width / 4; - const ph = height / 4; - const line = DIR_INDEX[v.dir]; - - const px = cx - pw / 2; - const py = cy - ph + 16; - - const sx = frame * pw; - const sy = line * ph; - - ctx.drawImage(v.image, sx, sy, pw, ph, px, py, pw, ph); - }); - - this.emit('afterDraw'); - } - - /** - * 设置绘制状态为正在移动还是静止 - */ - move(moving: boolean) { - this.isMoving = moving; - if (!moving) { - resetMoving(this); - } - } - - /** - * 设置当前是否为后退状态 - */ - backward(back: boolean) { - this.back = back; - } - - /** - * 设置绘制时的alpha - */ - setAlpha(alpha: number) { - this.alpha = alpha; - } -} - -const render = new HeroRenderer(); - -export { render as heroRender }; diff --git a/src/core/render/preset/hero.ts b/src/core/render/preset/hero.ts index 6a16ae2..e3f386c 100644 --- a/src/core/render/preset/hero.ts +++ b/src/core/render/preset/hero.ts @@ -233,38 +233,41 @@ export class HeroRenderer * 否则可能会导致移动过程中与大怪物的层级关系不正确,比如全在大怪物身后。注意不建议频繁改动这个值, * 因为此举会导致层级的重新排序,降低渲染性能。 */ - moveAs(x: number, y: number, time: number, fn: TimingFn<3>) { - if (this.status !== 'stop') return; - if (!this.renderable) return; + moveAs(x: number, y: number, time: number, fn: TimingFn<3>): Promise { + if (this.status !== 'stop') return Promise.reject(); + if (!this.renderable) return Promise.reject(); this.status = 'moving-as'; let nowZIndex = fn(0)[2]; let startTime = Date.now(); - this.layer.delegateTicker( - () => { - if (!this.renderable) return; - const now = Date.now(); - const progress = (now - startTime) / time; - const [nx, ny, nz] = fn(progress); - this.renderable.x = nx; - this.renderable.y = ny; - this.renderable.zIndex = nz; - if (nz !== nowZIndex) { - this.layer.movingRenderable.sort( - (a, b) => a.zIndex - b.zIndex - ); + return new Promise(res => { + this.layer.delegateTicker( + () => { + if (!this.renderable) return; + const now = Date.now(); + const progress = (now - startTime) / time; + const [nx, ny, nz] = fn(progress); + this.renderable.x = nx; + this.renderable.y = ny; + this.renderable.zIndex = nz; + if (nz !== nowZIndex) { + this.layer.movingRenderable.sort( + (a, b) => a.zIndex - b.zIndex + ); + } + this.layer.update(this.layer); + }, + time, + () => { + this.status = 'stop'; + if (!this.renderable) return res(); + this.renderable.animate = 0; + this.renderable.x = x; + this.renderable.y = y; + this.layer.update(this.layer); + res(); } - this.layer.update(this.layer); - }, - time, - () => { - this.status = 'stop'; - if (!this.renderable) return; - this.renderable.animate = 0; - this.renderable.x = x; - this.renderable.y = y; - this.layer.update(this.layer); - } - ); + ); + }); } /** @@ -309,3 +312,9 @@ adapter.recieve('move', (item, dir: Dir) => { adapter.recieve('endMove', item => { return item.endMove(); }); +adapter.recieve( + 'moveAs', + (item, x: number, y: number, time: number, fn: TimingFn<3>) => { + return item.moveAs(x, y, time, fn); + } +); diff --git a/src/core/render/preset/layer.ts b/src/core/render/preset/layer.ts index a30936b..305d1c4 100644 --- a/src/core/render/preset/layer.ts +++ b/src/core/render/preset/layer.ts @@ -639,12 +639,7 @@ interface MovingStepFunction { relative?: boolean; } -type MovingStep = MovingStepFunction | MovingStepLinearSwap; - interface MovingBlock { - steps: MovingStep[]; - /** 当前正在执行哪一步 */ - index: number; /** 当前横坐标 */ x: number; /** 当前纵坐标 */ @@ -695,8 +690,6 @@ export class Layer extends Container { /** 分块信息 */ block: BlockCacher = new BlockCacher(0, 0, core._WIDTH_, 4); - /** 正在移动的图块 */ - moving: MovingBlock[] = []; /** 大怪物渲染信息 */ bigImages: Map = new Map(); // todo: 是否需要桶排? @@ -706,6 +699,8 @@ export class Layer extends Container { needUpdateMoving: boolean = false; private extend: Map = new Map(); + /** 正在移动的图块的渲染信息 */ + private moving: Set = new Set(); constructor() { super('absolute', false); @@ -1142,25 +1137,7 @@ export class Layer extends Container { 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.push(...this.moving); for (const ex of this.extend.values()) { ex.onMovingUpdate?.(this, this.movingRenderable); @@ -1202,12 +1179,7 @@ export class Layer extends Container { const { ctx } = this.backMap; const mat = camera.mat; - const a = mat[0]; - const b = mat[1]; - const c = mat[3]; - const d = mat[4]; - const e = mat[6]; - const f = mat[7]; + const [a, b, , c, d, , e, f] = mat; ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.translate(core._PX_ / 2, core._PY_ / 2); ctx.transform(a, b, c, d, e, f); @@ -1322,12 +1294,7 @@ export class Layer extends Container { ctx.save(); const mat = camera.mat; - const a = mat[0]; - const b = mat[1]; - const c = mat[3]; - const d = mat[4]; - const e = mat[6]; - const f = mat[7]; + const [a, b, , c, d, , e, f] = mat; ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.translate(core._PX_ / 2, core._PY_ / 2); ctx.transform(a, b, c, d, e, f); @@ -1336,7 +1303,7 @@ export class Layer extends Container { const r = (max1 * max2) ** 2; this.movingRenderable.forEach(v => { - const { x, y, image, frame: blockFrame, render, animate } = v; + const { x, y, image, render, animate } = v; const ff = frame % 4; const i = animate === -1 ? ff : animate; const [sx, sy, w, h] = render[i]; @@ -1376,7 +1343,31 @@ export class Layer extends Container { x: number, y: number, time?: number - ): Promise; + ): Promise { + const block = this.renderData[index]; + const fx = index % this.width; + const fy = Math.floor(index / this.width); + + if (type === 'swap' || time === 0) { + this.putRenderData([0], 1, fx, fy); + this.putRenderData([block], 1, x, y); + return Promise.resolve(); + } else { + if (!time) return Promise.reject(); + const dx = x - fx; + const dy = y - fy; + return this.moveAs( + index, + x, + y, + progress => { + return [dx * progress, dy * progress, Math.floor(dy + fy)]; + }, + time + ); + } + } + /** * 让图块按照一个函数进行移动 * @param index 要移动的图块在渲染数据中的索引位置 @@ -1388,22 +1379,68 @@ export class Layer extends Container { * @param time 移动总时长 * @param relative 是否是相对模式 */ - move( + moveAs( index: number, - type: 'fn', + x: number, + y: number, fn: TimingFn<3>, - time?: number, - relative?: boolean - ): Promise; - move( - index: number, - type: 'linear' | 'swap' | 'fn', - x: number | TimingFn<3>, - y?: number, - time?: number | boolean + time: number, + relative: boolean = true ): Promise { - // todo - return Promise.resolve(); + const block = this.renderData[index]; + const fx = index % this.width; + const fy = Math.floor(index / this.width); + const renderable = texture.getRenderable(block); + if (!renderable) return Promise.reject(); + + const image = renderable.autotile + ? renderable.image[0] + : renderable.image; + + const moving: LayerMovingRenderable = { + x: fx, + y: fy, + zIndex: fy, + image: image, + autotile: false, + frame: renderable.frame, + bigImage: renderable.bigImage, + animate: -1, + render: renderable.render + }; + this.moving.add(moving); + + // 删除原始位置的图块 + this.putRenderData([0], 1, fx, fy); + + let nowZ = fy; + const startTime = Date.now(); + return new Promise(resolve => { + this.delegateTicker( + () => { + const now = Date.now(); + const progress = (now - startTime) / time; + const [nx, ny, nz] = fn(progress); + const tx = relative ? nx + fx : nx; + const ty = relative ? ny + fy : ny; + moving.x = tx; + moving.y = ty; + moving.zIndex = nz; + if (nz !== nowZ) { + this.movingRenderable.sort( + (a, b) => a.zIndex - b.zIndex + ); + } + this.update(this); + }, + time, + () => { + this.putRenderData([block], 1, x, y); + this.moving.delete(moving); + resolve(); + } + ); + }); } destroy(): void {