mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-31 23:29:27 +08:00
fix: 光影效果
This commit is contained in:
parent
053de036ec
commit
27923851bd
@ -1,6 +1,7 @@
|
|||||||
import { parseCss } from '@/plugin/utils';
|
import { parseCss } from '@/plugin/utils';
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import { CSSObj } from '../interface';
|
import { CSSObj } from '../interface';
|
||||||
|
import { isWebGL2Supported } from './webgl';
|
||||||
|
|
||||||
interface OffscreenCanvasEvent {
|
interface OffscreenCanvasEvent {
|
||||||
/** 当被动触发resize时(例如core.domStyle.scale变化、窗口大小变化)时触发,使用size函数并不会触发 */
|
/** 当被动触发resize时(例如core.domStyle.scale变化、窗口大小变化)时触发,使用size函数并不会触发 */
|
||||||
@ -36,8 +37,6 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
|||||||
this.width = this.canvas.width / devicePixelRatio;
|
this.width = this.canvas.width / devicePixelRatio;
|
||||||
this.height = this.canvas.height / devicePixelRatio;
|
this.height = this.canvas.height / devicePixelRatio;
|
||||||
|
|
||||||
this.canvas.style.position = 'absolute';
|
|
||||||
|
|
||||||
MotaOffscreenCanvas2D.list.add(this);
|
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 {
|
export class MotaCanvas2D extends MotaOffscreenCanvas2D {
|
||||||
static map: Map<string, MotaCanvas2D> = new Map();
|
static map: Map<string, MotaCanvas2D> = new Map();
|
||||||
|
|
||||||
@ -255,5 +322,12 @@ window.addEventListener('resize', () => {
|
|||||||
v.emit('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
|
isWebGL2Supported
|
||||||
} from './webgl';
|
} from './webgl';
|
||||||
import { setCanvasFilterByFloorId } from '@/plugin/fx/gameCanvas';
|
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();
|
Shadow.init();
|
||||||
addLightFromBlock(
|
addLightFromBlock(
|
||||||
core.floorIds.slice(61, 70).concat(core.floorIds.slice(72, 81)).concat(core.floorIds.slice(85, 103)),
|
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 },
|
{ decay: 20, r: 150, color: [0.9333, 0.6, 0.333, 0.4], noShelter: true },
|
||||||
{ background: [0, 0, 0, 0.4] }
|
{ background: [0, 0, 0, 0.4] }
|
||||||
);
|
);
|
||||||
Shadow.mount();
|
// Shadow.mount();
|
||||||
|
|
||||||
// 勇士身上的光源
|
// 勇士身上的光源
|
||||||
Mota.rewrite(core.control, 'drawHero', 'add', () => {
|
// Mota.rewrite(core.control, 'drawHero', 'add', () => {
|
||||||
if (core.getFlag('__heroOpacity__') !== 0) {
|
// if (core.getFlag('__heroOpacity__') !== 0) {
|
||||||
const shadow = Shadow.now();
|
// const shadow = Shadow.now();
|
||||||
if (shadow) {
|
// if (shadow) {
|
||||||
shadow.followHero.forEach(v => {
|
// shadow.followHero.forEach(v => {
|
||||||
shadow.modifyLight(v, {
|
// shadow.modifyLight(v, {
|
||||||
x: core.status.heroCenter.px,
|
// x: core.status.heroCenter.px,
|
||||||
y: core.status.heroCenter.py + 8
|
// y: core.status.heroCenter.py + 8
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
if (shadow.followHero.size > 0) shadow.requestRefresh();
|
// if (shadow.followHero.size > 0) shadow.requestRefresh();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
// 更新地形数据
|
// 更新地形数据
|
||||||
Mota.rewrite(core.maps, 'removeBlock', 'add', success => {
|
// Mota.rewrite(core.maps, 'removeBlock', 'add', success => {
|
||||||
if (success && !main.replayChecking) {
|
// if (success && !main.replayChecking) {
|
||||||
Shadow.update(true);
|
// Shadow.update(true);
|
||||||
}
|
// }
|
||||||
return success;
|
// return success;
|
||||||
});
|
// });
|
||||||
Mota.rewrite(core.maps, 'setBlock', 'add', () => {
|
// Mota.rewrite(core.maps, 'setBlock', 'add', () => {
|
||||||
if (!main.replayChecking) {
|
// if (!main.replayChecking) {
|
||||||
Shadow.update(true);
|
// Shadow.update(true);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
Mota.rewrite(core.control, 'loadData', 'add', () => {
|
Mota.rewrite(core.control, 'loadData', 'add', () => {
|
||||||
if (!main.replayChecking) {
|
if (!main.replayChecking) {
|
||||||
Shadow.update(true);
|
Shadow.update(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Mota.require('var', 'hook').on('changingFloor', (floorId) => {
|
// Mota.require('var', 'hook').on('changingFloor', (floorId) => {
|
||||||
if (!main.replayChecking) {
|
// 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.clearBuffer();
|
||||||
Shadow.update();
|
Shadow.update();
|
||||||
setCanvasFilterByFloorId(floorId);
|
setCanvasFilterByFloorId(floorId);
|
||||||
}
|
LayerShadowExtends.shadowList.forEach(v => v.sprite.update(v.sprite));
|
||||||
})
|
})
|
||||||
});
|
|
||||||
|
|
||||||
// 深度测试着色器
|
// 深度测试着色器
|
||||||
|
|
||||||
@ -977,6 +996,7 @@ export class Shadow {
|
|||||||
color: this.create2DTexture(core._PX_),
|
color: this.create2DTexture(core._PX_),
|
||||||
blur: this.create2DTexture(core._PX_)
|
blur: this.create2DTexture(core._PX_)
|
||||||
}
|
}
|
||||||
|
this.resizeCanvas();
|
||||||
}
|
}
|
||||||
|
|
||||||
static resize() {
|
static resize() {
|
||||||
@ -1007,7 +1027,6 @@ export class Shadow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static mount() {
|
static mount() {
|
||||||
this.resizeCanvas();
|
|
||||||
core.dom.gameDraw.appendChild(this.canvas);
|
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 { HeroRenderer } from './preset/hero';
|
||||||
import { LayerGroup, FloorLayer } from './preset/layer';
|
import { LayerGroup, FloorLayer } from './preset/layer';
|
||||||
import { MotaRenderer } from './render';
|
import { MotaRenderer } from './render';
|
||||||
|
import { LayerShadowExtends } from '../fx/shadow';
|
||||||
|
|
||||||
let main: MotaRenderer;
|
let main: MotaRenderer;
|
||||||
|
|
||||||
@ -27,10 +28,12 @@ Mota.require('var', 'loading').once('loaded', () => {
|
|||||||
const hero = new HeroRenderer();
|
const hero = new HeroRenderer();
|
||||||
const detail = new FloorItemDetail();
|
const detail = new FloorItemDetail();
|
||||||
const door = new LayerDoorAnimate();
|
const door = new LayerDoorAnimate();
|
||||||
|
const shadow = new LayerShadowExtends();
|
||||||
layer.extends(damage);
|
layer.extends(damage);
|
||||||
layer.extends(detail);
|
layer.extends(detail);
|
||||||
layer.getLayer('event')?.extends(hero);
|
layer.getLayer('event')?.extends(hero);
|
||||||
layer.getLayer('event')?.extends(door);
|
layer.getLayer('event')?.extends(door);
|
||||||
|
layer.getLayer('event')?.extends(shadow);
|
||||||
|
|
||||||
render.appendChild(layer);
|
render.appendChild(layer);
|
||||||
});
|
});
|
||||||
|
@ -12,6 +12,7 @@ type HeroMovingStatus = 'stop' | 'moving' | 'moving-as';
|
|||||||
|
|
||||||
interface HeroRenderEvent {
|
interface HeroRenderEvent {
|
||||||
stepEnd: [];
|
stepEnd: [];
|
||||||
|
moveTick: [x: number, y: number];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HeroRenderer
|
export class HeroRenderer
|
||||||
@ -170,6 +171,7 @@ export class HeroRenderer
|
|||||||
this.renderable.x = rx;
|
this.renderable.x = rx;
|
||||||
this.renderable.y = ry;
|
this.renderable.y = ry;
|
||||||
}
|
}
|
||||||
|
this.emit('moveTick', this.renderable.x, this.renderable.y);
|
||||||
this.renderable.animate = this.movingFrame;
|
this.renderable.animate = this.movingFrame;
|
||||||
this.layer.update(this.layer);
|
this.layer.update(this.layer);
|
||||||
}
|
}
|
||||||
@ -272,6 +274,7 @@ export class HeroRenderer
|
|||||||
if (!isNil(y)) {
|
if (!isNil(y)) {
|
||||||
this.renderable.y = y;
|
this.renderable.y = y;
|
||||||
}
|
}
|
||||||
|
this.emit('moveTick', this.renderable.x, this.renderable.y);
|
||||||
this.layer.update(this.layer);
|
this.layer.update(this.layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,6 +309,7 @@ export class HeroRenderer
|
|||||||
(a, b) => a.zIndex - b.zIndex
|
(a, b) => a.zIndex - b.zIndex
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
this.emit('moveTick', this.renderable.x, this.renderable.y);
|
||||||
this.layer.update(this.layer);
|
this.layer.update(this.layer);
|
||||||
},
|
},
|
||||||
time,
|
time,
|
||||||
@ -315,6 +319,7 @@ export class HeroRenderer
|
|||||||
this.renderable.animate = 0;
|
this.renderable.animate = 0;
|
||||||
this.renderable.x = x;
|
this.renderable.x = x;
|
||||||
this.renderable.y = y;
|
this.renderable.y = y;
|
||||||
|
this.emit('moveTick', this.renderable.x, this.renderable.y);
|
||||||
this.layer.update(this.layer);
|
this.layer.update(this.layer);
|
||||||
res();
|
res();
|
||||||
}
|
}
|
||||||
|
@ -390,30 +390,6 @@ export function init() {
|
|||||||
core.animateFrame.asyncId[animate] = cb;
|
core.animateFrame.asyncId[animate] = cb;
|
||||||
this._openDoor_animate(block, x, y, callback);
|
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