mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-04-28 18:23:25 +08:00
Compare commits
2 Commits
19a0c29015
...
6f10ac3d81
Author | SHA1 | Date | |
---|---|---|---|
6f10ac3d81 | |||
b9f4804c8c |
@ -97,10 +97,10 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
|
|||||||
|
|
||||||
Mota.require('var', 'loading').once('loaded', () => {
|
Mota.require('var', 'loading').once('loaded', () => {
|
||||||
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
|
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
|
||||||
// @ts-ignore
|
// @ts-expect-error 无法推导
|
||||||
this.idNumberMap = {};
|
this.idNumberMap = {};
|
||||||
for (const [key, { id }] of Object.entries(map)) {
|
for (const [key, { id }] of Object.entries(map)) {
|
||||||
// @ts-ignore
|
// @ts-expect-error 无法推导
|
||||||
this.idNumberMap[id] = parseInt(key) as AllNumbers;
|
this.idNumberMap[id] = parseInt(key) as AllNumbers;
|
||||||
}
|
}
|
||||||
this.tileset = core.material.images.tilesets;
|
this.tileset = core.material.images.tilesets;
|
||||||
@ -128,7 +128,7 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
|
|||||||
*/
|
*/
|
||||||
private calRenderable() {
|
private calRenderable() {
|
||||||
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
|
const map = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
|
||||||
for (const [key, data] of Object.entries(map)) {
|
for (const key of Object.keys(map)) {
|
||||||
this.calRenderableByNum(parseInt(key));
|
this.calRenderableByNum(parseInt(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,7 +167,8 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
|
|||||||
const data = map[num as Exclude<AllNumbers, 0>];
|
const data = map[num as Exclude<AllNumbers, 0>];
|
||||||
// 地狱般的分支if
|
// 地狱般的分支if
|
||||||
if (data) {
|
if (data) {
|
||||||
let { cls, faceIds, bigImage, id, animate } = data;
|
let { faceIds, bigImage } = data;
|
||||||
|
const { cls, id, animate } = data;
|
||||||
if (cls === 'enemys' || cls === 'enemy48') {
|
if (cls === 'enemys' || cls === 'enemy48') {
|
||||||
// 怪物需要特殊处理,因为它的大怪物信息不在 maps 里面
|
// 怪物需要特殊处理,因为它的大怪物信息不在 maps 里面
|
||||||
({ bigImage, faceIds } = enemys[id as EnemyIds]);
|
({ bigImage, faceIds } = enemys[id as EnemyIds]);
|
||||||
@ -212,7 +213,7 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
|
|||||||
if (cls === 'enemy48' || cls === 'npc48') {
|
if (cls === 'enemy48' || cls === 'npc48') {
|
||||||
const img = core.material.images[cls];
|
const img = core.material.images[cls];
|
||||||
if (!img) return null;
|
if (!img) return null;
|
||||||
// @ts-ignore
|
// @ts-expect-error 无法推导
|
||||||
const line = icons[cls][id];
|
const line = icons[cls][id];
|
||||||
const w = 32;
|
const w = 32;
|
||||||
const h = 48;
|
const h = 48;
|
||||||
@ -269,7 +270,7 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
|
|||||||
if (!image) return null;
|
if (!image) return null;
|
||||||
const frame = core.getAnimateFrames(cls);
|
const frame = core.getAnimateFrames(cls);
|
||||||
const cell = 32;
|
const cell = 32;
|
||||||
// @ts-ignore
|
// @ts-expect-error 无法推导
|
||||||
const offset = (icons[cls][id] as number) * cell;
|
const offset = (icons[cls][id] as number) * cell;
|
||||||
const render: [number, number, number, number][] = [
|
const render: [number, number, number, number][] = [
|
||||||
[0, offset, cell, cell]
|
[0, offset, cell, cell]
|
||||||
|
52
src/core/render/frame.ts
Normal file
52
src/core/render/frame.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import EventEmitter from 'eventemitter3';
|
||||||
|
import { RenderItem } from './item';
|
||||||
|
|
||||||
|
export interface IAnimateFrame {
|
||||||
|
updateFrameAnimate(frame: number, time: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
RenderItem.ticker.add(time => {
|
||||||
|
if (!core.isPlaying()) return;
|
||||||
|
if (time - lastTime > core.values.animateSpeed) {
|
||||||
|
RenderItem.animatedFrame++;
|
||||||
|
lastTime = time;
|
||||||
|
renderEmits.emitAnimateFrame(RenderItem.animatedFrame, time);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
@ -184,62 +184,66 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
|
|||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setHD(hd: boolean): void {
|
||||||
|
super.setHD(hd);
|
||||||
|
this.sizeGL(this.width, this.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
size(width: number, height: number): void {
|
||||||
|
super.size(width, height);
|
||||||
|
this.sizeGL(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sizeGL(width: number, height: number) {
|
||||||
|
const ratio = this.highResolution ? devicePixelRatio : 1;
|
||||||
|
const scale = ratio * core.domStyle.scale;
|
||||||
|
this.canvas.width = width * scale;
|
||||||
|
this.canvas.height = height * scale;
|
||||||
|
}
|
||||||
|
|
||||||
protected render(
|
protected render(
|
||||||
canvas: MotaOffscreenCanvas2D,
|
canvas: MotaOffscreenCanvas2D,
|
||||||
transform: Transform
|
transform: Transform
|
||||||
): void {
|
): void {
|
||||||
if (!GL2.support || !this.program) return;
|
if (!GL2.support || !this.program || !this.gl) return;
|
||||||
const compile = this.program.requestCompile();
|
const compile = this.program.requestCompile();
|
||||||
if (compile) {
|
if (compile) {
|
||||||
this.gl.useProgram(this.program.program);
|
this.gl.useProgram(this.program.program);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.cacheDirty) {
|
if (this.cacheDirty) {
|
||||||
this.drawScene(canvas, transform);
|
// 清空画布
|
||||||
|
const gl = this.gl;
|
||||||
|
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
gl.clearColor(0, 0, 0, 0);
|
||||||
|
gl.clearDepth(1);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||||
|
this.drawScene(canvas, gl, this.program, transform);
|
||||||
this.cacheDirty = false;
|
this.cacheDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.ctx.drawImage(this.canvas, 0, 0, this.width, this.height);
|
canvas.ctx.drawImage(this.canvas, 0, 0, this.width, this.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawScene(canvas: MotaOffscreenCanvas2D, transform: Transform) {
|
/**
|
||||||
const gl = this.gl;
|
* 渲染当前 gl2 画布
|
||||||
const program = this.program;
|
* @param canvas 渲染至的目标画布,注意系统会自动将 gl2 画布渲染至目标画布,不需要手动画到该画布上
|
||||||
if (!gl || !program) return;
|
* @param gl 当前正在渲染的 gl2 画布
|
||||||
const ready = program.ready();
|
* @param program 当前元素正在使用的着色器程序
|
||||||
if (!ready) return;
|
* @param transform 当前元素相对父元素的变换矩阵
|
||||||
|
*/
|
||||||
// 清空画布
|
protected abstract drawScene(
|
||||||
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
||||||
gl.clearColor(0, 0, 0, 0);
|
|
||||||
gl.clearDepth(1);
|
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
||||||
|
|
||||||
const pre = this.preDraw(canvas, transform, gl, program);
|
|
||||||
if (!pre) {
|
|
||||||
this.postDraw(canvas, transform, gl, program);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.draw(gl, program);
|
|
||||||
|
|
||||||
this.postDraw(canvas, transform, gl, program);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract preDraw(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
canvas: MotaOffscreenCanvas2D,
|
||||||
transform: Transform,
|
|
||||||
gl: WebGL2RenderingContext,
|
gl: WebGL2RenderingContext,
|
||||||
program: GL2Program
|
program: GL2Program,
|
||||||
): boolean;
|
transform: Transform
|
||||||
|
|
||||||
protected abstract postDraw(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
transform: Transform,
|
|
||||||
gl: WebGL2RenderingContext,
|
|
||||||
program: GL2Program
|
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行顶点绘制
|
||||||
|
* @param gl 当前正在渲染的 gl2 画布
|
||||||
|
* @param program 当前元素正在使用的着色器程序
|
||||||
|
*/
|
||||||
draw(gl: WebGL2RenderingContext, program: GL2Program) {
|
draw(gl: WebGL2RenderingContext, program: GL2Program) {
|
||||||
const indices = program.usingIndices;
|
const indices = program.usingIndices;
|
||||||
const param = program.getDrawParams(program.renderMode);
|
const param = program.getDrawParams(program.renderMode);
|
||||||
@ -1675,7 +1679,7 @@ export class GL2Program extends EventEmitter<ShaderProgramEvent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 摧毁这个着色器程序,不要直接调用,请使用 {@link Shader.deleteProgram} 来删除一个着色器程序
|
* 摧毁这个着色器程序,不要直接调用,请使用 {@link GL2.deleteProgram} 来删除一个着色器程序
|
||||||
*/
|
*/
|
||||||
destroy() {
|
destroy() {
|
||||||
this.clearProgram();
|
this.clearProgram();
|
||||||
|
@ -100,5 +100,3 @@ export * from './render';
|
|||||||
export * from './shader';
|
export * from './shader';
|
||||||
export * from './sprite';
|
export * from './sprite';
|
||||||
export * from './transform';
|
export * from './transform';
|
||||||
export * from './utils';
|
|
||||||
export * from '../../module/ui/components';
|
|
||||||
|
@ -5,6 +5,7 @@ import { Ticker, TickerFn } from 'mutate-animate';
|
|||||||
import { Transform } from './transform';
|
import { Transform } from './transform';
|
||||||
import { logger } from '../common/logger';
|
import { logger } from '../common/logger';
|
||||||
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
||||||
|
import { transformCanvas } from './utils';
|
||||||
|
|
||||||
export type RenderFunction = (
|
export type RenderFunction = (
|
||||||
canvas: MotaOffscreenCanvas2D,
|
canvas: MotaOffscreenCanvas2D,
|
||||||
@ -21,7 +22,7 @@ export interface IRenderUpdater {
|
|||||||
update(item?: RenderItem): void;
|
update(item?: RenderItem): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IRenderAnchor {
|
export interface IRenderAnchor {
|
||||||
/** 锚点横坐标,0表示最左端,1表示最右端 */
|
/** 锚点横坐标,0表示最左端,1表示最右端 */
|
||||||
anchorX: number;
|
anchorX: number;
|
||||||
/** 锚点纵坐标,0表示最上端,1表示最下端 */
|
/** 锚点纵坐标,0表示最上端,1表示最下端 */
|
||||||
@ -35,7 +36,7 @@ interface IRenderAnchor {
|
|||||||
setAnchor(x: number, y: number): void;
|
setAnchor(x: number, y: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IRenderConfig {
|
export interface IRenderConfig {
|
||||||
/** 是否是高清画布 */
|
/** 是否是高清画布 */
|
||||||
highResolution: boolean;
|
highResolution: boolean;
|
||||||
/** 是否启用抗锯齿 */
|
/** 是否启用抗锯齿 */
|
||||||
@ -76,7 +77,7 @@ export interface IRenderChildable {
|
|||||||
requestSort(): void;
|
requestSort(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IRenderFrame {
|
export interface IRenderFrame {
|
||||||
/**
|
/**
|
||||||
* 在下一帧渲染之前执行函数,常用于渲染前数据更新,理论上不应当用于渲染,不保证运行顺序
|
* 在下一帧渲染之前执行函数,常用于渲染前数据更新,理论上不应当用于渲染,不保证运行顺序
|
||||||
* @param fn 执行的函数
|
* @param fn 执行的函数
|
||||||
@ -96,7 +97,7 @@ interface IRenderFrame {
|
|||||||
requestRenderFrame(fn: () => void): void;
|
requestRenderFrame(fn: () => void): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IRenderTickerSupport {
|
export interface IRenderTickerSupport {
|
||||||
/**
|
/**
|
||||||
* 委托ticker,让其在指定时间范围内每帧执行对应函数,超过时间后自动删除
|
* 委托ticker,让其在指定时间范围内每帧执行对应函数,超过时间后自动删除
|
||||||
* @param fn 每帧执行的函数
|
* @param fn 每帧执行的函数
|
||||||
@ -121,7 +122,7 @@ interface IRenderTickerSupport {
|
|||||||
hasTicker(id: number): boolean;
|
hasTicker(id: number): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IRenderVueSupport {
|
export interface IRenderVueSupport {
|
||||||
/**
|
/**
|
||||||
* 在 jsx, vue 中当属性改变后触发此函数,用于处理响应式等情况
|
* 在 jsx, vue 中当属性改变后触发此函数,用于处理响应式等情况
|
||||||
* @param key 属性键名
|
* @param key 属性键名
|
||||||
@ -139,12 +140,114 @@ interface IRenderVueSupport {
|
|||||||
): void;
|
): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum MouseType {
|
||||||
|
/** 没有按键按下 */
|
||||||
|
None = 0,
|
||||||
|
/** 左键 */
|
||||||
|
Left = 1 << 0,
|
||||||
|
/** 中键,即按下滚轮 */
|
||||||
|
Middle = 1 << 1,
|
||||||
|
/** 右键 */
|
||||||
|
Right = 1 << 2,
|
||||||
|
/** 侧键后退 */
|
||||||
|
Back = 1 << 3,
|
||||||
|
/** 侧键前进 */
|
||||||
|
Forward = 1 << 4
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum WheelType {
|
||||||
|
None,
|
||||||
|
/** 以像素为单位 */
|
||||||
|
Pixel,
|
||||||
|
/** 以行为单位,每行长度视浏览器设置而定,约为 1rem */
|
||||||
|
Line,
|
||||||
|
/** 以页为单位,一般为一个屏幕高度 */
|
||||||
|
Page
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IActionEvent {
|
||||||
|
/** 当前事件是监听的哪个元素 */
|
||||||
|
readonly target: RenderItem;
|
||||||
|
/** 这次操作的标识符,在按下、移动、抬起阶段中保持不变 */
|
||||||
|
readonly identifier: number;
|
||||||
|
/** 相对于触发元素左上角的横坐标 */
|
||||||
|
readonly offsetX: number;
|
||||||
|
/** 相对于触发元素左上角的纵坐标 */
|
||||||
|
readonly offsetY: number;
|
||||||
|
/** 相对于整个画布左上角的横坐标 */
|
||||||
|
readonly absoluteX: number;
|
||||||
|
/** 相对于整个画布左上角的纵坐标 */
|
||||||
|
readonly absoluteY: number;
|
||||||
|
/**
|
||||||
|
* 触发的按键种类,会出现在点击、按下、抬起三个事件中,而其他的如移动等该值只会是 {@link MouseType.None},
|
||||||
|
* 电脑端可以有左键、中键、右键等,手机只会触发左键,每一项的值参考 {@link MouseType}
|
||||||
|
*/
|
||||||
|
readonly type: MouseType;
|
||||||
|
/**
|
||||||
|
* 当前按下了哪些按键。该值是一个数字,可以通过位运算判断是否按下了某个按键。
|
||||||
|
* 例如通过 `buttons & MouseType.Left` 来判断是否按下了左键。
|
||||||
|
*/
|
||||||
|
readonly buttons: number;
|
||||||
|
/** 触发时是否按下了 alt 键 */
|
||||||
|
readonly altKey: boolean;
|
||||||
|
/** 触发时是否按下了 shift 键 */
|
||||||
|
readonly shiftKey: boolean;
|
||||||
|
/** 触发时是否按下了 ctrl 键 */
|
||||||
|
readonly ctrlKey: boolean;
|
||||||
|
/** 触发时是否按下了 Windows(Windows) / Command(Mac) 键 */
|
||||||
|
readonly metaKey: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用后将停止事件的继续传播。
|
||||||
|
* 在捕获阶段,将会阻止捕获的进一步进行,在冒泡阶段,将会阻止冒泡的进一步进行。
|
||||||
|
* 如果当前元素有很多监听器,该方法并不会阻止其他监听器的执行。
|
||||||
|
*/
|
||||||
|
stopPropagation(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IWheelEvent extends IActionEvent {
|
||||||
|
/** 滚轮事件的鼠标横向滚动量 */
|
||||||
|
readonly wheelX: number;
|
||||||
|
/** 滚轮事件的鼠标纵向滚动量 */
|
||||||
|
readonly wheelY: number;
|
||||||
|
/** 滚轮事件的鼠标垂直屏幕的滚动量 */
|
||||||
|
readonly wheelZ: number;
|
||||||
|
/** 滚轮事件的滚轮类型,表示了对应值的单位 */
|
||||||
|
readonly wheelType: WheelType;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ERenderItemEvent {
|
export interface ERenderItemEvent {
|
||||||
beforeRender: [transform: Transform];
|
beforeRender: [transform: Transform];
|
||||||
afterRender: [transform: Transform];
|
afterRender: [transform: Transform];
|
||||||
destroy: [];
|
destroy: [];
|
||||||
/** 当这个元素被点击时触发 */
|
/** 当这个元素被点击时的捕获阶段触发 */
|
||||||
clickCapture: [x: number, y: number, type: number, ev: MouseEvent];
|
clickCapture: [ev: IActionEvent];
|
||||||
|
/** 当这个元素被点击时的冒泡阶段触发 */
|
||||||
|
click: [ev: IActionEvent];
|
||||||
|
/** 当鼠标或手指在该元素上按下的捕获阶段触发 */
|
||||||
|
downCapture: [ev: IActionEvent];
|
||||||
|
/** 当鼠标或手指在该元素上按下的冒泡阶段触发 */
|
||||||
|
down: [ev: IActionEvent];
|
||||||
|
/** 当鼠标或手指在该元素上移动的捕获阶段触发 */
|
||||||
|
moveCapture: [ev: IActionEvent];
|
||||||
|
/** 当鼠标或手指在该元素上移动的冒泡阶段触发 */
|
||||||
|
move: [ev: IActionEvent];
|
||||||
|
/** 当鼠标或手指在该元素上抬起的捕获阶段触发 */
|
||||||
|
upCapture: [ev: IActionEvent];
|
||||||
|
/** 当鼠标或手指在该元素上抬起的冒泡阶段触发 */
|
||||||
|
up: [ev: IActionEvent];
|
||||||
|
/** 当鼠标或手指进入该元素的捕获阶段触发 */
|
||||||
|
enterCapture: [ev: IActionEvent];
|
||||||
|
/** 当鼠标或手指进入该元素的冒泡阶段触发 */
|
||||||
|
enter: [ev: IActionEvent];
|
||||||
|
/** 当鼠标或手指离开该元素的捕获阶段触发 */
|
||||||
|
leaveCapture: [ev: IActionEvent];
|
||||||
|
/** 当鼠标或手指离开该元素的冒泡阶段触发 */
|
||||||
|
leave: [ev: IActionEvent];
|
||||||
|
/** 当鼠标滚轮时的捕获阶段触发 */
|
||||||
|
wheelCapture: [ev: IWheelEvent];
|
||||||
|
/** 当鼠标滚轮时的冒泡阶段触发 */
|
||||||
|
wheel: [ev: IWheelEvent];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TickerDelegation {
|
interface TickerDelegation {
|
||||||
@ -205,8 +308,9 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
|||||||
width: number = 200;
|
width: number = 200;
|
||||||
height: number = 200;
|
height: number = 200;
|
||||||
|
|
||||||
// 渲染锚点,(0,0)表示左上角,(1,1)表示右下角
|
/** 渲染锚点,(0,0)表示左上角,(1,1)表示右下角 */
|
||||||
anchorX: number = 0;
|
anchorX: number = 0;
|
||||||
|
/** 渲染锚点,(0,0)表示左上角,(1,1)表示右下角 */
|
||||||
anchorY: number = 0;
|
anchorY: number = 0;
|
||||||
|
|
||||||
/** 渲染模式,absolute表示绝对位置,static表示跟随摄像机移动 */
|
/** 渲染模式,absolute表示绝对位置,static表示跟随摄像机移动 */
|
||||||
@ -740,63 +844,3 @@ RenderItem.ticker.add(time => {
|
|||||||
arr.forEach(v => v());
|
arr.forEach(v => v());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export interface IAnimateFrame {
|
|
||||||
updateFrameAnimate(frame: number, time: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
RenderItem.ticker.add(time => {
|
|
||||||
if (!core.isPlaying()) return;
|
|
||||||
if (time - lastTime > core.values.animateSpeed) {
|
|
||||||
RenderItem.animatedFrame++;
|
|
||||||
lastTime = time;
|
|
||||||
renderEmits.emitAnimateFrame(RenderItem.animatedFrame, time);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export function transformCanvas(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
transform: Transform
|
|
||||||
) {
|
|
||||||
const { ctx } = canvas;
|
|
||||||
const mat = transform.mat;
|
|
||||||
const [a, b, , c, d, , e, f] = mat;
|
|
||||||
ctx.transform(a, b, c, d, e, f);
|
|
||||||
}
|
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
import { logger } from '../common/logger';
|
|
||||||
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
|
||||||
|
|
||||||
export class CanvasPool {
|
|
||||||
private pool: MotaOffscreenCanvas2D[] = [];
|
|
||||||
private requested: Set<MotaOffscreenCanvas2D> = new Set();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 申请画布
|
|
||||||
* @param num 要申请多少画布
|
|
||||||
*/
|
|
||||||
requestCanvas(num: number): MotaOffscreenCanvas2D[] {
|
|
||||||
if (this.pool.length < num) {
|
|
||||||
const diff = num - this.pool.length;
|
|
||||||
for (let i = 0; i < diff; i++) {
|
|
||||||
this.pool.push(new MotaOffscreenCanvas2D(false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const toProvide = this.pool.splice(0, num);
|
|
||||||
toProvide.forEach(v => this.requested.add(v));
|
|
||||||
return toProvide;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退回画布
|
|
||||||
* @param canvas 要退回多少画布
|
|
||||||
*/
|
|
||||||
returnCanvas(canvas: MotaOffscreenCanvas2D[]) {
|
|
||||||
canvas.forEach(v => {
|
|
||||||
if (!this.requested.has(v)) {
|
|
||||||
logger.warn(40);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.requested.delete(v);
|
|
||||||
this.pool.push(v);
|
|
||||||
v.clear();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
this.pool.forEach(v => v.delete());
|
|
||||||
this.requested.forEach(v => v.delete());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,10 @@
|
|||||||
import { logger } from '@/core/common/logger';
|
|
||||||
import { RenderAdapter } from '../adapter';
|
import { RenderAdapter } from '../adapter';
|
||||||
import { Sprite } from '../sprite';
|
|
||||||
import { HeroRenderer } from './hero';
|
import { HeroRenderer } from './hero';
|
||||||
import { ILayerGroupRenderExtends, LayerGroup } from './layer';
|
import { ILayerGroupRenderExtends, LayerGroup } from './layer';
|
||||||
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
||||||
import { ERenderItemEvent, RenderItem, transformCanvas } from '../item';
|
import { ERenderItemEvent, RenderItem } from '../item';
|
||||||
import { Transform } from '../transform';
|
import { Transform } from '../transform';
|
||||||
|
import { transformCanvas } from '../utils';
|
||||||
|
|
||||||
export class LayerGroupAnimate implements ILayerGroupRenderExtends {
|
export class LayerGroupAnimate implements ILayerGroupRenderExtends {
|
||||||
static animateList: Set<LayerGroupAnimate> = new Set();
|
static animateList: Set<LayerGroupAnimate> = new Set();
|
||||||
|
@ -6,13 +6,7 @@ import {
|
|||||||
Layer,
|
Layer,
|
||||||
LayerGroup
|
LayerGroup
|
||||||
} from './layer';
|
} from './layer';
|
||||||
import { ESpriteEvent, Sprite } from '../sprite';
|
import { BlockCacher, CanvasCacheItem, ICanvasCacheItem } from './block';
|
||||||
import {
|
|
||||||
BlockCacher,
|
|
||||||
CanvasCacheItem,
|
|
||||||
IBlockCacheable,
|
|
||||||
ICanvasCacheItem
|
|
||||||
} from './block';
|
|
||||||
import type {
|
import type {
|
||||||
DamageEnemy,
|
DamageEnemy,
|
||||||
EnemyCollection,
|
EnemyCollection,
|
||||||
@ -21,10 +15,11 @@ import type {
|
|||||||
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
import { getDamageColor } from '@/plugin/utils';
|
import { getDamageColor } from '@/plugin/utils';
|
||||||
import { ERenderItemEvent, RenderItem, transformCanvas } from '../item';
|
import { ERenderItemEvent, RenderItem } from '../item';
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
import { Transform } from '../transform';
|
import { Transform } from '../transform';
|
||||||
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
||||||
|
import { transformCanvas } from '../utils';
|
||||||
|
|
||||||
const ensureFloorDamage = Mota.require('fn', 'ensureFloorDamage');
|
const ensureFloorDamage = Mota.require('fn', 'ensureFloorDamage');
|
||||||
|
|
||||||
@ -75,22 +70,22 @@ export class FloorDamageExtends
|
|||||||
this.update(floor);
|
this.update(floor);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onSetBlock = (x: number, y: number, floor: FloorIds) => {
|
// private onSetBlock = (x: number, y: number, floor: FloorIds) => {
|
||||||
// this.sprite.enemy?.once('extract', () => {
|
// this.sprite.enemy?.once('extract', () => {
|
||||||
// if (floor !== this.sprite.enemy?.floorId) return;
|
// if (floor !== this.sprite.enemy?.floorId) return;
|
||||||
// this.sprite.updateBlocks();
|
// this.sprite.updateBlocks();
|
||||||
// });
|
// });
|
||||||
// if (!this.floorBinder.bindThisFloor) {
|
// if (!this.floorBinder.bindThisFloor) {
|
||||||
// this.sprite.enemy?.extract();
|
// this.sprite.enemy?.extract();
|
||||||
// }
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 进行楼层更新监听
|
* 进行楼层更新监听
|
||||||
*/
|
*/
|
||||||
private listen() {
|
private listen() {
|
||||||
this.floorBinder.on('update', this.onUpdate);
|
this.floorBinder.on('update', this.onUpdate);
|
||||||
this.floorBinder.on('setBlock', this.onSetBlock);
|
// this.floorBinder.on('setBlock', this.onSetBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
awake(group: LayerGroup): void {
|
awake(group: LayerGroup): void {
|
||||||
@ -106,9 +101,9 @@ export class FloorDamageExtends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(group: LayerGroup): void {
|
onDestroy(_group: LayerGroup): void {
|
||||||
this.floorBinder.off('update', this.onUpdate);
|
this.floorBinder.off('update', this.onUpdate);
|
||||||
this.floorBinder.off('setBlock', this.onSetBlock);
|
// this.floorBinder.off('setBlock', this.onSetBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,7 +254,7 @@ export class Damage extends RenderItem<EDamageEvent> {
|
|||||||
blocks.forEach(v => this.dirtyBlocks.add(v));
|
blocks.forEach(v => this.dirtyBlocks.add(v));
|
||||||
this.emit('updateBlocks', blocks);
|
this.emit('updateBlocks', blocks);
|
||||||
} else {
|
} else {
|
||||||
this.blockData.forEach((v, i) => {
|
this.blockData.forEach((_v, i) => {
|
||||||
this.dirtyBlocks.add(i);
|
this.dirtyBlocks.add(i);
|
||||||
});
|
});
|
||||||
this.emit('updateBlocks', new Set(this.blockData.keys()));
|
this.emit('updateBlocks', new Set(this.blockData.keys()));
|
||||||
@ -473,7 +468,6 @@ export class Damage extends RenderItem<EDamageEvent> {
|
|||||||
// console.time('damage');
|
// console.time('damage');
|
||||||
const { ctx } = canvas;
|
const { ctx } = canvas;
|
||||||
transformCanvas(canvas, transform);
|
transformCanvas(canvas, transform);
|
||||||
// console.trace();
|
|
||||||
|
|
||||||
const render = this.calNeedRender(transform);
|
const render = this.calNeedRender(transform);
|
||||||
const block = this.block;
|
const block = this.block;
|
||||||
|
@ -170,7 +170,7 @@ export class LayerGroupFloorBinder
|
|||||||
LayerGroupFloorBinder.activedBinder.add(this);
|
LayerGroupFloorBinder.activedBinder.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onLayerAdd(group: LayerGroup, layer: Layer): void {
|
onLayerAdd(_group: LayerGroup, layer: Layer): void {
|
||||||
this.checkLayerExtends(layer);
|
this.checkLayerExtends(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,7 +300,7 @@ export class LayerFloorBinder implements ILayerRenderExtends {
|
|||||||
this.checkListen();
|
this.checkListen();
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(layer: Layer) {
|
onDestroy(_layer: Layer) {
|
||||||
LayerFloorBinder.listenedBinder.delete(this);
|
LayerFloorBinder.listenedBinder.delete(this);
|
||||||
this.parent?.layerBinders.delete(this);
|
this.parent?.layerBinders.delete(this);
|
||||||
}
|
}
|
||||||
@ -397,11 +397,11 @@ export class LayerDoorAnimate implements ILayerRenderExtends {
|
|||||||
doorAdapter.add(this);
|
doorAdapter.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMovingUpdate(layer: Layer, renderable: LayerMovingRenderable[]): void {
|
onMovingUpdate(_layer: Layer, renderable: LayerMovingRenderable[]): void {
|
||||||
renderable.push(...this.moving);
|
renderable.push(...this.moving);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(layer: Layer): void {
|
onDestroy(_layer: Layer): void {
|
||||||
doorAdapter.remove(this);
|
doorAdapter.remove(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -354,8 +354,8 @@ export class HeroRenderer
|
|||||||
moveAs(x: number, y: number, time: number, fn: TimingFn<3>): Promise<void> {
|
moveAs(x: number, y: number, time: number, fn: TimingFn<3>): Promise<void> {
|
||||||
if (!this.moving) return Promise.resolve();
|
if (!this.moving) return Promise.resolve();
|
||||||
if (!this.renderable) return Promise.resolve();
|
if (!this.renderable) return Promise.resolve();
|
||||||
let nowZIndex = fn(0)[2];
|
const nowZIndex = fn(0)[2];
|
||||||
let startTime = Date.now();
|
const startTime = Date.now();
|
||||||
return new Promise(res => {
|
return new Promise(res => {
|
||||||
this.layer.delegateTicker(
|
this.layer.delegateTicker(
|
||||||
() => {
|
() => {
|
||||||
@ -414,7 +414,7 @@ export class HeroRenderer
|
|||||||
layer.removeTicker(this.moveId);
|
layer.removeTicker(this.moveId);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMovingUpdate(layer: Layer, renderable: LayerMovingRenderable[]): void {
|
onMovingUpdate(_layer: Layer, renderable: LayerMovingRenderable[]): void {
|
||||||
if (this.renderable) {
|
if (this.renderable) {
|
||||||
renderable.push(this.renderable);
|
renderable.push(this.renderable);
|
||||||
this.emit('append', renderable);
|
this.emit('append', renderable);
|
||||||
|
@ -2,7 +2,7 @@ import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
|||||||
import { Container, EContainerEvent } from '../container';
|
import { Container, EContainerEvent } from '../container';
|
||||||
import { Sprite } from '../sprite';
|
import { Sprite } from '../sprite';
|
||||||
import { TimingFn } from 'mutate-animate';
|
import { TimingFn } from 'mutate-animate';
|
||||||
import { IAnimateFrame, renderEmits, RenderItem } from '../item';
|
import { RenderItem } from '../item';
|
||||||
import { logger } from '@/core/common/logger';
|
import { logger } from '@/core/common/logger';
|
||||||
import { RenderableData, texture } from '../cache';
|
import { RenderableData, texture } from '../cache';
|
||||||
import { BlockCacher, CanvasCacheItem, ICanvasCacheItem } from './block';
|
import { BlockCacher, CanvasCacheItem, ICanvasCacheItem } from './block';
|
||||||
@ -11,6 +11,7 @@ import { LayerFloorBinder, LayerGroupFloorBinder } from './floor';
|
|||||||
import { RenderAdapter } from '../adapter';
|
import { RenderAdapter } from '../adapter';
|
||||||
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
||||||
import { Camera } from '../camera';
|
import { Camera } from '../camera';
|
||||||
|
import { IAnimateFrame, renderEmits } from '../frame';
|
||||||
|
|
||||||
export interface ILayerGroupRenderExtends {
|
export interface ILayerGroupRenderExtends {
|
||||||
/** 拓展的唯一标识符 */
|
/** 拓展的唯一标识符 */
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
||||||
import {
|
import { ERenderItemEvent, RenderItem, RenderItemPosition } from '../item';
|
||||||
ERenderItemEvent,
|
|
||||||
IAnimateFrame,
|
|
||||||
renderEmits,
|
|
||||||
RenderItem,
|
|
||||||
RenderItemPosition
|
|
||||||
} from '../item';
|
|
||||||
import { Transform } from '../transform';
|
import { Transform } from '../transform';
|
||||||
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
||||||
import { AutotileRenderable, RenderableData } from '../cache';
|
import { AutotileRenderable, RenderableData } from '../cache';
|
||||||
import { texture } from '../cache';
|
import { texture } from '../cache';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
import { logger } from '@/core/common/logger';
|
import { logger } from '@/core/common/logger';
|
||||||
|
import { IAnimateFrame, renderEmits } from '../frame';
|
||||||
|
|
||||||
type CanvasStyle = string | CanvasGradient | CanvasPattern;
|
type CanvasStyle = string | CanvasGradient | CanvasPattern;
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { logger } from '@/core/common/logger';
|
|
||||||
import { HeroRenderer } from './hero';
|
import { HeroRenderer } from './hero';
|
||||||
import { ILayerGroupRenderExtends, LayerGroup } from './layer';
|
import { ILayerGroupRenderExtends, LayerGroup } from './layer';
|
||||||
import { LayerGroupFloorBinder } from './floor';
|
import { LayerGroupFloorBinder } from './floor';
|
||||||
@ -162,7 +161,7 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
|||||||
let yStartTime: number = Date.now();
|
let yStartTime: number = Date.now();
|
||||||
let ending: boolean = false;
|
let ending: boolean = false;
|
||||||
// 这个数等于 sinh(2),用这个数的话,可以正好在刚开始移动的时候达到1的斜率,效果会比较好
|
// 这个数等于 sinh(2),用这个数的话,可以正好在刚开始移动的时候达到1的斜率,效果会比较好
|
||||||
let transitionTime = this.hero!.speed * 3.626860407847019;
|
const transitionTime = this.hero!.speed * 3.626860407847019;
|
||||||
|
|
||||||
const setTargetX = (x: number, time: number) => {
|
const setTargetX = (x: number, time: number) => {
|
||||||
if (x === xTarget) return;
|
if (x === xTarget) return;
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
||||||
import { ERenderItemEvent, RenderItem, RenderItemPosition } from './item';
|
|
||||||
import { Transform } from './transform';
|
|
||||||
import { EGL2Event, GL2, GL2Program, IGL2ProgramPrefix } from './gl2';
|
import { EGL2Event, GL2, GL2Program, IGL2ProgramPrefix } from './gl2';
|
||||||
|
|
||||||
const SHADER_PREFIX: IGL2ProgramPrefix = {
|
const SHADER_PREFIX: IGL2ProgramPrefix = {
|
||||||
@ -38,51 +36,26 @@ export interface EShaderEvent extends EGL2Event {}
|
|||||||
export class Shader<E extends EShaderEvent = EShaderEvent> extends GL2<
|
export class Shader<E extends EShaderEvent = EShaderEvent> extends GL2<
|
||||||
EShaderEvent | E
|
EShaderEvent | E
|
||||||
> {
|
> {
|
||||||
setHD(hd: boolean): void {
|
protected drawScene(
|
||||||
super.setHD(hd);
|
|
||||||
this.sizeGL(this.width, this.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
size(width: number, height: number): void {
|
|
||||||
super.size(width, height);
|
|
||||||
this.sizeGL(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
private sizeGL(width: number, height: number) {
|
|
||||||
const ratio = this.highResolution ? devicePixelRatio : 1;
|
|
||||||
const scale = ratio * core.domStyle.scale;
|
|
||||||
this.canvas.width = width * scale;
|
|
||||||
this.canvas.height = height * scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected preDraw(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
canvas: MotaOffscreenCanvas2D,
|
||||||
transform: Transform,
|
|
||||||
gl: WebGL2RenderingContext,
|
gl: WebGL2RenderingContext,
|
||||||
program: GL2Program
|
program: GL2Program
|
||||||
): boolean {
|
): void {
|
||||||
if (!program.modified) return false;
|
if (!program.modified) return;
|
||||||
const tex = program.getTexture('u_sampler');
|
const tex = program.getTexture('u_sampler');
|
||||||
if (!tex) return false;
|
if (!tex) return;
|
||||||
const c = canvas.canvas;
|
const c = canvas.canvas;
|
||||||
if (tex.width === c.width && tex.height === c.height) {
|
if (tex.width === c.width && tex.height === c.height) {
|
||||||
tex.sub(c, 0, 0, c.width, c.height);
|
tex.sub(c, 0, 0, c.width, c.height);
|
||||||
} else {
|
} else {
|
||||||
tex.set(c);
|
tex.set(c);
|
||||||
}
|
}
|
||||||
return true;
|
this.draw(gl, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected postDraw(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
transform: Transform,
|
|
||||||
gl: WebGL2RenderingContext,
|
|
||||||
program: GL2Program
|
|
||||||
): void {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ShaderProgram extends GL2Program {
|
export class ShaderProgram extends GL2Program {
|
||||||
protected readonly prefix: IGL2ProgramPrefix = SHADER_PREFIX;
|
protected override readonly prefix: IGL2ProgramPrefix = SHADER_PREFIX;
|
||||||
|
|
||||||
constructor(gl2: GL2, vs?: string, fs?: string) {
|
constructor(gl2: GL2, vs?: string, fs?: string) {
|
||||||
super(gl2, vs, fs);
|
super(gl2, vs, fs);
|
||||||
|
@ -7,7 +7,6 @@ import {
|
|||||||
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
||||||
import { Transform } from './transform';
|
import { Transform } from './transform';
|
||||||
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
||||||
import { logger } from '../common/logger';
|
|
||||||
|
|
||||||
export interface ESpriteEvent extends ERenderItemEvent {}
|
export interface ESpriteEvent extends ERenderItemEvent {}
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ import { RenderAdapter } from './adapter';
|
|||||||
import { FloorViewport } from './preset/viewport';
|
import { FloorViewport } from './preset/viewport';
|
||||||
import { JSX } from 'vue/jsx-runtime';
|
import { JSX } from 'vue/jsx-runtime';
|
||||||
import { DefineComponent, DefineSetupFnComponent } from 'vue';
|
import { DefineComponent, DefineSetupFnComponent } from 'vue';
|
||||||
|
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
|
||||||
|
import { Transform } from './transform';
|
||||||
|
|
||||||
export type Props<
|
export type Props<
|
||||||
T extends
|
T extends
|
||||||
@ -50,3 +52,13 @@ export function isSetEqual<T>(set1: Set<T>, set2: Set<T>) {
|
|||||||
if (set1 === set2) return true;
|
if (set1 === set2) return true;
|
||||||
else return set1.size === set2.size && set1.isSubsetOf(set2);
|
else return set1.size === set2.size && set1.isSubsetOf(set2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function transformCanvas(
|
||||||
|
canvas: MotaOffscreenCanvas2D,
|
||||||
|
transform: Transform
|
||||||
|
) {
|
||||||
|
const { ctx } = canvas;
|
||||||
|
const mat = transform.mat;
|
||||||
|
const [a, b, , c, d, , e, f] = mat;
|
||||||
|
ctx.transform(a, b, c, d, e, f);
|
||||||
|
}
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
import { Shader, ShaderProgram } from '@/core/render/shader';
|
|
||||||
import { IWeather, WeatherController } from './weather';
|
import { IWeather, WeatherController } from './weather';
|
||||||
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
|
||||||
import { GL2Program } from '@/core/render/gl2';
|
|
||||||
import { Transform } from '@/core/render/transform';
|
|
||||||
|
|
||||||
export class SunWeather implements IWeather {
|
export class SunWeather implements IWeather {
|
||||||
static id: string = 'sun';
|
static id: string = 'sun';
|
||||||
@ -15,21 +11,3 @@ export class SunWeather implements IWeather {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WeatherController.register(SunWeather);
|
WeatherController.register(SunWeather);
|
||||||
|
|
||||||
class SunShader extends Shader {
|
|
||||||
protected preDraw(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
transform: Transform,
|
|
||||||
gl: WebGL2RenderingContext,
|
|
||||||
program: GL2Program
|
|
||||||
): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected postDraw(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
transform: Transform,
|
|
||||||
gl: WebGL2RenderingContext,
|
|
||||||
program: GL2Program
|
|
||||||
): void {}
|
|
||||||
}
|
|
||||||
|
@ -103,7 +103,7 @@ export abstract class BarrageBoss extends EventEmitter<BarrageBossEvent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class BossSprite<
|
export class BossSprite<
|
||||||
T extends BarrageBoss = BarrageBoss
|
T extends BarrageBoss = BarrageBoss
|
||||||
> extends RenderItem {
|
> extends RenderItem {
|
||||||
/** 这个sprite所属的boss */
|
/** 这个sprite所属的boss */
|
||||||
@ -115,36 +115,16 @@ export abstract class BossSprite<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在内置渲染函数执行前渲染内容,返回false会阻止内置渲染函数执行
|
* override 此方法来实现自定义渲染,默认会调用 {@link renderProjectiles} 方法。
|
||||||
* @param canvas 渲染至的画布
|
* 关于本方法,参考 {@link RenderItem.render}
|
||||||
* @param transform 渲染时的变换矩阵
|
* @param canvas 渲染至的目标画布
|
||||||
|
* @param transform 当前画布相对于父元素的变换矩阵
|
||||||
*/
|
*/
|
||||||
protected abstract preDraw(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
transform: Transform
|
|
||||||
): boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在内置渲染函数执行后渲染内容,如果preDraw返回false,也会执行本函数
|
|
||||||
* @param canvas 渲染至的画布
|
|
||||||
* @param transform 渲染时的变换矩阵
|
|
||||||
*/
|
|
||||||
protected abstract postDraw(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
transform: Transform
|
|
||||||
): void;
|
|
||||||
|
|
||||||
protected render(
|
protected render(
|
||||||
canvas: MotaOffscreenCanvas2D,
|
canvas: MotaOffscreenCanvas2D,
|
||||||
transform: Transform
|
transform: Transform
|
||||||
): void {
|
): void {
|
||||||
const pre = this.preDraw(canvas, transform);
|
|
||||||
if (!pre) {
|
|
||||||
this.postDraw(canvas, transform);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.renderProjectiles(canvas, transform);
|
this.renderProjectiles(canvas, transform);
|
||||||
this.postDraw(canvas, transform);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,6 @@ import { MotaRenderer } from '@/core/render/render';
|
|||||||
import { LayerGroup } from '@/core/render/preset/layer';
|
import { LayerGroup } from '@/core/render/preset/layer';
|
||||||
import { RenderItem } from '@/core/render/item';
|
import { RenderItem } from '@/core/render/item';
|
||||||
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
||||||
import { Transform } from '@/core/render/transform';
|
|
||||||
import { Animation, hyper, power, sleep, Transition } from 'mutate-animate';
|
import { Animation, hyper, power, sleep, Transition } from 'mutate-animate';
|
||||||
import { Container } from '@/core/render/container';
|
import { Container } from '@/core/render/container';
|
||||||
import {
|
import {
|
||||||
@ -22,7 +21,7 @@ import {
|
|||||||
import { IStateDamageable } from '@/game/state/interface';
|
import { IStateDamageable } from '@/game/state/interface';
|
||||||
import { HeroRenderer } from '@/core/render/preset/hero';
|
import { HeroRenderer } from '@/core/render/preset/hero';
|
||||||
import { controller } from '@/module/weather';
|
import { controller } from '@/module/weather';
|
||||||
import { Pop, PopText } from '../fx/pop';
|
import { Pop } from '../fx/pop';
|
||||||
|
|
||||||
Mota.require('var', 'loading').once('coreInit', () => {
|
Mota.require('var', 'loading').once('coreInit', () => {
|
||||||
const shader = new Shader();
|
const shader = new Shader();
|
||||||
@ -67,7 +66,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
|
|
||||||
readonly hitbox: Hitbox.Rect;
|
readonly hitbox: Hitbox.Rect;
|
||||||
readonly state: IStateDamageable;
|
readonly state: IStateDamageable;
|
||||||
readonly main: BossEffect;
|
readonly main: BossSprite;
|
||||||
|
|
||||||
/** 血条显示元素 */
|
/** 血条显示元素 */
|
||||||
private healthBar: HealthBar;
|
private healthBar: HealthBar;
|
||||||
@ -127,7 +126,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
|
|
||||||
this.healthBar = new HealthBar('absolute');
|
this.healthBar = new HealthBar('absolute');
|
||||||
this.word = new Word('absolute');
|
this.word = new Word('absolute');
|
||||||
this.main = new BossEffect('absolute', this);
|
this.main = new BossSprite('absolute', this);
|
||||||
const render = MotaRenderer.get('render-main')!;
|
const render = MotaRenderer.get('render-main')!;
|
||||||
this.group = render.getElementById('layer-main') as LayerGroup;
|
this.group = render.getElementById('layer-main') as LayerGroup;
|
||||||
this.mapDraw = render.getElementById('map-draw') as Container;
|
this.mapDraw = render.getElementById('map-draw') as Container;
|
||||||
@ -135,7 +134,9 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
|
|
||||||
this.healthBar.init();
|
this.healthBar.init();
|
||||||
this.word.init();
|
this.word.init();
|
||||||
this.main.init();
|
this.main.size(480, 480);
|
||||||
|
this.main.setHD(true);
|
||||||
|
this.main.setZIndex(80);
|
||||||
|
|
||||||
TowerBoss.effect.setTransform(this.group.camera);
|
TowerBoss.effect.setTransform(this.group.camera);
|
||||||
|
|
||||||
@ -201,7 +202,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
/**
|
/**
|
||||||
* 用于全局检测,例如受伤、攻击boss等
|
* 用于全局检测,例如受伤、攻击boss等
|
||||||
*/
|
*/
|
||||||
check(time: number) {
|
check(_time: number) {
|
||||||
this.checkLose();
|
this.checkLose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +299,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
this.stageProgress = 0;
|
this.stageProgress = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private aiPrologue(time: number, frame: number) {
|
private aiPrologue(time: number, _frame: number) {
|
||||||
// stageProgress:
|
// stageProgress:
|
||||||
// 0: 开始; 1: 开始血条动画
|
// 0: 开始; 1: 开始血条动画
|
||||||
|
|
||||||
@ -362,7 +363,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private aiStage1(time: number, frame: number) {
|
private aiStage1(time: number, _frame: number) {
|
||||||
// stageProgress:
|
// stageProgress:
|
||||||
// 0: 开始; 1,2,3,4: 对应对话
|
// 0: 开始; 1,2,3,4: 对应对话
|
||||||
|
|
||||||
@ -394,7 +395,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private aiDialogue1(time: number, frame: number) {
|
private aiDialogue1(time: number, _frame: number) {
|
||||||
this.changeStage(TowerBossStage.Stage2, time);
|
this.changeStage(TowerBossStage.Stage2, time);
|
||||||
this.attackTime = 3;
|
this.attackTime = 3;
|
||||||
this.skill4Time = 5;
|
this.skill4Time = 5;
|
||||||
@ -441,7 +442,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private aiStage2(time: number, frame: number) {
|
private aiStage2(time: number, _frame: number) {
|
||||||
const skill4Release = this.skill4Time * this.skill4Interval;
|
const skill4Release = this.skill4Time * this.skill4Interval;
|
||||||
const skill5Release = this.skill5Time * this.skill5Interval;
|
const skill5Release = this.skill5Time * this.skill5Interval;
|
||||||
const attack = this.attackTime * this.attackInterval;
|
const attack = this.attackTime * this.attackInterval;
|
||||||
@ -496,7 +497,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
core.setBlock(557, 7, n + 1);
|
core.setBlock(557, 7, n + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private aiDialogue2(time: number, frame: number) {
|
private aiDialogue2(time: number, _frame: number) {
|
||||||
this.changeStage(TowerBossStage.Stage3, time);
|
this.changeStage(TowerBossStage.Stage3, time);
|
||||||
this.attackTime = 3;
|
this.attackTime = 3;
|
||||||
this.terrainClose(1);
|
this.terrainClose(1);
|
||||||
@ -539,7 +540,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private aiStage3(time: number, frame: number) {
|
private aiStage3(time: number, _frame: number) {
|
||||||
const skill6Release = this.skill6Time * this.skill6Interval;
|
const skill6Release = this.skill6Time * this.skill6Interval;
|
||||||
const skill7Release = this.skill7Time * this.skill7Interval;
|
const skill7Release = this.skill7Time * this.skill7Interval;
|
||||||
const attack = this.attackTime * this.attackInterval;
|
const attack = this.attackTime * this.attackInterval;
|
||||||
@ -567,7 +568,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private aiStage4(time: number, frame: number) {
|
private aiStage4(time: number, _frame: number) {
|
||||||
const skill6Release = this.skill6Time * this.skill6Interval;
|
const skill6Release = this.skill6Time * this.skill6Interval;
|
||||||
const skill7Release = this.skill7Time * this.skill7Interval;
|
const skill7Release = this.skill7Time * this.skill7Interval;
|
||||||
const attack = this.attackTime * this.attackInterval;
|
const attack = this.attackTime * this.attackInterval;
|
||||||
@ -595,7 +596,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private aiStage5(time: number, frame: number) {
|
private aiStage5(time: number, _frame: number) {
|
||||||
const skill6Release = this.skill6Time * this.skill6Interval;
|
const skill6Release = this.skill6Time * this.skill6Interval;
|
||||||
const skill7Release = this.skill7Time * this.skill7Interval;
|
const skill7Release = this.skill7Time * this.skill7Interval;
|
||||||
const attack = this.attackTime * this.attackInterval;
|
const attack = this.attackTime * this.attackInterval;
|
||||||
@ -618,7 +619,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private aiEnd(time: number, frame: number) {
|
private aiEnd(_time: number, _frame: number) {
|
||||||
this.end();
|
this.end();
|
||||||
core.insertAction([
|
core.insertAction([
|
||||||
{ type: 'openDoor', loc: [13, 6], floorId: 'MT19' },
|
{ type: 'openDoor', loc: [13, 6], floorId: 'MT19' },
|
||||||
@ -630,29 +631,6 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BossEffect extends BossSprite<TowerBoss> {
|
|
||||||
/**
|
|
||||||
* 初始化
|
|
||||||
*/
|
|
||||||
init() {
|
|
||||||
this.size(480, 480);
|
|
||||||
this.setHD(true);
|
|
||||||
this.setZIndex(80);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected preDraw(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
transform: Transform
|
|
||||||
): boolean {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected postDraw(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
transform: Transform
|
|
||||||
): void {}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TextRenderable {
|
interface TextRenderable {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
@ -747,10 +725,7 @@ class Word extends RenderItem {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(
|
protected render(canvas: MotaOffscreenCanvas2D): void {
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
transform: Transform
|
|
||||||
): void {
|
|
||||||
const data = this.getTextRenerable();
|
const data = this.getTextRenerable();
|
||||||
const ctx = canvas.ctx;
|
const ctx = canvas.ctx;
|
||||||
ctx.font = '18px "normal"';
|
ctx.font = '18px "normal"';
|
||||||
@ -832,10 +807,7 @@ class HealthBar extends RenderItem {
|
|||||||
this.status = HealthBarStatus.End;
|
this.status = HealthBarStatus.End;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(
|
protected render(canvas: MotaOffscreenCanvas2D): void {
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
transform: Transform
|
|
||||||
): void {
|
|
||||||
const ctx = canvas.ctx;
|
const ctx = canvas.ctx;
|
||||||
|
|
||||||
const hp = this.trans.value.hp;
|
const hp = this.trans.value.hp;
|
||||||
|
@ -142,7 +142,7 @@ export class Chase extends EventEmitter<ChaseEvent> {
|
|||||||
|
|
||||||
this.emit('frame', nTime, fTime);
|
this.emit('frame', nTime, fTime);
|
||||||
|
|
||||||
while (1) {
|
while (true) {
|
||||||
const time = this.onTimeListener[0];
|
const time = this.onTimeListener[0];
|
||||||
if (!time) break;
|
if (!time) break;
|
||||||
if (time.time <= nTime) {
|
if (time.time <= nTime) {
|
||||||
@ -157,7 +157,7 @@ export class Chase extends EventEmitter<ChaseEvent> {
|
|||||||
const floor = this.onFloorTimeListener[this.nowFloor];
|
const floor = this.onFloorTimeListener[this.nowFloor];
|
||||||
if (!floor) return;
|
if (!floor) return;
|
||||||
|
|
||||||
while (1) {
|
while (true) {
|
||||||
const time = floor[0];
|
const time = floor[0];
|
||||||
if (!time) break;
|
if (!time) break;
|
||||||
if (time.time <= fTime) {
|
if (time.time <= fTime) {
|
||||||
|
Loading…
Reference in New Issue
Block a user