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 {