mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-31 15:09:26 +08:00
fix: 光影效果
This commit is contained in:
parent
053de036ec
commit
27923851bd
@ -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');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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) {
|
||||
Shadow.clearBuffer();
|
||||
Shadow.update();
|
||||
setCanvasFilterByFloorId(floorId);
|
||||
}
|
||||
})
|
||||
// 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
40
src/core/render/gl.ts
Normal 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user