feat: 帧动画 & fix: 勇士移动

This commit is contained in:
unanmed 2024-08-20 18:04:22 +08:00
parent fdc08406b9
commit 5e54cc9424
7 changed files with 84 additions and 42 deletions

View File

@ -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');
}
});

View File

@ -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,

View File

@ -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);
}
});
});

View File

@ -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');

View File

@ -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();
});
}));
}
}

View File

@ -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
});
});

View File

@ -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();