From 5e54cc942418a6999f586f50b98afe96a816cea7 Mon Sep 17 00:00:00 2001
From: unanmed <1319491857@qq.com>
Date: Tue, 20 Aug 2024 18:04:22 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B8=A7=E5=8A=A8=E7=94=BB=20&=20fix:?=
 =?UTF-8?q?=20=E5=8B=87=E5=A3=AB=E7=A7=BB=E5=8A=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/core/fx/canvas2d.ts          |  4 +++
 src/core/index.ts                |  2 --
 src/core/render/item.ts          | 42 ++++++++++++++++++++++++++++----
 src/core/render/preset/damage.ts | 19 +++++++++++----
 src/core/render/preset/hero.ts   |  7 ++++--
 src/core/render/preset/layer.ts  | 39 +++++++++++------------------
 src/core/render/render.ts        | 13 +++++++---
 7 files changed, 84 insertions(+), 42 deletions(-)

diff --git a/src/core/fx/canvas2d.ts b/src/core/fx/canvas2d.ts
index 33629f5..edbe320 100644
--- a/src/core/fx/canvas2d.ts
+++ b/src/core/fx/canvas2d.ts
@@ -25,6 +25,9 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
 
     scale: number = 1;
 
+    /** 更新标识符,如果发生变化则说明画布被动清空 */
+    symbol: number = 0;
+
     constructor() {
         super();
 
@@ -248,6 +251,7 @@ window.addEventListener('resize', () => {
         MotaOffscreenCanvas2D.list.forEach(v => {
             if (v.autoScale) {
                 v.size(v.width, v.height);
+                v.symbol++;
                 v.emit('resize');
             }
         });
diff --git a/src/core/index.ts b/src/core/index.ts
index b4e1df4..ed8b265 100644
--- a/src/core/index.ts
+++ b/src/core/index.ts
@@ -62,7 +62,6 @@ import { Danmaku } from './main/custom/danmaku';
 import * as Shadow from './fx/shadow';
 import { MotaCanvas2D } from './fx/canvas2d';
 import * as portal from './fx/portal';
-import { heroRender } from './render/hero';
 import { MotaRenderer } from './render/render';
 import { Container } from './render/container';
 import { Sprite } from './render/sprite';
@@ -148,7 +147,6 @@ Mota.register('module', 'Effect', {
     Portal: portal
 });
 Mota.register('module', 'Render', {
-    heroRender,
     texture,
     MotaRenderer,
     Container,
diff --git a/src/core/render/item.ts b/src/core/render/item.ts
index e4b48cd..acf92e0 100644
--- a/src/core/render/item.ts
+++ b/src/core/render/item.ts
@@ -1,5 +1,5 @@
 import { isNil } from 'lodash-es';
-import { EventEmitter } from '../common/eventEmitter';
+import { EventEmitter } from 'eventemitter3';
 import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
 import { Camera } from './camera';
 import { Ticker, TickerFn } from 'mutate-animate';
@@ -379,11 +379,43 @@ RenderItem.ticker.add(() => {
     }
 });
 
-interface RenderEvent {
-    animateFrame: (frame: number, time: number) => void;
+export interface IAnimateFrame {
+    updateFrameAnimate(frame: number, time: number): void;
 }
 
-export const renderEmits = new EventEmitter<RenderEvent>();
+interface RenderEvent {
+    animateFrame: [frame: number, time: number];
+}
+
+class RenderEmits extends EventEmitter<RenderEvent> {
+    private framer: Set<IAnimateFrame> = new Set();
+
+    /**
+     * 添加一个可更新帧动画的对象
+     */
+    addFramer(framer: IAnimateFrame) {
+        this.framer.add(framer);
+    }
+
+    /**
+     * 移除一个可更新帧动画的对象
+     */
+    removeFramer(framer: IAnimateFrame) {
+        this.framer.delete(framer);
+    }
+
+    /**
+     * 更新所有帧动画
+     * @param frame 帧数
+     * @param time 帧动画时刻
+     */
+    emitAnimateFrame(frame: number, time: number) {
+        this.framer.forEach(v => v.updateFrameAnimate(frame, time));
+        this.emit('animateFrame', frame, time);
+    }
+}
+
+export const renderEmits = new RenderEmits();
 
 Mota.require('var', 'hook').once('reset', () => {
     let lastTime = 0;
@@ -392,7 +424,7 @@ Mota.require('var', 'hook').once('reset', () => {
         if (time - lastTime > core.values.animateSpeed) {
             RenderItem.animatedFrame++;
             lastTime = time;
-            renderEmits.emit('animateFrame', RenderItem.animatedFrame, time);
+            renderEmits.emitAnimateFrame(RenderItem.animatedFrame, time);
         }
     });
 });
diff --git a/src/core/render/preset/damage.ts b/src/core/render/preset/damage.ts
index 8e99e9c..5e0152a 100644
--- a/src/core/render/preset/damage.ts
+++ b/src/core/render/preset/damage.ts
@@ -104,11 +104,16 @@ interface DamageRenderable {
     strokeWidth?: number;
 }
 
+interface DamageCache {
+    canvas: MotaOffscreenCanvas2D;
+    symbol: number;
+}
+
 export class Damage extends Sprite {
     mapWidth: number = 0;
     mapHeight: number = 0;
 
-    block: BlockCacher<HTMLCanvasElement>;
+    block: BlockCacher<DamageCache>;
     /** 键表示分块索引,值表示在这个分块上的渲染信息(当然实际渲染位置可以不在这个分块上) */
     renderable: Map<number, Set<DamageRenderable>> = new Map();
 
@@ -404,13 +409,14 @@ export class Damage extends Sprite {
             // todo: 是否真的需要缓存
             // 检查有没有缓存
             const cache = block.cache.get(v * block.cacheDepth);
-            if (cache) {
-                ctx.drawImage(cache, px, py, size, size);
+            if (cache && cache.symbol === cache.canvas.symbol) {
+                ctx.drawImage(cache.canvas.canvas, px, py, size, size);
                 return;
             }
 
             // 否则依次渲染并写入缓存
-            const temp = new MotaOffscreenCanvas2D();
+            const temp = cache?.canvas ?? new MotaOffscreenCanvas2D();
+            temp.clear();
             temp.setHD(true);
             temp.setAntiAliasing(true);
             temp.withGameScale(true);
@@ -431,7 +437,10 @@ export class Damage extends Sprite {
             });
 
             ctx.drawImage(temp.canvas, px, py, size, size);
-            block.cache.set(v, temp.canvas);
+            block.cache.set(v, {
+                canvas: temp,
+                symbol: temp.symbol
+            });
         });
         ctx.restore();
         // console.timeEnd('damage');
diff --git a/src/core/render/preset/hero.ts b/src/core/render/preset/hero.ts
index e3f386c..6337b0c 100644
--- a/src/core/render/preset/hero.ts
+++ b/src/core/render/preset/hero.ts
@@ -140,6 +140,7 @@ export class HeroRenderer
         }
 
         const progress = (time - this.lastStepTime) / this.speed;
+
         const { x: dx, y: dy } = this.stepDelta;
         const { x, y } = core.status.hero.loc;
         if (progress >= 1) {
@@ -184,8 +185,10 @@ export class HeroRenderer
         else {
             this.step();
             return (this.moveDetached = new Promise<void>(resolve => {
-                this.moveDetached = void 0;
-                this.once('stepEnd', resolve);
+                this.once('stepEnd', () => {
+                    this.moveDetached = void 0;
+                    resolve();
+                });
             }));
         }
     }
diff --git a/src/core/render/preset/layer.ts b/src/core/render/preset/layer.ts
index 305d1c4..890a06d 100644
--- a/src/core/render/preset/layer.ts
+++ b/src/core/render/preset/layer.ts
@@ -3,7 +3,12 @@ import { Container } from '../container';
 import { Sprite } from '../sprite';
 import { Camera } from '../camera';
 import { TimingFn } from 'mutate-animate';
-import { RenderItem, renderEmits, transformCanvas } from '../item';
+import {
+    IAnimateFrame,
+    renderEmits,
+    RenderItem,
+    transformCanvas
+} from '../item';
 import { logger } from '@/core/common/logger';
 import { AutotileRenderable, RenderableData, texture } from '../cache';
 import { glMatrix } from 'gl-matrix';
@@ -83,7 +88,7 @@ export interface ILayerGroupRenderExtends {
 
 export type FloorLayer = 'bg' | 'bg2' | 'event' | 'fg' | 'fg2';
 
-export class LayerGroup extends Container {
+export class LayerGroup extends Container implements IAnimateFrame {
     /** 地图组列表 */
     // static list: Set<LayerGroup> = new Set();
 
@@ -113,9 +118,7 @@ export class LayerGroup extends Container {
             this.releaseNeedRender();
         });
 
-        // this.usePreset('defaults');
-        // LayerGroup.list.add(this);
-        // this.bindFloor(floor);
+        renderEmits.addFramer(this);
     }
 
     /**
@@ -157,7 +160,6 @@ export class LayerGroup extends Container {
         this.layers.forEach(v => {
             v.block.setBlockSize(size);
         });
-        // this.damage?.block.setBlockSize(size);
     }
 
     /**
@@ -173,11 +175,8 @@ export class LayerGroup extends Container {
      */
     emptyLayer() {
         this.removeChild(...this.layers.values());
-        // if (this.damage) this.removeChild(this.damage);
-        // this.damage?.destroy();
         this.layers.forEach(v => v.destroy());
         this.layers.clear();
-        // this.damage = void 0;
 
         for (const ex of this.extend.values()) {
             ex.onEmptyLayer?.(this);
@@ -190,7 +189,6 @@ export class LayerGroup extends Container {
      */
     addLayer(layer: FloorLayer) {
         const l = new Layer();
-        // l.bindLayer(layer);
         l.layer = layer;
         if (l.layer) this.layers.set(l.layer, l);
         this.appendChild(l);
@@ -293,7 +291,6 @@ export class LayerGroup extends Container {
         this.layers.forEach(v => {
             v.cache(v.using);
         });
-        // this.damage?.cache(this.damage.using);
         this.update(this);
 
         for (const ex of this.extend.values()) {
@@ -306,19 +303,10 @@ export class LayerGroup extends Container {
             ex.onDestroy?.(this);
         }
         super.destroy();
-        // LayerGroup.list.delete(this);
+        renderEmits.removeFramer(this);
     }
 }
 
-const hook = Mota.require('var', 'hook');
-
-// todo: animate frame.
-// renderEmits.on('animateFrame', () => {
-//     LayerGroup.list.forEach(v => {
-//         v.updateFrameAnimate();
-//     });
-// });
-
 export function calNeedRenderOf(
     camera: Camera,
     cell: number,
@@ -601,8 +589,8 @@ export interface ILayerRenderExtends {
 }
 
 interface LayerCacheItem {
-    // todo: 删掉这个属性
-    canvas: HTMLCanvasElement;
+    symbol: number;
+    canvas: MotaOffscreenCanvas2D;
 }
 
 export interface LayerMovingRenderable extends RenderableData {
@@ -1227,7 +1215,7 @@ export class Layer extends Container {
             const cache = this.block.cache.get(index);
             if (cache) {
                 ctx.drawImage(
-                    cache.canvas,
+                    cache.canvas.canvas,
                     sx * cell,
                     sy * cell,
                     blockSize * cell,
@@ -1276,7 +1264,8 @@ export class Layer extends Container {
                 blockSize * cell
             );
             this.block.cache.set(index, {
-                canvas: temp.canvas
+                canvas: temp,
+                symbol: temp.symbol
             });
         });
 
diff --git a/src/core/render/render.ts b/src/core/render/render.ts
index 268616e..e527d5f 100644
--- a/src/core/render/render.ts
+++ b/src/core/render/render.ts
@@ -163,9 +163,16 @@ Mota.require('var', 'hook').once('reset', () => {
     layer.requestAfterFrame(() => {
         hero.setImage(core.material.images.images['hero2.png']);
     });
-    layer.delegateTicker(() => {
-        hero.turn();
-    }, 10000);
+    hero.readyMove();
+    layer.delegateTicker(
+        () => {
+            hero.move('right');
+        },
+        10000,
+        () => {
+            hero.endMove();
+        }
+    );
 
     camera.move(240, 240);
     render.update();