From 1c369251b17a0222bcd1ceeccfb6c861e4673775 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Mon, 26 Aug 2024 21:10:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9D=E7=9F=B3=E8=A1=80=E7=93=B6?= =?UTF-8?q?=E6=98=BE=E4=BC=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/index.ts | 2 + src/core/render/index.ts | 42 +++++++++ src/core/render/preset/damage.ts | 45 +++++----- src/core/render/preset/floor.ts | 6 +- src/core/render/preset/hero.ts | 9 +- src/core/render/preset/layer.ts | 19 ++++ src/core/render/render.ts | 73 +-------------- src/game/system.ts | 3 +- src/plugin/fx/itemDetail.ts | 149 ++++++++++++++++++++++--------- src/plugin/game/fallback.ts | 7 +- src/types/control.d.ts | 7 +- 11 files changed, 218 insertions(+), 144 deletions(-) create mode 100644 src/core/render/index.ts diff --git a/src/core/index.ts b/src/core/index.ts index 8bc99ed..881e0ee 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -69,6 +69,7 @@ import { Image, Text } from './render/preset/misc'; import { RenderItem } from './render/item'; import { texture } from './render/cache'; import { RenderAdapter } from './render/adapter'; +import { getMainRenderer } from './render'; // ----- 类注册 Mota.register('class', 'AudioPlayer', AudioPlayer); @@ -148,6 +149,7 @@ Mota.register('module', 'Effect', { }); Mota.register('module', 'Render', { texture, + getMainRenderer: getMainRenderer, MotaRenderer, Container, Sprite, diff --git a/src/core/render/index.ts b/src/core/render/index.ts new file mode 100644 index 0000000..caef4d0 --- /dev/null +++ b/src/core/render/index.ts @@ -0,0 +1,42 @@ +import { FloorItemDetail } from '@/plugin/fx/itemDetail'; +import { FloorDamageExtends } from './preset/damage'; +import { LayerGroupFloorBinder } from './preset/floor'; +import { HeroRenderer } from './preset/hero'; +import { LayerGroup, FloorLayer } from './preset/layer'; +import { MotaRenderer } from './render'; + +let main: MotaRenderer; + +export function getMainRenderer() { + return main; +} + +Mota.require('var', 'loading').once('loaded', () => { + const render = new MotaRenderer(); + main = render; + render.mount(); + render.hide(); + + const layer = new LayerGroup(); + + ['bg', 'bg2', 'event', 'fg', 'fg2'].forEach(v => { + layer.addLayer(v as FloorLayer); + }); + + const damage = new FloorDamageExtends(); + const hero = new HeroRenderer(); + const detail = new FloorItemDetail(); + layer.extends(damage); + layer.extends(detail); + layer.getLayer('event')?.extends(hero); + + render.appendChild(layer); +}); + +Mota.require('var', 'hook').on('reset', () => { + main.show(); +}); + +Mota.require('var', 'hook').on('restart', () => { + main.hide(); +}); diff --git a/src/core/render/preset/damage.ts b/src/core/render/preset/damage.ts index 1911062..46027d4 100644 --- a/src/core/render/preset/damage.ts +++ b/src/core/render/preset/damage.ts @@ -40,7 +40,7 @@ export class FloorDamageExtends * 立刻刷新伤害渲染 */ update(floor: FloorIds) { - if (!this.sprite) return; + if (!this.sprite || !floor) return; const map = core.status.maps[floor]; this.sprite.setMapSize(map.width, map.height); ensureFloorDamage(floor); @@ -89,21 +89,19 @@ export class FloorDamageExtends } awake(group: LayerGroup): void { - group.requestBeforeFrame(() => { - const ex = group.getExtends('floor-binder'); - if (ex instanceof LayerGroupFloorBinder) { - this.floorBinder = ex; - this.group = group; - this.create(); - this.listen(); - } else { - logger.warn( - 17, - `Floor-damage extends needs 'floor-binder' extends as dependency.` - ); - group.removeExtends('floor-damage'); - } - }); + const ex = group.getExtends('floor-binder'); + if (ex instanceof LayerGroupFloorBinder) { + this.floorBinder = ex; + this.group = group; + this.create(); + this.listen(); + } else { + logger.warn( + 17, + `Floor-damage extends needs 'floor-binder' extends as dependency.` + ); + group.removeExtends('floor-damage'); + } } onDestroy(group: LayerGroup): void { @@ -132,6 +130,7 @@ interface DamageCache { interface EDamageEvent extends ESpriteEvent { setMapSize: [width: number, height: number]; beforeDamageRender: [need: Set, transform: Transform]; + updateBlocks: [blocks: Set]; } export class Damage extends Sprite { @@ -241,13 +240,16 @@ export class Damage extends Sprite { /** * 更新指定分块 * @param blocks 要更新的分块集合 + * @param map 是否更新地图伤害 */ - updateBlocks(blocks?: Set) { + updateBlocks(blocks?: Set, map: boolean = true) { if (blocks) { - blocks.forEach(v => this.updateBlock(v)); + blocks.forEach(v => this.updateBlock(v, map)); + this.emit('updateBlocks', blocks); } else { this.blockData.forEach((_, k) => this.updateBlock(k, false)); - this.extractAllMapDamage(); + if (map) this.extractAllMapDamage(); + this.emit('updateBlocks', new Set(this.blockData.keys())); } this.update(this); } @@ -274,7 +276,9 @@ export class Damage extends Sprite { this.needUpdateBlocks.add(block); this.requestBeforeFrame(() => { this.needUpdateBlock = false; - this.needUpdateBlocks.forEach(v => this.updateBlock(v, false)); + this.updateBlocks(this.needUpdateBlocks, false); + this.needUpdateBlocks.clear(); + // this.needUpdateBlocks.forEach(v => this.updateBlock(v, false)); // todo: 阻击夹域等地图伤害检测是否必要更新,例如不包含阻击夹域的怪就不必要更新这个怪物信息 // this.extractAllMapDamage(); }); @@ -423,6 +427,7 @@ export class Damage extends Sprite { ctx.save(); this.damageMap.clear(); transformCanvas(this.damageMap, transform); + // console.trace(); const { res: render } = this.calNeedRender(transform); const block = this.block; diff --git a/src/core/render/preset/floor.ts b/src/core/render/preset/floor.ts index 4d8f44a..fd970fe 100644 --- a/src/core/render/preset/floor.ts +++ b/src/core/render/preset/floor.ts @@ -149,9 +149,9 @@ export class LayerGroupFloorBinder LayerGroupFloorBinder.activedBinder.add(this); } - onLayerAdd(group: LayerGroup, layer: Layer): void { - this.checkLayerExtends(layer); - } + // onLayerAdd(group: LayerGroup, layer: Layer): void { + // this.checkLayerExtends(layer); + // } onDestroy(group: LayerGroup) { LayerGroupFloorBinder.activedBinder.delete(this); diff --git a/src/core/render/preset/hero.ts b/src/core/render/preset/hero.ts index 4a5400c..1bb1b5a 100644 --- a/src/core/render/preset/hero.ts +++ b/src/core/render/preset/hero.ts @@ -145,7 +145,10 @@ export class HeroRenderer */ private moveTick(time: number) { if (this.status !== 'moving') return; - if (!this.renderable) return; + if (!this.renderable) { + this.emit('stepEnd'); + return; + } if (time - this.lastFrameTime > this.speed) { this.lastFrameTime = time; @@ -379,6 +382,10 @@ adapter.recieve('turn', (item, dir: Dir2) => { item.turn(dir); return Promise.resolve(); }); +adapter.recieve('setImage', (item, image: SizedCanvasImageSource) => { + item.setImage(image); + return Promise.resolve(); +}); // 同步fallback,用于适配现在的样板,之后会删除 adapter.recieveSync('setHeroLoc', (item, x?: number, y?: number) => { item.setHeroLoc(x, y); diff --git a/src/core/render/preset/layer.ts b/src/core/render/preset/layer.ts index 259cd75..e529302 100644 --- a/src/core/render/preset/layer.ts +++ b/src/core/render/preset/layer.ts @@ -8,6 +8,7 @@ import { RenderableData, texture } from '../cache'; import { glMatrix } from 'gl-matrix'; import { BlockCacher } from './block'; import { Transform } from '../transform'; +import { LayerFloorBinder, LayerGroupFloorBinder } from './floor'; export interface ILayerGroupRenderExtends { /** 拓展的唯一标识符 */ @@ -60,6 +61,18 @@ export interface ILayerGroupRenderExtends { */ onFrameUpdate?(group: LayerGroup, frame: number): void; + /** + * 在渲染之前执行的函数 + * @param group 目标LayerGroup实例 + */ + onBeforeRender?(group: LayerGroup): void; + + /** + * 在渲染之后执行的函数 + * @param group 目标LayerGroup实例 + */ + onAfterRender?(group: LayerGroup): void; + /** * 当拓展被取消挂载时执行的函数(LayerGroup被销毁,拓展被移除等) * @param group 目标LayerGroup实例 @@ -100,6 +113,10 @@ export class LayerGroup extends Container implements IAnimateFrame { }); renderEmits.addFramer(this); + + const binder = new LayerGroupFloorBinder(); + this.extends(binder); + binder.bindThis(); } /** @@ -675,6 +692,8 @@ export class Layer extends Container { ctx.drawImage(this.staticMap.canvas, 0, 0, width, height); ctx.drawImage(this.movingMap.canvas, 0, 0, width, height); }); + + this.extends(new LayerFloorBinder()); } /** diff --git a/src/core/render/render.ts b/src/core/render/render.ts index 16d9bd7..31d8e08 100644 --- a/src/core/render/render.ts +++ b/src/core/render/render.ts @@ -1,14 +1,7 @@ -import { Animation, hyper, linear, sleep } from 'mutate-animate'; -import { MotaCanvas2D, MotaOffscreenCanvas2D } from '../fx/canvas2d'; +import { MotaCanvas2D } from '../fx/canvas2d'; import { Container } from './container'; -import { RenderItem, transformCanvas } from './item'; -import { FloorLayer, Layer, LayerGroup } from './preset/layer'; -import { LayerGroupFloorBinder } from './preset/floor'; -import { FloorDamageExtends } from './preset/damage'; -import { HeroRenderer } from './preset/hero'; +import { RenderItem } from './item'; import { Transform } from './transform'; -import { Text } from './preset/misc'; -import { Shader } from './shader'; export class MotaRenderer extends Container { static list: Set = new Set(); @@ -69,65 +62,3 @@ export class MotaRenderer extends Container { window.addEventListener('resize', () => { MotaRenderer.list.forEach(v => v.update(v)); }); - -Mota.require('var', 'hook').once('reset', () => { - const render = new MotaRenderer(); - const transform = render.transform; - render.mount(); - - const ani = new Animation(); - - const shader = new Shader(); - const layer = new LayerGroup(); - - ['bg', 'bg2', 'event', 'fg', 'fg2'].forEach(v => { - layer.addLayer(v as FloorLayer); - }); - - const binder = new LayerGroupFloorBinder(); - const damage = new FloorDamageExtends(); - const hero = new HeroRenderer(); - layer.extends(binder); - layer.extends(damage); - layer.getLayer('event')?.extends(hero); - binder.bindThis(); - render.appendChild(shader); - shader.appendChild(layer); - shader.size(480, 480); - shader.fs(` - uniform float u_offset; - - void main() { - // 计算当前像素到爆炸中心的距离 - vec2 coordToCenter = v_texCoord - vec2(0.5, 0.5); - float distance = length(coordToCenter); - - // 根据时间计算当前距离上的波动相位 - float wavePhase = 100.0 * (distance - u_offset); - - // 计算波动的强度(正弦波)并结合衰减 - float wave = sin(wavePhase) * 0.02 / (1.0 + 10.0 * distance); - - // 将波动效果应用到纹理坐标上,造成扭曲 - vec2 warpedCoords = v_texCoord + normalize(coordToCenter) * wave; - - // 采样纹理并输出颜色 - gl_FragColor = texture2D(u_sampler, warpedCoords); - } - `); - shader.compileShader(); - - const offset = shader.getUniform('u_offset'); - shader.delegateTicker(() => { - shader.gl.uniform1f(offset, ani.value.offset); - shader.update(); - }, 20000); - ani.value.offset = 0; - ani.mode(linear()).time(10000).absolute().apply('offset', 1); - - layer.requestAfterFrame(() => { - hero.setImage(core.material.images.images['hero2.png']); - }); - - console.log(render); -}); diff --git a/src/game/system.ts b/src/game/system.ts index f2b206c..a415f7b 100644 --- a/src/game/system.ts +++ b/src/game/system.ts @@ -31,7 +31,6 @@ import type { texture } from '@/core/render/cache'; import type { MotaRenderer } from '@/core/render/render'; import type { Container } from '@/core/render/container'; import type { Sprite } from '@/core/render/sprite'; -import type { Camera } from '@/core/render/camera'; import type { Image, Text } from '@/core/render/preset/misc'; import type { RenderItem } from '@/core/render/item'; import type { RenderAdapter } from '@/core/render/adapter'; @@ -107,10 +106,10 @@ interface ModuleInterface { }; Render: { texture: typeof texture; + main: MotaRenderer; MotaRenderer: typeof MotaRenderer; Container: typeof Container; Sprite: typeof Sprite; - Camera: typeof Camera; Text: typeof Text; Image: typeof Image; RenderItem: typeof RenderItem; diff --git a/src/plugin/fx/itemDetail.ts b/src/plugin/fx/itemDetail.ts index 2f0cbd2..777cefd 100644 --- a/src/plugin/fx/itemDetail.ts +++ b/src/plugin/fx/itemDetail.ts @@ -10,7 +10,6 @@ import { ILayerGroupRenderExtends, LayerGroup } from '@/core/render/preset/layer'; -import { cloneDeep } from 'lodash-es'; interface ItemDetailData { x: number; @@ -25,8 +24,13 @@ interface ItemData { } const ItemState = Mota.require('module', 'State').ItemState; +Mota.require('var', 'hook').on('setBlock', (x, y, floorId, block) => { + FloorItemDetail.listened.forEach(v => { + v.setBlock(block, x, y); + }); +}); -class FloorItemDetail implements ILayerGroupRenderExtends { +export class FloorItemDetail implements ILayerGroupRenderExtends { id: string = 'item-detail'; group!: LayerGroup; @@ -35,7 +39,12 @@ class FloorItemDetail implements ILayerGroupRenderExtends { sprite!: Damage; /** 每个分块中包含的物品信息 */ - blockData: Map> = new Map(); + blockData: Map> = new Map(); + + /** 需要更新的分块 */ + private dirtyBlock: Set = new Set(); + /** 道具详细信息 */ + private detailData: Map> = new Map(); static detailColor: Record = { atk: '#FF7A7A', @@ -51,8 +60,15 @@ class FloorItemDetail implements ILayerGroupRenderExtends { manaper: '#c66' }; - private onBeforeRender = (need: Set) => { + static listened: Set = new Set(); + + private onBeforeDamageRender = (need: Set) => { if (!mainSetting.getValue('screen.itemDetail')) return; + need.forEach(v => { + if (this.dirtyBlock.has(v)) { + this.sprite.block.clearCache(v, 1); + } + }); this.render(need); }; @@ -60,9 +76,21 @@ class FloorItemDetail implements ILayerGroupRenderExtends { this.updateMapSize(width, height); }; + private onUpdate = () => { + this.updateItems(); + }; + + private onUpdateBlocks = (blocks: Set) => { + blocks.forEach(v => { + this.dirtyBlock.add(v); + }); + }; + private listen() { - this.sprite.on('beforeDamageRender', this.onBeforeRender); + this.sprite.on('beforeDamageRender', this.onBeforeDamageRender); this.sprite.on('setMapSize', this.onUpdateMapSize); + this.sprite.on('updateBlocks', this.onUpdateBlocks); + this.damage.on('update', this.onUpdate); } /** @@ -72,9 +100,12 @@ class FloorItemDetail implements ILayerGroupRenderExtends { this.blockData.clear(); // 预留blockData - const num = width * height; + const [x, y] = this.sprite.block.getBlockXY(width, height); + const num = x * y; for (let i = 0; i < num; i++) { - this.blockData.set(i, new Set()); + this.blockData.set(i, new Map()); + this.detailData.set(i, new Map()); + this.dirtyBlock.add(i); } } @@ -83,6 +114,7 @@ class FloorItemDetail implements ILayerGroupRenderExtends { */ updateItems() { const floor = this.floorBinder.getFloor(); + if (!floor) return; core.extractBlocks(floor); core.status.maps[floor].blocks.forEach(v => { @@ -93,18 +125,46 @@ class FloorItemDetail implements ILayerGroupRenderExtends { const x = v.x; const y = v.y; const block = this.sprite.block.getIndexByLoc(x, y); - this.blockData.get(block)?.add({ x, y, id }); + const index = x + y * this.sprite.mapWidth; + const blockData = this.blockData.get(block); + blockData?.set(index, { x, y, id }); }); } + /** + * 设置图块 + * @param block 图块数字 + * @param x 横坐标 + * @param y 纵坐标 + */ + setBlock(block: AllNumbers, x: number, y: number) { + const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e; + const index = this.sprite.block.getIndexByLoc(x, y); + const itemIndex = x + y * this.sprite.mapWidth; + const blockData = this.blockData.get(index); + this.dirtyBlock.add(index); + if (block === 0) { + blockData?.delete(itemIndex); + return; + } + const cls = map[block].cls; + if (cls !== 'items') { + blockData?.delete(itemIndex); + return; + } + const id = map[block].id; + blockData?.set(itemIndex, { x, y, id }); + } + /** * 计算指定分块中的物品信息 * @param block 要计算的分块 */ calAllItems(block: Set) { + if (this.dirtyBlock.size === 0 || block.size === 0) return; let diff: Record = {}; const before = core.status.hero; - const hero = cloneDeep(core.status.hero); + const hero = structuredClone(core.status.hero); const handler: ProxyHandler = { set(target, key, v) { diff[key] = v - (target[key] || 0); @@ -114,14 +174,16 @@ class FloorItemDetail implements ILayerGroupRenderExtends { }; core.status.hero = new Proxy(hero, handler); - const res: Map> = new Map(); core.setFlag('__statistics__', true); block.forEach(v => { + if (!this.dirtyBlock.has(v)) return; const data = this.blockData.get(v); + const detail = this.detailData.get(v); + detail?.clear(); if (!data) return; - const info: Set = new Set(); data.forEach(v => { - const { x, y, id } = v; + const { id, x, y } = v; + const index = x + y * this.sprite.mapWidth; diff = {}; const item = core.material.items[id]; @@ -135,21 +197,18 @@ class FloorItemDetail implements ILayerGroupRenderExtends { const n = name as SelectKey; diff[name + 'per'] = per[n].toString() + '%'; } - info.add({ x, y, diff }); + detail?.set(index, { x, y, diff }); return; } // @ts-ignore ItemState.item(id)?.itemEffectFn(); - info.add({ x, y, diff }); + detail?.set(index, { x, y, diff }); }); - res.set(v, info); }); core.status.hero = before; window.hero = before; window.flags = before.flags; - - return res; } /** @@ -157,8 +216,13 @@ class FloorItemDetail implements ILayerGroupRenderExtends { * @param block 需要渲染的格子 */ render(block: Set) { - const data = this.calAllItems(block); - data.forEach((info, k) => { + this.calAllItems(block); + const data = this.detailData; + block.forEach(v => { + if (!this.dirtyBlock.has(v)) return; + this.dirtyBlock.delete(v); + const info = data.get(v); + if (!info) return; info.forEach(({ x, y, diff }) => { let n = 0; for (const [key, value] of Object.entries(diff)) { @@ -173,7 +237,7 @@ class FloorItemDetail implements ILayerGroupRenderExtends { align: 'left', baseline: 'alphabetic' }; - this.sprite.renderable.get(k)?.add(renderable); + this.sprite.renderable.get(v)?.add(renderable); n++; } }); @@ -181,32 +245,33 @@ class FloorItemDetail implements ILayerGroupRenderExtends { } awake(group: LayerGroup): void { + console.log(this); + this.group = group; - group.requestBeforeFrame(() => { - const binder = group.getExtends('floor-binder'); - const damage = group.getExtends('floor-damage'); - if ( - binder instanceof LayerGroupFloorBinder && - damage instanceof FloorDamageExtends - ) { - this.floorBinder = binder; - this.damage = damage; - group.requestAfterFrame(() => { - this.sprite = damage.sprite; - this.listen(); - }); - } else { - logger.warn( - 1001, - `Item-detail extends needs 'floor-binder' and 'floor-damage' as dependency` - ); - group.removeExtends('item-detail'); - } - }); + + const binder = group.getExtends('floor-binder'); + const damage = group.getExtends('floor-damage'); + if ( + binder instanceof LayerGroupFloorBinder && + damage instanceof FloorDamageExtends + ) { + this.floorBinder = binder; + this.damage = damage; + this.sprite = damage.sprite; + this.listen(); + FloorItemDetail.listened.add(this); + } else { + logger.warn( + 1001, + `Item-detail extends needs 'floor-binder' and 'floor-damage' as dependency` + ); + group.removeExtends('item-detail'); + } } onDestroy(group: LayerGroup): void { - this.sprite.off('beforeDamageRender', this.onBeforeRender); + this.sprite.off('beforeDamageRender', this.onBeforeDamageRender); this.sprite.off('setMapSize', this.onUpdateMapSize); + FloorItemDetail.listened.delete(this); } } diff --git a/src/plugin/game/fallback.ts b/src/plugin/game/fallback.ts index b362601..fc92d65 100644 --- a/src/plugin/game/fallback.ts +++ b/src/plugin/game/fallback.ts @@ -267,9 +267,12 @@ export function init() { stopChian = true; callback?.(); + }; - // if (callback) return this.moveAction(callback); - // this._moveHero_moving(); + events.prototype.setHeroIcon = function (name: ImageIds) { + const img = core.material.images.images[name]; + if (!img) return; + adapters['hero-adapter']?.all('setImage', img); }; hook.on('reset', () => { diff --git a/src/types/control.d.ts b/src/types/control.d.ts index 8b5b7fa..28ce760 100644 --- a/src/types/control.d.ts +++ b/src/types/control.d.ts @@ -312,7 +312,8 @@ interface Control { moveOneStep(callback?: () => any): void; /** - * @deprecated + * @deprecated 尽量不要使用!!如果需要无视地形使用代码来移动勇士,请使用 `eventMoveHero` + * 如果需要向前前进一格或撞击,请使用 `moveHero` * 尝试前进一步,如果面前不可被踏入就会直接触发该点事件 * @example core.moveAction(core.doAction); // 尝试前进一步,然后继续事件处理 * @param callback 走一步后的回调函数 @@ -320,8 +321,8 @@ interface Control { moveAction(callback?: () => void): void; /** - * @deprecated - * 连续前进,不撞南墙不回头 + * @deprecated 尽量不要使用!!如果需要无视地形使用代码来移动勇士,请使用 `eventMoveHero` + * 向指定方向移动一格 * @example core.moveHero(); // 连续前进 * @param direction 移动的方向,不设置就是勇士当前的方向 * @param callback 回调函数,设置了就只走一步