fix: 光影效果

This commit is contained in:
unanmed 2024-08-26 23:59:58 +08:00
parent 053de036ec
commit 27923851bd
6 changed files with 230 additions and 61 deletions

View File

@ -1,6 +1,7 @@
import { parseCss } from '@/plugin/utils';
import { EventEmitter } from 'eventemitter3';
import { CSSObj } from '../interface';
import { isWebGL2Supported } from './webgl';
interface OffscreenCanvasEvent {
/** 当被动触发resize时例如core.domStyle.scale变化、窗口大小变化时触发使用size函数并不会触发 */
@ -36,8 +37,6 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
this.width = this.canvas.width / devicePixelRatio;
this.height = this.canvas.height / devicePixelRatio;
this.canvas.style.position = 'absolute';
MotaOffscreenCanvas2D.list.add(this);
}
@ -121,6 +120,74 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
}
}
export class MotaOffscreenCanvasGL2 extends EventEmitter<OffscreenCanvasEvent> {
static support: boolean = isWebGL2Supported();
static list: Set<MotaOffscreenCanvasGL2> = new Set();
canvas: HTMLCanvasElement;
gl: WebGL2RenderingContext;
width: number;
height: number;
/** 是否自动跟随样板的core.domStyle.scale进行缩放 */
autoScale: boolean = false;
/** 是否是高清画布 */
highResolution: boolean = true;
scale: number = 1;
/** 更新标识符,如果发生变化则说明画布被动清空 */
symbol: number = 0;
constructor() {
super();
this.canvas = document.createElement('canvas');
this.gl = this.canvas.getContext('webgl2')!;
this.width = this.canvas.width / devicePixelRatio;
this.height = this.canvas.height / devicePixelRatio;
}
/**
*
*/
size(width: number, height: number) {
let ratio = this.highResolution ? devicePixelRatio : 1;
if (this.autoScale && this.highResolution) {
ratio *= core.domStyle.scale;
}
this.scale = ratio;
this.canvas.width = width * ratio;
this.canvas.height = height * ratio;
this.width = width;
this.height = height;
}
/**
* core.domStyle.scale
*/
withGameScale(auto: boolean) {
this.autoScale = auto;
this.size(this.width, this.height);
}
/**
*
*/
setHD(hd: boolean) {
this.highResolution = hd;
this.size(this.width, this.height);
}
/**
*
*/
delete() {
MotaOffscreenCanvasGL2.list.delete(this);
}
}
export class MotaCanvas2D extends MotaOffscreenCanvas2D {
static map: Map<string, MotaCanvas2D> = new Map();
@ -255,5 +322,12 @@ window.addEventListener('resize', () => {
v.emit('resize');
}
});
MotaOffscreenCanvasGL2.list.forEach(v => {
if (v.autoScale) {
v.size(v.width, v.height);
v.symbol++;
v.emit('resize');
}
});
});
});

View File

@ -6,6 +6,9 @@ import {
isWebGL2Supported
} from './webgl';
import { setCanvasFilterByFloorId } from '@/plugin/fx/gameCanvas';
import { ILayerRenderExtends, Layer } from '../render/preset/layer';
import { HeroRenderer } from '../render/preset/hero';
import { Sprite } from '../render/sprite';
/**
*
@ -70,7 +73,9 @@ function addLightFromBlock(floors: FloorIds[], block: number, config: LightConfi
})
}
Mota.require('var', 'hook').once('reset', () => {
const hook = Mota.require('var', 'hook');
hook.once('reset', () => {
Shadow.init();
addLightFromBlock(
core.floorIds.slice(61, 70).concat(core.floorIds.slice(72, 81)).concat(core.floorIds.slice(85, 103)),
@ -85,48 +90,62 @@ Mota.require('var', 'hook').once('reset', () => {
{ decay: 20, r: 150, color: [0.9333, 0.6, 0.333, 0.4], noShelter: true },
{ background: [0, 0, 0, 0.4] }
);
Shadow.mount();
// Shadow.mount();
// 勇士身上的光源
Mota.rewrite(core.control, 'drawHero', 'add', () => {
if (core.getFlag('__heroOpacity__') !== 0) {
const shadow = Shadow.now();
if (shadow) {
shadow.followHero.forEach(v => {
shadow.modifyLight(v, {
x: core.status.heroCenter.px,
y: core.status.heroCenter.py + 8
});
});
if (shadow.followHero.size > 0) shadow.requestRefresh();
}
}
});
// Mota.rewrite(core.control, 'drawHero', 'add', () => {
// if (core.getFlag('__heroOpacity__') !== 0) {
// const shadow = Shadow.now();
// if (shadow) {
// shadow.followHero.forEach(v => {
// shadow.modifyLight(v, {
// x: core.status.heroCenter.px,
// y: core.status.heroCenter.py + 8
// });
// });
// if (shadow.followHero.size > 0) shadow.requestRefresh();
// }
// }
// });
// 更新地形数据
Mota.rewrite(core.maps, 'removeBlock', 'add', success => {
if (success && !main.replayChecking) {
Shadow.update(true);
}
return success;
});
Mota.rewrite(core.maps, 'setBlock', 'add', () => {
if (!main.replayChecking) {
Shadow.update(true);
}
});
// Mota.rewrite(core.maps, 'removeBlock', 'add', success => {
// if (success && !main.replayChecking) {
// Shadow.update(true);
// }
// return success;
// });
// Mota.rewrite(core.maps, 'setBlock', 'add', () => {
// if (!main.replayChecking) {
// Shadow.update(true);
// }
// });
Mota.rewrite(core.control, 'loadData', 'add', () => {
if (!main.replayChecking) {
Shadow.update(true);
}
});
Mota.require('var', 'hook').on('changingFloor', (floorId) => {
if (!main.replayChecking) {
// Mota.require('var', 'hook').on('changingFloor', (floorId) => {
// if (!main.replayChecking) {
// Shadow.clearBuffer();
// Shadow.update();
// setCanvasFilterByFloorId(floorId);
// }
// })
});
hook.on('reset', () => {
Shadow.update(true);
LayerShadowExtends.shadowList.forEach(v => v.sprite.update(v.sprite));
})
hook.on('setBlock', () => {
Shadow.update(true);
LayerShadowExtends.shadowList.forEach(v => v.sprite.update(v.sprite));
})
hook.on('changingFloor', floorId => {
Shadow.clearBuffer();
Shadow.update();
setCanvasFilterByFloorId(floorId);
}
LayerShadowExtends.shadowList.forEach(v => v.sprite.update(v.sprite));
})
});
// 深度测试着色器
@ -977,6 +996,7 @@ export class Shadow {
color: this.create2DTexture(core._PX_),
blur: this.create2DTexture(core._PX_)
}
this.resizeCanvas();
}
static resize() {
@ -1007,7 +1027,6 @@ export class Shadow {
}
static mount() {
this.resizeCanvas();
core.dom.gameDraw.appendChild(this.canvas);
}
@ -1281,3 +1300,55 @@ export function calMapWalls(floor: FloorIds, nocache: boolean = false) {
}
}
}
export class LayerShadowExtends implements ILayerRenderExtends {
static shadowList: Set<LayerShadowExtends> = new Set();
id: string = 'shadow';
hero!: HeroRenderer
sprite!: Sprite;
private onMoveTick = (x: number, y: number) => {
const now = Shadow.now();
if (!now) return;
if (now.followHero.size === 0) return;
now.followHero.forEach(v => {
now.modifyLight(v, {
x: x * 32 + 16,
y: y * 32 + 16
});
});
now.requestRefresh();
this.sprite.update(this.sprite);
}
private listen() {
this.hero.on('moveTick', this.onMoveTick);
}
awake(layer: Layer): void {
const ex = layer.getExtends('floor-hero');
if (!ex) {
layer.removeExtends('shadow');
logger.error(1101, `Shadow extends needs 'floor-hero' extends as dependency.`);
return;
}
this.hero = ex as HeroRenderer;
this.listen();
LayerShadowExtends.shadowList.add(this);
this.sprite = new Sprite('static', false);
this.sprite.setHD(true);
this.sprite.size(layer.width, layer.height);
this.sprite.setRenderFn((canvas, transform) => {
canvas.ctx.drawImage(Shadow.canvas, 0, 0, layer.width, layer.height);
});
layer.appendChild(this.sprite);
}
onDestroy(layer: Layer): void {
this.hero.off('moveTick', this.onMoveTick);
this.sprite.destroy();
LayerShadowExtends.shadowList.delete(this);
}
}

40
src/core/render/gl.ts Normal file
View File

@ -0,0 +1,40 @@
import { MotaOffscreenCanvas2D, MotaOffscreenCanvasGL2 } from '../fx/canvas2d';
import { RenderItem } from './item';
import { Transform } from './transform';
type GL2RenderFunc = (
canvas: MotaOffscreenCanvasGL2,
transform: Transform
) => void;
export class GL2 extends RenderItem {
canvas: MotaOffscreenCanvasGL2 = new MotaOffscreenCanvasGL2();
/** 渲染函数 */
private renderFn: GL2RenderFunc = () => {};
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {
const gl = this.canvas.gl;
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clearDepth(1);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
this.renderFn(this.canvas, transform);
canvas.ctx.drawImage(this.canvas.canvas, 0, 0, this.width, this.height);
}
/**
* gl2元素的渲染函数
* @param fn
*/
setRenderFn(fn: GL2RenderFunc) {
this.renderFn = fn;
}
}

View File

@ -4,6 +4,7 @@ import { LayerDoorAnimate, LayerGroupFloorBinder } from './preset/floor';
import { HeroRenderer } from './preset/hero';
import { LayerGroup, FloorLayer } from './preset/layer';
import { MotaRenderer } from './render';
import { LayerShadowExtends } from '../fx/shadow';
let main: MotaRenderer;
@ -27,10 +28,12 @@ Mota.require('var', 'loading').once('loaded', () => {
const hero = new HeroRenderer();
const detail = new FloorItemDetail();
const door = new LayerDoorAnimate();
const shadow = new LayerShadowExtends();
layer.extends(damage);
layer.extends(detail);
layer.getLayer('event')?.extends(hero);
layer.getLayer('event')?.extends(door);
layer.getLayer('event')?.extends(shadow);
render.appendChild(layer);
});

View File

@ -12,6 +12,7 @@ type HeroMovingStatus = 'stop' | 'moving' | 'moving-as';
interface HeroRenderEvent {
stepEnd: [];
moveTick: [x: number, y: number];
}
export class HeroRenderer
@ -170,6 +171,7 @@ export class HeroRenderer
this.renderable.x = rx;
this.renderable.y = ry;
}
this.emit('moveTick', this.renderable.x, this.renderable.y);
this.renderable.animate = this.movingFrame;
this.layer.update(this.layer);
}
@ -272,6 +274,7 @@ export class HeroRenderer
if (!isNil(y)) {
this.renderable.y = y;
}
this.emit('moveTick', this.renderable.x, this.renderable.y);
this.layer.update(this.layer);
}
@ -306,6 +309,7 @@ export class HeroRenderer
(a, b) => a.zIndex - b.zIndex
);
}
this.emit('moveTick', this.renderable.x, this.renderable.y);
this.layer.update(this.layer);
},
time,
@ -315,6 +319,7 @@ export class HeroRenderer
this.renderable.animate = 0;
this.renderable.x = x;
this.renderable.y = y;
this.emit('moveTick', this.renderable.x, this.renderable.y);
this.layer.update(this.layer);
res();
}

View File

@ -390,30 +390,6 @@ export function init() {
core.animateFrame.asyncId[animate] = cb;
this._openDoor_animate(block, x, y, callback);
}
// var blockInfo = core.getBlockInfo(block);
// var speed = (doorInfo.time || 160) / 4;
// blockInfo.posX = 3;
// core.maps._drawBlockInfo(blockInfo, x, y);
// var animate = window.setInterval(
// function () {
// blockInfo.posX--;
// if (blockInfo.posX < 0) {
// clearInterval(animate);
// delete core.animateFrame.asyncId[animate];
// cb();
// return;
// }
// core.maps._drawBlockInfo(blockInfo, x, y);
// },
// core.status.replay.speed == 24
// ? 1
// : speed / Math.max(core.status.replay.speed, 1)
// );
// core.animateFrame.lastAsyncId = animate;
// core.animateFrame.asyncId[animate] = cb;
};
});