From 2a17749adc4ad4ef02e4e3413b861afa69c96d33 Mon Sep 17 00:00:00 2001 From: strawberry42271 <2806566736@qq.com> Date: Mon, 23 Dec 2024 19:23:13 +0800 Subject: [PATCH 01/22] =?UTF-8?q?feat:graphics=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/preset/graphics.ts | 228 +++++++++++++++++++++++++---- 1 file changed, 199 insertions(+), 29 deletions(-) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 57f9aaa..5ddf392 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -2,6 +2,7 @@ import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d'; import { ERenderItemEvent, RenderItem } from '../item'; import { Transform } from '../transform'; import { ElementNamespace, ComponentInternalInstance } from 'vue'; +import { isNil } from 'lodash-es'; /* * Expected usage (this comment needs to be deleted after implementing correctly): @@ -54,14 +55,14 @@ export interface EGraphicItemEvent extends ERenderItemEvent {} export abstract class GraphicItemBase extends RenderItem - implements IGraphicProperty + implements Required { mode: number = GraphicMode.Fill; fill: CanvasStyle = '#fff'; stroke: CanvasStyle = '#fff'; lineWidth: number = 2; - lineDash?: number[] | undefined; - lineDashOffset?: number | undefined; + lineDash: number[] = []; + lineDashOffset: number = 0; lineJoin: CanvasLineJoin = 'bevel'; lineCap: CanvasLineCap = 'butt'; miterLimit: number = 10; @@ -71,31 +72,50 @@ export abstract class GraphicItemBase * 设置描边绘制的信息 * @param options 线的信息 */ - setLineOption(options: Partial) {} + setLineOption(options: Partial) { + if (!isNil(options.lineWidth)) this.lineWidth = options.lineWidth; + if (!isNil(options.lineDash)) this.lineDash = options.lineDash; + if (!isNil(options.lineDashOffset)) this.lineDashOffset = options.lineDashOffset; + if (!isNil(options.lineJoin)) this.lineJoin = options.lineJoin; + if (!isNil(options.lineCap)) this.lineCap = options.lineCap; + if (!isNil(options.miterLimit)) this.miterLimit = options.miterLimit; + } /** * 设置填充样式 * @param style 绘制样式 */ - setFillStyle(style: CanvasStyle) {} + setFillStyle(style: CanvasStyle) { + this.fill = style; + this.update(); + } /** * 设置描边样式 * @param style 绘制样式 */ - setStrokeStyle(style: CanvasStyle) {} + setStrokeStyle(style: CanvasStyle) { + this.stroke = style; + this.update(); + } /** * 设置填充原则 * @param rule 填充原则 */ - setFillRule(rule: CanvasFillRule) {} + setFillRule(rule: CanvasFillRule) { + this.fillRule = rule; + this.update(); + } /** * 设置绘制模式,是描边还是填充 * @param mode 绘制模式 */ - setMode(mode: GraphicMode) {} + setMode(mode: GraphicMode) { + this.mode = mode; + this.update(); + } /** * 设置画布的渲染状态,在实际渲染前调用 @@ -103,7 +123,16 @@ export abstract class GraphicItemBase */ protected setCanvasState(canvas: MotaOffscreenCanvas2D) { const ctx = canvas.ctx; - ctx.fillStyle = this.fill; // 示例,后面的都按这个写,不需要save restore,写完把这个注释删了 + ctx.fillStyle = this.fill; + ctx.strokeStyle = this.stroke; + ctx.lineWidth = this.lineWidth; + ctx.setLineDash(this.lineDash) + ctx.lineDashOffset = this.lineDashOffset; + ctx.lineJoin = this.lineJoin; + ctx.lineCap = this.lineCap; + ctx.miterLimit = this.miterLimit; + ctx.fill(this.fillRule); + this.update(); } patchProp( @@ -156,20 +185,50 @@ export class Circle extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + ctx.beginPath(); + ctx.arc(this.x,this.y,this.radius,this.start,this.end); + + switch (this.mode) { + case GraphicMode.Fill: + ctx.fill(this.fillRule); + break; + case GraphicMode.Stroke: + ctx.stroke(); + break; + case GraphicMode.FillAndStroke: + ctx.fill(this.fillRule); + ctx.stroke(); + break; + case GraphicMode.StrokeAndFill: + ctx.stroke(); + ctx.fill(this.fillRule); + break; + } + } /** * 设置圆的半径 * @param radius 半径 */ - setRadius(radius: number) {} + setRadius(radius: number) { + this.radius = radius; + this.size(radius*2,radius*2); + this.update(); + } /** * 设置圆的起始与终止角度 * @param start 起始角度 * @param end 终止角度 */ - setAngle(start: number, end: number) {} + setAngle(start: number, end: number) { + this.start = start; + this.end = end; + this.update(); + } patchProp( key: string, @@ -193,21 +252,52 @@ export class Ellipse extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + ctx.beginPath(); + ctx.ellipse(this.x,this.y,this.radiusX,this.radiusY,0,this.start,this.end); + + switch (this.mode) { + case GraphicMode.Fill: + ctx.fill(this.fillRule); + break; + case GraphicMode.Stroke: + ctx.stroke(); + break; + case GraphicMode.FillAndStroke: + ctx.fill(this.fillRule); + ctx.stroke(); + break; + case GraphicMode.StrokeAndFill: + ctx.stroke(); + ctx.fill(this.fillRule); + break; + } + } /** * 设置椭圆的横纵轴长度 * @param x 横轴长度 * @param y 纵轴长度 */ - setRadius(x: number, y: number) {} + setRadius(x: number, y: number) { + this.radiusX = x; + this.radiusY = y; + this.update(); + } + /** * 设置椭圆的起始与终止角度 * @param start 起始角度 * @param end 终止角度 */ - setAngle(start: number, end: number) {} + setAngle(start: number, end: number) { + this.start = start; + this.end = end; + this.update(); + } patchProp( key: string, @@ -231,17 +321,33 @@ export class Line extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + ctx.beginPath(); + ctx.moveTo(this.x1,this.y1) + ctx.lineTo(this.x2,this.y2); + ctx.stroke(); + + } /** * 设置第一个点的横纵坐标 */ - setPoint1(x: number, y: number) {} + setPoint1(x: number, y: number) { + this.x1 = x; + this.y1 = y; + this.update(); + } /** * 设置第二个点的横纵坐标 */ - setPoint2(x: number, y: number) {} + setPoint2(x: number, y: number) { + this.x2 = x; + this.y2 = y; + this.update(); + } patchProp( key: string, @@ -269,27 +375,50 @@ export class BezierCurve extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + ctx.beginPath(); + ctx.moveTo(this.sx,this.sy) + ctx.bezierCurveTo(this.cp1x,this.cp1y,this.cp2x,this.cp2y,this.ex,this.ey); + ctx.stroke(); + } /** * 设置起始点坐标 */ - setStart(x: number, y: number) {} + setStart(x: number, y: number) { + this.sx = x; + this.sy = y; + this.update(); + } /** * 设置控制点1坐标 */ - setControl1(x: number, y: number) {} + setControl1(x: number, y: number) { + this.cp1x = x; + this.cp1y = y; + this.update(); + } /** * 设置控制点2坐标 */ - setControl2(x: number, y: number) {} + setControl2(x: number, y: number) { + this.cp2x = x; + this.cp2y = y; + this.update(); + } /** * 设置终点坐标 */ - setEnd(x: number, y: number) {} + setEnd(x: number, y: number) { + this.ex = x; + this.ey = y; + this.update(); + } patchProp( key: string, @@ -315,22 +444,41 @@ export class QuadraticCurve extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + ctx.beginPath(); + ctx.moveTo(this.sx,this.sy) + ctx.quadraticCurveTo(this.cpx,this.cpy,this.ex,this.ey); + ctx.stroke(); + } /** * 设置起始点坐标 */ - setStart(x: number, y: number) {} + setStart(x: number, y: number) { + this.sx = x; + this.sy = y; + this.update(); + } /** * 设置控制点坐标 */ - setControl(x: number, y: number) {} + setControl(x: number, y: number) { + this.cpx = x; + this.cpy = y; + this.update(); + } /** * 设置终点坐标 */ - setEnd(x: number, y: number) {} + setEnd(x: number, y: number) { + this.ex = x; + this.ey = y; + this.update(); + } patchProp( key: string, @@ -352,7 +500,26 @@ export class Path extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + switch (this.mode) { + case GraphicMode.Fill: + ctx.fill(this.path,this.fillRule); + break; + case GraphicMode.Stroke: + ctx.stroke(this.path); + break; + case GraphicMode.FillAndStroke: + ctx.fill(this.path,this.fillRule); + ctx.stroke(this.path); + break; + case GraphicMode.StrokeAndFill: + ctx.stroke(this.path); + ctx.fill(this.path,this.fillRule); + break; + } + } /** * 获取当前路径 @@ -365,7 +532,10 @@ export class Path extends GraphicItemBase { * 为路径添加路径 * @param path 要添加的路径 */ - addPath(path: Path2D) {} + addPath(path: Path2D) { + this.path.addPath(path); + this.update(); + } patchProp( key: string, From 4e583fb121aa480e8d5213e748dc97a4c38eae28 Mon Sep 17 00:00:00 2001 From: strawberry42271 <2806566736@qq.com> Date: Tue, 24 Dec 2024 17:11:49 +0800 Subject: [PATCH 02/22] =?UTF-8?q?feat:=20graphic=E7=9A=84patchProp?= =?UTF-8?q?=E5=86=99=E5=AE=8C=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/preset/graphics.ts | 105 +++++++++++++++++++++++++++++ src/core/render/renderer/props.ts | 44 ++++++++++-- 2 files changed, 143 insertions(+), 6 deletions(-) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 5ddf392..803d801 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -238,6 +238,18 @@ export class Circle extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'radius': + if (!this.assertType(nextValue, 'number', key)) return; + this.setRadius(nextValue); + return; + case 'start': + if (!this.assertType(nextValue, 'number', key)) return; + this.setAngle(nextValue,this.end); + return; + case 'end': + if (!this.assertType(nextValue, 'number', key)) return; + this.setAngle(this.start,nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } @@ -307,6 +319,22 @@ export class Ellipse extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'radiusX': + if (!this.assertType(nextValue, 'number', key)) return; + this.setRadius(nextValue,this.radiusY); + return; + case 'radiusY': + if (!this.assertType(nextValue, 'number', key)) return; + this.setRadius(this.radiusY,nextValue); + return; + case 'start': + if (!this.assertType(nextValue, 'number', key)) return; + this.setAngle(nextValue,this.end); + return; + case 'end': + if (!this.assertType(nextValue, 'number', key)) return; + this.setAngle(this.start,nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } @@ -357,6 +385,22 @@ export class Line extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'x1': + if (!this.assertType(nextValue, 'number', key)) return; + this.setPoint1(nextValue,this.y1); + return; + case 'y1': + if (!this.assertType(nextValue, 'number', key)) return; + this.setPoint1(this.x1,nextValue); + return; + case 'x2': + if (!this.assertType(nextValue, 'number', key)) return; + this.setPoint2(nextValue,this.y2); + return; + case 'y2': + if (!this.assertType(nextValue, 'number', key)) return; + this.setPoint2(this.x2,nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } @@ -428,6 +472,38 @@ export class BezierCurve extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'sx': + if (!this.assertType(nextValue, 'number', key)) return; + this.setStart(nextValue,this.sy); + return; + case 'sy': + if (!this.assertType(nextValue, 'number', key)) return; + this.setStart(this.sx,nextValue); + return; + case 'cp1x': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl1(nextValue,this.cp1y); + return; + case 'cp1y': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl1(this.cp1x,nextValue); + return; + case 'cp2x': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl2(nextValue,this.cp2y); + return; + case 'cp2y': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl2(this.cp2x,nextValue); + return; + case 'ex': + if (!this.assertType(nextValue, 'number', key)) return; + this.setEnd(nextValue,this.ey); + return; + case 'ey': + if (!this.assertType(nextValue, 'number', key)) return; + this.setEnd(this.ex,nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } @@ -488,6 +564,30 @@ export class QuadraticCurve extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'sx': + if (!this.assertType(nextValue, 'number', key)) return; + this.setStart(nextValue,this.sy); + return; + case 'sy': + if (!this.assertType(nextValue, 'number', key)) return; + this.setStart(this.sx,nextValue); + return; + case 'cpx': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl(nextValue,this.cpy); + return; + case 'cpy': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl(this.cpx,nextValue); + return; + case 'ex': + if (!this.assertType(nextValue, 'number', key)) return; + this.setEnd(nextValue,this.ey); + return; + case 'ey': + if (!this.assertType(nextValue, 'number', key)) return; + this.setEnd(this.ex,nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } @@ -545,6 +645,11 @@ export class Path extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'path': + if (!this.assertType(nextValue, Path2D, key)) return; + this.path = nextValue; + this.update(); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } diff --git a/src/core/render/renderer/props.ts b/src/core/render/renderer/props.ts index 61f688e..ddc9cfc 100644 --- a/src/core/render/renderer/props.ts +++ b/src/core/render/renderer/props.ts @@ -108,17 +108,49 @@ export interface GraphicPropsBase extends BaseProps, Partial { export interface RectProps extends GraphicPropsBase {} -export interface CirclesProps extends GraphicPropsBase {} +export interface CirclesProps extends GraphicPropsBase { + radius?: number; + start?: number; + end?: number; +} -export interface EllipseProps extends GraphicPropsBase {} +export interface EllipseProps extends GraphicPropsBase { + radiusX?: number; + radiusY?: number; + start?: number; + end?: number; +} -export interface LineProps extends GraphicPropsBase {} +export interface LineProps extends GraphicPropsBase { + x1?: number; + y1?: number; + x2?: number; + y2?: number; +} -export interface BezierProps extends GraphicPropsBase {} +export interface BezierProps extends GraphicPropsBase { + sx?: number; + sy?: number; + cp1x?: number; + cp1y?: number; + cp2x?: number; + cp2y?: number; + ex?: number; + ey?: number; +} -export interface QuadraticProps extends GraphicPropsBase {} +export interface QuadraticProps extends GraphicPropsBase { + sx?: number; + sy?: number; + cpx?: number; + cpy?: number; + ex?: number; + ey?: number; +} -export interface PathProps extends GraphicPropsBase {} +export interface PathProps extends GraphicPropsBase { + path?: Path2D; +} export interface IconProps extends BaseProps {} From 26600c21541a4998cfa1db49c653b098838e2e48 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Tue, 24 Dec 2024 18:18:53 +0800 Subject: [PATCH 03/22] style: graphics.ts --- src/core/render/preset/graphics.ts | 95 +++++++++++++++++------------- 1 file changed, 55 insertions(+), 40 deletions(-) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 803d801..3624fd9 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -75,10 +75,12 @@ export abstract class GraphicItemBase setLineOption(options: Partial) { if (!isNil(options.lineWidth)) this.lineWidth = options.lineWidth; if (!isNil(options.lineDash)) this.lineDash = options.lineDash; - if (!isNil(options.lineDashOffset)) this.lineDashOffset = options.lineDashOffset; + if (!isNil(options.lineDashOffset)) + this.lineDashOffset = options.lineDashOffset; if (!isNil(options.lineJoin)) this.lineJoin = options.lineJoin; if (!isNil(options.lineCap)) this.lineCap = options.lineCap; if (!isNil(options.miterLimit)) this.miterLimit = options.miterLimit; + this.update(); } /** @@ -126,7 +128,7 @@ export abstract class GraphicItemBase ctx.fillStyle = this.fill; ctx.strokeStyle = this.stroke; ctx.lineWidth = this.lineWidth; - ctx.setLineDash(this.lineDash) + ctx.setLineDash(this.lineDash); ctx.lineDashOffset = this.lineDashOffset; ctx.lineJoin = this.lineJoin; ctx.lineCap = this.lineCap; @@ -189,7 +191,7 @@ export class Circle extends GraphicItemBase { const ctx = canvas.ctx; this.setCanvasState(canvas); ctx.beginPath(); - ctx.arc(this.x,this.y,this.radius,this.start,this.end); + ctx.arc(this.x, this.y, this.radius, this.start, this.end); switch (this.mode) { case GraphicMode.Fill: @@ -215,7 +217,7 @@ export class Circle extends GraphicItemBase { */ setRadius(radius: number) { this.radius = radius; - this.size(radius*2,radius*2); + this.size(radius * 2, radius * 2); this.update(); } @@ -244,11 +246,11 @@ export class Circle extends GraphicItemBase { return; case 'start': if (!this.assertType(nextValue, 'number', key)) return; - this.setAngle(nextValue,this.end); + this.setAngle(nextValue, this.end); return; case 'end': if (!this.assertType(nextValue, 'number', key)) return; - this.setAngle(this.start,nextValue); + this.setAngle(this.start, nextValue); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -268,7 +270,15 @@ export class Ellipse extends GraphicItemBase { const ctx = canvas.ctx; this.setCanvasState(canvas); ctx.beginPath(); - ctx.ellipse(this.x,this.y,this.radiusX,this.radiusY,0,this.start,this.end); + ctx.ellipse( + this.x, + this.y, + this.radiusX, + this.radiusY, + 0, + this.start, + this.end + ); switch (this.mode) { case GraphicMode.Fill: @@ -299,7 +309,6 @@ export class Ellipse extends GraphicItemBase { this.update(); } - /** * 设置椭圆的起始与终止角度 * @param start 起始角度 @@ -321,19 +330,19 @@ export class Ellipse extends GraphicItemBase { switch (key) { case 'radiusX': if (!this.assertType(nextValue, 'number', key)) return; - this.setRadius(nextValue,this.radiusY); + this.setRadius(nextValue, this.radiusY); return; case 'radiusY': if (!this.assertType(nextValue, 'number', key)) return; - this.setRadius(this.radiusY,nextValue); + this.setRadius(this.radiusY, nextValue); return; case 'start': if (!this.assertType(nextValue, 'number', key)) return; - this.setAngle(nextValue,this.end); + this.setAngle(nextValue, this.end); return; case 'end': if (!this.assertType(nextValue, 'number', key)) return; - this.setAngle(this.start,nextValue); + this.setAngle(this.start, nextValue); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -353,10 +362,9 @@ export class Line extends GraphicItemBase { const ctx = canvas.ctx; this.setCanvasState(canvas); ctx.beginPath(); - ctx.moveTo(this.x1,this.y1) - ctx.lineTo(this.x2,this.y2); + ctx.moveTo(this.x1, this.y1); + ctx.lineTo(this.x2, this.y2); ctx.stroke(); - } /** @@ -387,19 +395,19 @@ export class Line extends GraphicItemBase { switch (key) { case 'x1': if (!this.assertType(nextValue, 'number', key)) return; - this.setPoint1(nextValue,this.y1); + this.setPoint1(nextValue, this.y1); return; case 'y1': if (!this.assertType(nextValue, 'number', key)) return; - this.setPoint1(this.x1,nextValue); + this.setPoint1(this.x1, nextValue); return; case 'x2': if (!this.assertType(nextValue, 'number', key)) return; - this.setPoint2(nextValue,this.y2); + this.setPoint2(nextValue, this.y2); return; case 'y2': if (!this.assertType(nextValue, 'number', key)) return; - this.setPoint2(this.x2,nextValue); + this.setPoint2(this.x2, nextValue); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -423,8 +431,15 @@ export class BezierCurve extends GraphicItemBase { const ctx = canvas.ctx; this.setCanvasState(canvas); ctx.beginPath(); - ctx.moveTo(this.sx,this.sy) - ctx.bezierCurveTo(this.cp1x,this.cp1y,this.cp2x,this.cp2y,this.ex,this.ey); + ctx.moveTo(this.sx, this.sy); + ctx.bezierCurveTo( + this.cp1x, + this.cp1y, + this.cp2x, + this.cp2y, + this.ex, + this.ey + ); ctx.stroke(); } @@ -474,35 +489,35 @@ export class BezierCurve extends GraphicItemBase { switch (key) { case 'sx': if (!this.assertType(nextValue, 'number', key)) return; - this.setStart(nextValue,this.sy); + this.setStart(nextValue, this.sy); return; case 'sy': if (!this.assertType(nextValue, 'number', key)) return; - this.setStart(this.sx,nextValue); + this.setStart(this.sx, nextValue); return; case 'cp1x': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl1(nextValue,this.cp1y); + this.setControl1(nextValue, this.cp1y); return; case 'cp1y': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl1(this.cp1x,nextValue); + this.setControl1(this.cp1x, nextValue); return; case 'cp2x': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl2(nextValue,this.cp2y); + this.setControl2(nextValue, this.cp2y); return; case 'cp2y': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl2(this.cp2x,nextValue); + this.setControl2(this.cp2x, nextValue); return; case 'ex': if (!this.assertType(nextValue, 'number', key)) return; - this.setEnd(nextValue,this.ey); + this.setEnd(nextValue, this.ey); return; case 'ey': if (!this.assertType(nextValue, 'number', key)) return; - this.setEnd(this.ex,nextValue); + this.setEnd(this.ex, nextValue); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -524,8 +539,8 @@ export class QuadraticCurve extends GraphicItemBase { const ctx = canvas.ctx; this.setCanvasState(canvas); ctx.beginPath(); - ctx.moveTo(this.sx,this.sy) - ctx.quadraticCurveTo(this.cpx,this.cpy,this.ex,this.ey); + ctx.moveTo(this.sx, this.sy); + ctx.quadraticCurveTo(this.cpx, this.cpy, this.ex, this.ey); ctx.stroke(); } @@ -566,27 +581,27 @@ export class QuadraticCurve extends GraphicItemBase { switch (key) { case 'sx': if (!this.assertType(nextValue, 'number', key)) return; - this.setStart(nextValue,this.sy); + this.setStart(nextValue, this.sy); return; case 'sy': if (!this.assertType(nextValue, 'number', key)) return; - this.setStart(this.sx,nextValue); + this.setStart(this.sx, nextValue); return; case 'cpx': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl(nextValue,this.cpy); + this.setControl(nextValue, this.cpy); return; case 'cpy': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl(this.cpx,nextValue); + this.setControl(this.cpx, nextValue); return; case 'ex': if (!this.assertType(nextValue, 'number', key)) return; - this.setEnd(nextValue,this.ey); + this.setEnd(nextValue, this.ey); return; case 'ey': if (!this.assertType(nextValue, 'number', key)) return; - this.setEnd(this.ex,nextValue); + this.setEnd(this.ex, nextValue); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -605,18 +620,18 @@ export class Path extends GraphicItemBase { this.setCanvasState(canvas); switch (this.mode) { case GraphicMode.Fill: - ctx.fill(this.path,this.fillRule); + ctx.fill(this.path, this.fillRule); break; case GraphicMode.Stroke: ctx.stroke(this.path); break; case GraphicMode.FillAndStroke: - ctx.fill(this.path,this.fillRule); + ctx.fill(this.path, this.fillRule); ctx.stroke(this.path); break; case GraphicMode.StrokeAndFill: ctx.stroke(this.path); - ctx.fill(this.path,this.fillRule); + ctx.fill(this.path, this.fillRule); break; } } From 733b6908c8d512b3efda3fb51bb92176391028cb Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Tue, 24 Dec 2024 19:55:52 +0800 Subject: [PATCH 04/22] feat: patchProp for GraphicItemBase --- src/core/render/preset/graphics.ts | 104 +++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 3624fd9..d75c4ef 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -51,6 +51,12 @@ export const enum GraphicMode { StrokeAndFill } +const enum GraphicModeProp { + Fill, + Stroke, + StrokeAndFill +} + export interface EGraphicItemEvent extends ERenderItemEvent {} export abstract class GraphicItemBase @@ -68,6 +74,11 @@ export abstract class GraphicItemBase miterLimit: number = 10; fillRule: CanvasFillRule = 'nonzero'; + private propFill: boolean = true; + private propStroke: boolean = false; + private strokeAndFill: boolean = false; + private propFillSet: boolean = false; + /** * 设置描边绘制的信息 * @param options 线的信息 @@ -119,6 +130,46 @@ export abstract class GraphicItemBase this.update(); } + /** + * 检查渲染模式,参考 {@link GraphicPropsBase} 中的 fill stroke strokeAndFill 属性 + */ + private checkMode(mode: GraphicModeProp, value: boolean) { + switch (mode) { + case GraphicModeProp.Fill: + this.propFill = value; + this.propFillSet = true; + break; + case GraphicModeProp.Stroke: + this.propStroke = value; + break; + case GraphicModeProp.StrokeAndFill: + this.strokeAndFill = true; + break; + } + if (this.strokeAndFill) { + this.mode = GraphicMode.StrokeAndFill; + } else { + if (!this.propFillSet) { + if (this.propStroke) { + this.mode = GraphicMode.Stroke; + } else { + this.mode = GraphicMode.Fill; + } + } else { + if (this.propFill && this.propStroke) { + this.mode = GraphicMode.FillAndStroke; + } else if (this.propFill) { + this.mode = GraphicMode.Fill; + } else if (this.propStroke) { + this.mode = GraphicMode.Stroke; + } else { + this.mode = GraphicMode.Fill; + } + } + } + this.update(); + } + /** * 设置画布的渲染状态,在实际渲染前调用 * @param canvas 要设置的画布 @@ -144,7 +195,60 @@ export abstract class GraphicItemBase namespace?: ElementNamespace, parentComponent?: ComponentInternalInstance | null ): void { + if (isNil(prevValue) && isNil(nextValue)) return; switch (key) { + case 'fill': + if (!this.assertType(nextValue, 'number', key)) return; + this.checkMode(GraphicModeProp.Fill, nextValue); + break; + case 'stroke': + if (!this.assertType(nextValue, 'number', key)) return; + this.checkMode(GraphicModeProp.Stroke, nextValue); + break; + case 'strokeAndFill': + if (!this.assertType(nextValue, 'number', key)) return; + this.checkMode(GraphicModeProp.StrokeAndFill, nextValue); + break; + case 'fillRule': + if (!this.assertType(nextValue, 'string', key)) return; + this.setFillRule(nextValue); + break; + case 'fillStyle': + this.setFillStyle(nextValue); + break; + case 'strokeStyle': + this.setStrokeStyle(nextValue); + break; + case 'lineWidth': + if (!this.assertType(nextValue, 'number', key)) return; + this.lineWidth = nextValue; + this.update(); + break; + case 'lineDash': + if (!this.assertType(nextValue, Array, key)) return; + this.lineDash = nextValue; + this.update(); + break; + case 'lineDashOffset': + if (!this.assertType(nextValue, 'number', key)) return; + this.lineDashOffset = nextValue; + this.update(); + break; + case 'lineJoin': + if (!this.assertType(nextValue, 'string', key)) return; + this.lineJoin = nextValue; + this.update(); + break; + case 'lineCap': + if (!this.assertType(nextValue, 'string', key)) return; + this.lineCap = nextValue; + this.update(); + break; + case 'miterLimit': + if (!this.assertType(nextValue, 'number', key)) return; + this.miterLimit = nextValue; + this.update(); + break; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } From 136de3072bf948ebfccbd4b10f683fe3d3741841 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Tue, 24 Dec 2024 19:57:44 +0800 Subject: [PATCH 05/22] fix: strokeAndFill in checkMode --- src/core/render/preset/graphics.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index d75c4ef..6e1a048 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -143,7 +143,7 @@ export abstract class GraphicItemBase this.propStroke = value; break; case GraphicModeProp.StrokeAndFill: - this.strokeAndFill = true; + this.strokeAndFill = value; break; } if (this.strokeAndFill) { From 9d48e9c09d12a25155de6de8f8dd84ba503a483d Mon Sep 17 00:00:00 2001 From: strawberry42271 <2806566736@qq.com> Date: Wed, 25 Dec 2024 17:56:59 +0800 Subject: [PATCH 06/22] =?UTF-8?q?feat:=20Icon\winskin=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/preset/misc.ts | 231 +++++++++++++++++++++++++++++- src/core/render/renderer/props.ts | 12 +- 2 files changed, 234 insertions(+), 9 deletions(-) diff --git a/src/core/render/preset/misc.ts b/src/core/render/preset/misc.ts index fcb3847..8b27b78 100644 --- a/src/core/render/preset/misc.ts +++ b/src/core/render/preset/misc.ts @@ -1,9 +1,18 @@ import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d'; import { Sprite } from '../sprite'; -import { ERenderItemEvent, RenderItem, RenderItemPosition } from '../item'; +import { + ERenderItemEvent, + IAnimateFrame, + renderEmits, + RenderItem, + RenderItemPosition +} from '../item'; import { Transform } from '../transform'; import { ElementNamespace, ComponentInternalInstance } from 'vue'; import { AutotileRenderable, RenderableData } from '../cache'; +import { texture } from '../cache'; +import { isNil } from 'lodash-es'; +import { logger } from '@/core/common/logger'; type CanvasStyle = string | CanvasGradient | CanvasPattern; @@ -204,7 +213,7 @@ export class Comment extends RenderItem { export interface EIconEvent extends ERenderItemEvent {} -export class Icon extends RenderItem { +export class Icon extends RenderItem implements IAnimateFrame { /** 图标id */ icon: AllNumbers = 0; /** 帧数 */ @@ -217,13 +226,69 @@ export class Icon extends RenderItem { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + const renderable = this.renderable; + if (!renderable) return; + const [x, y, w, h] = renderable.render[0]; + const cw = canvas.width; + const ch = canvas.height; + const frame = this.animate + ? RenderItem.animatedFrame % renderable.frame + : 0; + if (this.animate) { + if (renderable.autotile) { + ctx.drawImage(renderable.image[0], x, y, w, h, 0, 0, cw, ch); + } else { + ctx.drawImage(renderable.image, x, y, w, h, 0, 0, cw, ch); + } + } else { + const [x1, y1, w1, h1] = renderable.render[frame]; + if (renderable.autotile) { + ctx.drawImage( + renderable.image[0], + x1, + y1, + w1, + h1, + 0, + 0, + cw, + ch + ); + } else { + ctx.drawImage(renderable.image, x1, y1, w1, h1, 0, 0, cw, ch); + } + this.update(this), renderEmits.addFramer(this); + } + } /** * 设置图标 * @param id 图标id */ - setIcon(id: AllIds | AllNumbers) {} + setIcon(id: AllIds | AllNumbers) { + const num = typeof id === 'number' ? id : texture.idNumberMap[id]; + const renderable = texture.getRenderable(num); + + if (!renderable) { + //todo: logger.warn() + return; + } else { + this.icon = num; + renderable.animate = 0; + this.renderable = renderable; + this.frame = renderable.frame; + } + this.update(); + } + + /** + * 更新动画帧 + */ + updateFrameAnimate(): void { + this.update(this); + } patchProp( key: string, @@ -239,10 +304,12 @@ export class Icon extends RenderItem { case 'animate': if (!this.assertType(nextValue, 'boolean', key)) return; this.animate = nextValue; + this.update(); return; case 'frame': if (!this.assertType(nextValue, 'number', key)) return; this.frame = nextValue; + this.update(); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -267,19 +334,162 @@ export class Winskin extends RenderItem { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + const img = this.image; + const x = 0; + const y = 0; + const w = canvas.width; + const h = canvas.height; + const sz = this.borderSize / 32; + ctx.drawImage(img, 128, 0, 16, 16, x, y, 16 * sz, 16 * sz); + for (var dx = 0; dx < w - 64 * sz; dx += 32 * sz) { + ctx.drawImage( + img, + 144, + 0, + 32, + 16, + x + dx + 16, + y, + 32 * sz, + 16 * sz + ); + ctx.drawImage( + img, + 144, + 48, + 32, + 16, + x + dx + 16, + y + h - 16 * sz, + 32 * sz, + 16 * sz + ); + } + ctx.drawImage( + img, + 144, + 0, + w - dx - 32, + 16, + x + dx + 16 * sz, + y, + w - dx - 32 * sz, + 16 * sz + ); + ctx.drawImage( + img, + 144, + 48, + w - dx - 32, + 16, + x + dx + 16 * sz, + y + h - 16 * sz, + w - dx - 32 * sz, + 16 * sz + ); + ctx.drawImage( + img, + 176, + 0, + 16, + 16, + x + w - 16 * sz, + y, + 16 * sz, + 16 * sz + ); + // 左右 + for (var dy = 0; dy < h - 64 * sz; dy += 32 * sz) { + ctx.drawImage( + img, + 128, + 16, + 16, + 32, + x, + y + dy + 16 * sz, + 16 * sz, + 32 * sz + ); + ctx.drawImage( + img, + 176, + 16, + 16, + 32, + x + w - 16 * sz, + y + dy + 16 * sz, + 16 * sz, + 32 * sz + ); + } + ctx.drawImage( + img, + 128, + 16, + 16, + h - dy - 32, + x, + y + dy + 16 * sz, + 16 * sz, + h - dy - 32 * sz + ); + ctx.drawImage( + img, + 176, + 16, + 16, + h - dy - 32, + x + w - 16 * sz, + y + dy + 16 * sz, + 16 * sz, + h - dy - 32 * sz + ); + // 下方 + ctx.drawImage( + img, + 128, + 48, + 16, + 16, + x, + y + h - 16 * sz, + 16 * sz, + 16 * sz + ); + ctx.drawImage( + img, + 176, + 48, + 16, + 16, + x + w - 16 * sz, + y + h - 16 * sz, + 16 * sz, + 16 * sz + ); + this.update(); + } /** * 设置winskin图片 * @param image winskin图片 */ - setImage(image: SizedCanvasImageSource) {} + setImage(image: SizedCanvasImageSource) { + this.image = image; + this.update(); + } /** * 设置边框大小 * @param size 边框大小 */ - setBorderSize(size: number) {} + setBorderSize(size: number) { + this.borderSize = size; + this.update(); + } patchProp( key: string, @@ -289,6 +499,13 @@ export class Winskin extends RenderItem { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'image': + this.setImage(nextValue); + return; + case 'borderSize': + if (!this.assertType(nextValue, 'number', key)) return; + this.setBorderSize(nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } diff --git a/src/core/render/renderer/props.ts b/src/core/render/renderer/props.ts index ddc9cfc..71a55dc 100644 --- a/src/core/render/renderer/props.ts +++ b/src/core/render/renderer/props.ts @@ -7,6 +7,7 @@ import { } from '../preset/layer'; import type { EnemyCollection } from '@/game/enemy/damage'; import { ILineProperty } from '../preset/graphics'; +import { SizedCanvasImageSource } from '../preset'; export interface CustomProps { _item: (props: BaseProps) => RenderItem; @@ -152,6 +153,13 @@ export interface PathProps extends GraphicPropsBase { path?: Path2D; } -export interface IconProps extends BaseProps {} +export interface IconProps extends BaseProps { + icon: AllNumbers; + frame: number; + animate: boolean; +} -export interface WinskinProps extends BaseProps {} +export interface WinskinProps extends BaseProps { + image: SizedCanvasImageSource; + borderSize: number; +} From 3057d740b68a0528566948984238195c1f9fe5ef Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Thu, 26 Dec 2024 18:16:59 +0800 Subject: [PATCH 07/22] =?UTF-8?q?feat:=20=E5=9C=86=E8=A7=92=E7=9F=A9?= =?UTF-8?q?=E5=BD=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/preset/graphics.ts | 102 +++++++++++++++++++++++++- src/core/render/renderer/elements.tsx | 2 + src/core/render/renderer/map.ts | 4 +- src/core/render/renderer/props.ts | 23 ++++++ 4 files changed, 129 insertions(+), 2 deletions(-) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 6e1a048..56dc874 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -1,5 +1,5 @@ import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d'; -import { ERenderItemEvent, RenderItem } from '../item'; +import { ERenderItemEvent, RenderItem, RenderItemPosition } from '../item'; import { Transform } from '../transform'; import { ElementNamespace, ComponentInternalInstance } from 'vue'; import { isNil } from 'lodash-es'; @@ -773,3 +773,103 @@ export class Path extends GraphicItemBase { super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } } + +const enum RectRType { + /** 圆角为椭圆 */ + Ellipse, + /** 圆角为二次贝塞尔曲线 */ + Quad, + /** 圆角为三次贝塞尔曲线。该模式下,包含两个控制点,一个控制点位于上下矩形边延长线,另一个控制点位于左右矩形边延长线 */ + Cubic, + /** 圆角为直线连接 */ + Line +} + +export class RectR extends GraphicItemBase { + /** 矩形路径 */ + private path: Path2D; + + /** 圆角类型 */ + roundType: RectRType = RectRType.Ellipse; + /** 横向圆角半径 */ + radiusX: number = 0; + /** 纵向圆角半径 */ + radiusY: number = 0; + /** + * 二次贝塞尔曲线下,表示控制点的横向比例,控制点在上下矩形边与圆角的交界处为0,在左右矩形边与圆角的交界处延长线为1 + * 三次贝塞尔曲线下,表示在上下矩形边延长线上的控制点的比例 + */ + cpx: number = 0; + /** + * 二次贝塞尔曲线下,表示控制点的纵向比例,控制点在左右矩形边与圆角的交界处为0,在上下矩形边与圆角的交界处延长线为1 + * 三次贝塞尔曲线下,表示在左右矩形边延长线上的控制点的比例 + */ + cpy: number = 0; + + constructor( + type: RenderItemPosition, + cache: boolean = false, + fall: boolean = false + ) { + super(type, cache, fall); + + const path = new Path2D(); + path.rect(this.x, this.y, this.width, this.height); + this.path = path; + } + + /** + * 更新路径 + */ + private updatePath() {} + + /** + * 设置圆角半径 + * @param x 横向半径 + * @param y 纵向半径 + */ + setRadius(x: number, y: number) {} + + /** + * 设置贝塞尔曲线模式下的控制点 + * @param x cpx + * @param y cpy + */ + setControl(x: number, y: number) {} + + protected render( + canvas: MotaOffscreenCanvas2D, + transform: Transform + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + switch (this.mode) { + case GraphicMode.Fill: + ctx.fill(this.path, this.fillRule); + break; + case GraphicMode.Stroke: + ctx.stroke(this.path); + break; + case GraphicMode.FillAndStroke: + ctx.fill(this.path, this.fillRule); + ctx.stroke(this.path); + break; + case GraphicMode.StrokeAndFill: + ctx.stroke(this.path); + ctx.fill(this.path, this.fillRule); + break; + } + } + + patchProp( + key: string, + prevValue: any, + nextValue: any, + namespace?: ElementNamespace, + parentComponent?: ComponentInternalInstance | null + ): void { + switch (key) { + } + super.patchProp(key, prevValue, nextValue, namespace, parentComponent); + } +} diff --git a/src/core/render/renderer/elements.tsx b/src/core/render/renderer/elements.tsx index 2d08c29..4b9e1cc 100644 --- a/src/core/render/renderer/elements.tsx +++ b/src/core/render/renderer/elements.tsx @@ -26,6 +26,7 @@ import { PathProps, QuadraticProps, RectProps, + RectRProps, ShaderProps, SpriteProps, TextProps, @@ -101,6 +102,7 @@ declare module 'vue/jsx-runtime' { 'g-bezier': TagDefine; 'g-quad': TagDefine; 'g-path': TagDefine; + 'g-rectr': TagDefine; icon: TagDefine; winskin: TagDefine; } diff --git a/src/core/render/renderer/map.ts b/src/core/render/renderer/map.ts index b3b76b2..c67dee3 100644 --- a/src/core/render/renderer/map.ts +++ b/src/core/render/renderer/map.ts @@ -14,7 +14,8 @@ import { Line, Path, QuadraticCurve, - Rect + Rect, + RectR } from '../preset/graphics'; import { BaseProps } from './props'; @@ -189,6 +190,7 @@ tagMap.register('g-line', standardElementNoCache(Line)); tagMap.register('g-bezier', standardElementNoCache(BezierCurve)); tagMap.register('g-quad', standardElementNoCache(QuadraticCurve)); tagMap.register('g-path', standardElementNoCache(Path)); +tagMap.register('g-rectr', standardElementNoCache(RectR)); tagMap.register('icon', standardElementNoCache(Icon)); tagMap.register('winskin', (_0, _1, props) => { if (!props) return new Winskin(core.material.images.images['winskin.png']); diff --git a/src/core/render/renderer/props.ts b/src/core/render/renderer/props.ts index 71a55dc..10bf408 100644 --- a/src/core/render/renderer/props.ts +++ b/src/core/render/renderer/props.ts @@ -153,6 +153,29 @@ export interface PathProps extends GraphicPropsBase { path?: Path2D; } +export interface RectRProps extends GraphicPropsBase { + /** 圆角半径,此参数传入时,radiusX 和 radiusY 应保持一致 */ + radius: number; + /** 圆角横向半径 */ + radiusX?: number; + /** 圆角纵向半径 */ + radiusY?: number; + /** 圆角为线模式 */ + line?: boolean; + /** 圆角为椭圆模式,默认值 */ + ellipse?: boolean; + /** 圆角为二次贝塞尔曲线模式 */ + quad?: boolean; + /** 圆角为三次贝塞尔曲线模式 */ + cubic?: boolean; + /** 控制点,此参数传入时,cpx 和 cpy 应保持一致 */ + cp?: number; + /** 横向控制点 */ + cpx?: number; + /** 纵向控制点 */ + cpy?: number; +} + export interface IconProps extends BaseProps { icon: AllNumbers; frame: number; From b48dfae2112e482943059d3b7ff168b593ede3b0 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sat, 28 Dec 2024 16:46:22 +0800 Subject: [PATCH 08/22] =?UTF-8?q?fix:=20graphic=E5=85=83=E7=B4=A0=E9=94=99?= =?UTF-8?q?=E4=BD=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/renderer/map.ts | 64 ++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/src/core/render/renderer/map.ts b/src/core/render/renderer/map.ts index c67dee3..81ac6b2 100644 --- a/src/core/render/renderer/map.ts +++ b/src/core/render/renderer/map.ts @@ -4,7 +4,14 @@ import { ElementNamespace, VNodeProps } from 'vue'; import { Container } from '../container'; import { MotaRenderer } from '../render'; import { Sprite } from '../sprite'; -import { Comment, Icon, Image, Text, Winskin } from '../preset/misc'; +import { + Comment, + ETextEvent, + Icon, + Image, + Text, + Winskin +} from '../preset/misc'; import { Shader } from '../shader'; import { Animate, Damage, EDamageEvent, Layer, LayerGroup } from '../preset'; import { @@ -14,8 +21,7 @@ import { Line, Path, QuadraticCurve, - Rect, - RectR + Rect } from '../preset/graphics'; import { BaseProps } from './props'; @@ -91,6 +97,40 @@ const standardElementNoCache = ( }; }; +const enum ElementState { + None = 0, + Cache = 1, + Fall = 2 +} + +/** + * standardElementFor + */ +const se = ( + Item: new ( + type: RenderItemPosition, + cache?: boolean, + fall?: boolean + ) => RenderItem, + position: RenderItemPosition, + state: ElementState +) => { + const defaultCache = !!(state & ElementState.Cache); + const defautFall = !!(state & ElementState.Fall); + + return (_0: any, _1: any, props?: any) => { + if (!props) return new Item('absolute'); + else { + const { + type = position, + cache = defaultCache, + fall = defautFall + } = props; + return new Item(type, cache, fall); + } + }; +}; + // Default elements tagMap.register('container', standardElement(Container)); tagMap.register('template', standardElement(Container)); @@ -98,7 +138,7 @@ tagMap.register('mota-renderer', (_0, _1, props) => { return new MotaRenderer(props?.id); }); tagMap.register('sprite', standardElement(Sprite)); -tagMap.register('text', (_0, _1, props) => { +tagMap.register('text', (_0, _1, props) => { if (!props) return new Text(); else { const { type = 'static', text = '' } = props; @@ -183,14 +223,14 @@ tagMap.register('damage', (_0, _1, props) => { tagMap.register('animation', (_0, _1, props) => { return new Animate(); }); -tagMap.register('g-rect', standardElementNoCache(Rect)); -tagMap.register('g-circle', standardElementNoCache(Circle)); -tagMap.register('g-ellipse', standardElementNoCache(Ellipse)); -tagMap.register('g-line', standardElementNoCache(Line)); -tagMap.register('g-bezier', standardElementNoCache(BezierCurve)); -tagMap.register('g-quad', standardElementNoCache(QuadraticCurve)); -tagMap.register('g-path', standardElementNoCache(Path)); -tagMap.register('g-rectr', standardElementNoCache(RectR)); +tagMap.register('g-rect', se(Rect, 'absolute', ElementState.None)); +tagMap.register('g-circle', se(Circle, 'absolute', ElementState.None)); +tagMap.register('g-ellipse', se(Ellipse, 'absolute', ElementState.None)); +tagMap.register('g-line', se(Line, 'absolute', ElementState.None)); +tagMap.register('g-bezier', se(BezierCurve, 'absolute', ElementState.None)); +tagMap.register('g-quad', se(QuadraticCurve, 'absolute', ElementState.None)); +tagMap.register('g-path', se(Path, 'absolute', ElementState.None)); +tagMap.register('g-rectr', se(Path, 'absolute', ElementState.None)); tagMap.register('icon', standardElementNoCache(Icon)); tagMap.register('winskin', (_0, _1, props) => { if (!props) return new Winskin(core.material.images.images['winskin.png']); From 1650865a6aba0096dfa7d1436b344407c4c26044 Mon Sep 17 00:00:00 2001 From: strawberry42271 <2806566736@qq.com> Date: Mon, 23 Dec 2024 19:23:13 +0800 Subject: [PATCH 09/22] =?UTF-8?q?feat:graphics=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/preset/graphics.ts | 228 +++++++++++++++++++++++++---- 1 file changed, 199 insertions(+), 29 deletions(-) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 57f9aaa..5ddf392 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -2,6 +2,7 @@ import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d'; import { ERenderItemEvent, RenderItem } from '../item'; import { Transform } from '../transform'; import { ElementNamespace, ComponentInternalInstance } from 'vue'; +import { isNil } from 'lodash-es'; /* * Expected usage (this comment needs to be deleted after implementing correctly): @@ -54,14 +55,14 @@ export interface EGraphicItemEvent extends ERenderItemEvent {} export abstract class GraphicItemBase extends RenderItem - implements IGraphicProperty + implements Required { mode: number = GraphicMode.Fill; fill: CanvasStyle = '#fff'; stroke: CanvasStyle = '#fff'; lineWidth: number = 2; - lineDash?: number[] | undefined; - lineDashOffset?: number | undefined; + lineDash: number[] = []; + lineDashOffset: number = 0; lineJoin: CanvasLineJoin = 'bevel'; lineCap: CanvasLineCap = 'butt'; miterLimit: number = 10; @@ -71,31 +72,50 @@ export abstract class GraphicItemBase * 设置描边绘制的信息 * @param options 线的信息 */ - setLineOption(options: Partial) {} + setLineOption(options: Partial) { + if (!isNil(options.lineWidth)) this.lineWidth = options.lineWidth; + if (!isNil(options.lineDash)) this.lineDash = options.lineDash; + if (!isNil(options.lineDashOffset)) this.lineDashOffset = options.lineDashOffset; + if (!isNil(options.lineJoin)) this.lineJoin = options.lineJoin; + if (!isNil(options.lineCap)) this.lineCap = options.lineCap; + if (!isNil(options.miterLimit)) this.miterLimit = options.miterLimit; + } /** * 设置填充样式 * @param style 绘制样式 */ - setFillStyle(style: CanvasStyle) {} + setFillStyle(style: CanvasStyle) { + this.fill = style; + this.update(); + } /** * 设置描边样式 * @param style 绘制样式 */ - setStrokeStyle(style: CanvasStyle) {} + setStrokeStyle(style: CanvasStyle) { + this.stroke = style; + this.update(); + } /** * 设置填充原则 * @param rule 填充原则 */ - setFillRule(rule: CanvasFillRule) {} + setFillRule(rule: CanvasFillRule) { + this.fillRule = rule; + this.update(); + } /** * 设置绘制模式,是描边还是填充 * @param mode 绘制模式 */ - setMode(mode: GraphicMode) {} + setMode(mode: GraphicMode) { + this.mode = mode; + this.update(); + } /** * 设置画布的渲染状态,在实际渲染前调用 @@ -103,7 +123,16 @@ export abstract class GraphicItemBase */ protected setCanvasState(canvas: MotaOffscreenCanvas2D) { const ctx = canvas.ctx; - ctx.fillStyle = this.fill; // 示例,后面的都按这个写,不需要save restore,写完把这个注释删了 + ctx.fillStyle = this.fill; + ctx.strokeStyle = this.stroke; + ctx.lineWidth = this.lineWidth; + ctx.setLineDash(this.lineDash) + ctx.lineDashOffset = this.lineDashOffset; + ctx.lineJoin = this.lineJoin; + ctx.lineCap = this.lineCap; + ctx.miterLimit = this.miterLimit; + ctx.fill(this.fillRule); + this.update(); } patchProp( @@ -156,20 +185,50 @@ export class Circle extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + ctx.beginPath(); + ctx.arc(this.x,this.y,this.radius,this.start,this.end); + + switch (this.mode) { + case GraphicMode.Fill: + ctx.fill(this.fillRule); + break; + case GraphicMode.Stroke: + ctx.stroke(); + break; + case GraphicMode.FillAndStroke: + ctx.fill(this.fillRule); + ctx.stroke(); + break; + case GraphicMode.StrokeAndFill: + ctx.stroke(); + ctx.fill(this.fillRule); + break; + } + } /** * 设置圆的半径 * @param radius 半径 */ - setRadius(radius: number) {} + setRadius(radius: number) { + this.radius = radius; + this.size(radius*2,radius*2); + this.update(); + } /** * 设置圆的起始与终止角度 * @param start 起始角度 * @param end 终止角度 */ - setAngle(start: number, end: number) {} + setAngle(start: number, end: number) { + this.start = start; + this.end = end; + this.update(); + } patchProp( key: string, @@ -193,21 +252,52 @@ export class Ellipse extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + ctx.beginPath(); + ctx.ellipse(this.x,this.y,this.radiusX,this.radiusY,0,this.start,this.end); + + switch (this.mode) { + case GraphicMode.Fill: + ctx.fill(this.fillRule); + break; + case GraphicMode.Stroke: + ctx.stroke(); + break; + case GraphicMode.FillAndStroke: + ctx.fill(this.fillRule); + ctx.stroke(); + break; + case GraphicMode.StrokeAndFill: + ctx.stroke(); + ctx.fill(this.fillRule); + break; + } + } /** * 设置椭圆的横纵轴长度 * @param x 横轴长度 * @param y 纵轴长度 */ - setRadius(x: number, y: number) {} + setRadius(x: number, y: number) { + this.radiusX = x; + this.radiusY = y; + this.update(); + } + /** * 设置椭圆的起始与终止角度 * @param start 起始角度 * @param end 终止角度 */ - setAngle(start: number, end: number) {} + setAngle(start: number, end: number) { + this.start = start; + this.end = end; + this.update(); + } patchProp( key: string, @@ -231,17 +321,33 @@ export class Line extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + ctx.beginPath(); + ctx.moveTo(this.x1,this.y1) + ctx.lineTo(this.x2,this.y2); + ctx.stroke(); + + } /** * 设置第一个点的横纵坐标 */ - setPoint1(x: number, y: number) {} + setPoint1(x: number, y: number) { + this.x1 = x; + this.y1 = y; + this.update(); + } /** * 设置第二个点的横纵坐标 */ - setPoint2(x: number, y: number) {} + setPoint2(x: number, y: number) { + this.x2 = x; + this.y2 = y; + this.update(); + } patchProp( key: string, @@ -269,27 +375,50 @@ export class BezierCurve extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + ctx.beginPath(); + ctx.moveTo(this.sx,this.sy) + ctx.bezierCurveTo(this.cp1x,this.cp1y,this.cp2x,this.cp2y,this.ex,this.ey); + ctx.stroke(); + } /** * 设置起始点坐标 */ - setStart(x: number, y: number) {} + setStart(x: number, y: number) { + this.sx = x; + this.sy = y; + this.update(); + } /** * 设置控制点1坐标 */ - setControl1(x: number, y: number) {} + setControl1(x: number, y: number) { + this.cp1x = x; + this.cp1y = y; + this.update(); + } /** * 设置控制点2坐标 */ - setControl2(x: number, y: number) {} + setControl2(x: number, y: number) { + this.cp2x = x; + this.cp2y = y; + this.update(); + } /** * 设置终点坐标 */ - setEnd(x: number, y: number) {} + setEnd(x: number, y: number) { + this.ex = x; + this.ey = y; + this.update(); + } patchProp( key: string, @@ -315,22 +444,41 @@ export class QuadraticCurve extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + ctx.beginPath(); + ctx.moveTo(this.sx,this.sy) + ctx.quadraticCurveTo(this.cpx,this.cpy,this.ex,this.ey); + ctx.stroke(); + } /** * 设置起始点坐标 */ - setStart(x: number, y: number) {} + setStart(x: number, y: number) { + this.sx = x; + this.sy = y; + this.update(); + } /** * 设置控制点坐标 */ - setControl(x: number, y: number) {} + setControl(x: number, y: number) { + this.cpx = x; + this.cpy = y; + this.update(); + } /** * 设置终点坐标 */ - setEnd(x: number, y: number) {} + setEnd(x: number, y: number) { + this.ex = x; + this.ey = y; + this.update(); + } patchProp( key: string, @@ -352,7 +500,26 @@ export class Path extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + switch (this.mode) { + case GraphicMode.Fill: + ctx.fill(this.path,this.fillRule); + break; + case GraphicMode.Stroke: + ctx.stroke(this.path); + break; + case GraphicMode.FillAndStroke: + ctx.fill(this.path,this.fillRule); + ctx.stroke(this.path); + break; + case GraphicMode.StrokeAndFill: + ctx.stroke(this.path); + ctx.fill(this.path,this.fillRule); + break; + } + } /** * 获取当前路径 @@ -365,7 +532,10 @@ export class Path extends GraphicItemBase { * 为路径添加路径 * @param path 要添加的路径 */ - addPath(path: Path2D) {} + addPath(path: Path2D) { + this.path.addPath(path); + this.update(); + } patchProp( key: string, From 29f1f00e232e4f5cca7315782cf7e19cb8e14b86 Mon Sep 17 00:00:00 2001 From: strawberry42271 <2806566736@qq.com> Date: Tue, 24 Dec 2024 17:11:49 +0800 Subject: [PATCH 10/22] =?UTF-8?q?feat:=20graphic=E7=9A=84patchProp?= =?UTF-8?q?=E5=86=99=E5=AE=8C=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/preset/graphics.ts | 105 +++++++++++++++++++++++++++++ src/core/render/renderer/props.ts | 44 ++++++++++-- 2 files changed, 143 insertions(+), 6 deletions(-) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 5ddf392..803d801 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -238,6 +238,18 @@ export class Circle extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'radius': + if (!this.assertType(nextValue, 'number', key)) return; + this.setRadius(nextValue); + return; + case 'start': + if (!this.assertType(nextValue, 'number', key)) return; + this.setAngle(nextValue,this.end); + return; + case 'end': + if (!this.assertType(nextValue, 'number', key)) return; + this.setAngle(this.start,nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } @@ -307,6 +319,22 @@ export class Ellipse extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'radiusX': + if (!this.assertType(nextValue, 'number', key)) return; + this.setRadius(nextValue,this.radiusY); + return; + case 'radiusY': + if (!this.assertType(nextValue, 'number', key)) return; + this.setRadius(this.radiusY,nextValue); + return; + case 'start': + if (!this.assertType(nextValue, 'number', key)) return; + this.setAngle(nextValue,this.end); + return; + case 'end': + if (!this.assertType(nextValue, 'number', key)) return; + this.setAngle(this.start,nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } @@ -357,6 +385,22 @@ export class Line extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'x1': + if (!this.assertType(nextValue, 'number', key)) return; + this.setPoint1(nextValue,this.y1); + return; + case 'y1': + if (!this.assertType(nextValue, 'number', key)) return; + this.setPoint1(this.x1,nextValue); + return; + case 'x2': + if (!this.assertType(nextValue, 'number', key)) return; + this.setPoint2(nextValue,this.y2); + return; + case 'y2': + if (!this.assertType(nextValue, 'number', key)) return; + this.setPoint2(this.x2,nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } @@ -428,6 +472,38 @@ export class BezierCurve extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'sx': + if (!this.assertType(nextValue, 'number', key)) return; + this.setStart(nextValue,this.sy); + return; + case 'sy': + if (!this.assertType(nextValue, 'number', key)) return; + this.setStart(this.sx,nextValue); + return; + case 'cp1x': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl1(nextValue,this.cp1y); + return; + case 'cp1y': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl1(this.cp1x,nextValue); + return; + case 'cp2x': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl2(nextValue,this.cp2y); + return; + case 'cp2y': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl2(this.cp2x,nextValue); + return; + case 'ex': + if (!this.assertType(nextValue, 'number', key)) return; + this.setEnd(nextValue,this.ey); + return; + case 'ey': + if (!this.assertType(nextValue, 'number', key)) return; + this.setEnd(this.ex,nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } @@ -488,6 +564,30 @@ export class QuadraticCurve extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'sx': + if (!this.assertType(nextValue, 'number', key)) return; + this.setStart(nextValue,this.sy); + return; + case 'sy': + if (!this.assertType(nextValue, 'number', key)) return; + this.setStart(this.sx,nextValue); + return; + case 'cpx': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl(nextValue,this.cpy); + return; + case 'cpy': + if (!this.assertType(nextValue, 'number', key)) return; + this.setControl(this.cpx,nextValue); + return; + case 'ex': + if (!this.assertType(nextValue, 'number', key)) return; + this.setEnd(nextValue,this.ey); + return; + case 'ey': + if (!this.assertType(nextValue, 'number', key)) return; + this.setEnd(this.ex,nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } @@ -545,6 +645,11 @@ export class Path extends GraphicItemBase { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'path': + if (!this.assertType(nextValue, Path2D, key)) return; + this.path = nextValue; + this.update(); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } diff --git a/src/core/render/renderer/props.ts b/src/core/render/renderer/props.ts index 61f688e..ddc9cfc 100644 --- a/src/core/render/renderer/props.ts +++ b/src/core/render/renderer/props.ts @@ -108,17 +108,49 @@ export interface GraphicPropsBase extends BaseProps, Partial { export interface RectProps extends GraphicPropsBase {} -export interface CirclesProps extends GraphicPropsBase {} +export interface CirclesProps extends GraphicPropsBase { + radius?: number; + start?: number; + end?: number; +} -export interface EllipseProps extends GraphicPropsBase {} +export interface EllipseProps extends GraphicPropsBase { + radiusX?: number; + radiusY?: number; + start?: number; + end?: number; +} -export interface LineProps extends GraphicPropsBase {} +export interface LineProps extends GraphicPropsBase { + x1?: number; + y1?: number; + x2?: number; + y2?: number; +} -export interface BezierProps extends GraphicPropsBase {} +export interface BezierProps extends GraphicPropsBase { + sx?: number; + sy?: number; + cp1x?: number; + cp1y?: number; + cp2x?: number; + cp2y?: number; + ex?: number; + ey?: number; +} -export interface QuadraticProps extends GraphicPropsBase {} +export interface QuadraticProps extends GraphicPropsBase { + sx?: number; + sy?: number; + cpx?: number; + cpy?: number; + ex?: number; + ey?: number; +} -export interface PathProps extends GraphicPropsBase {} +export interface PathProps extends GraphicPropsBase { + path?: Path2D; +} export interface IconProps extends BaseProps {} From 5c9419280ecb061c9c25495ab609cfa049d7e1f3 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Tue, 24 Dec 2024 18:18:53 +0800 Subject: [PATCH 11/22] style: graphics.ts --- src/core/render/preset/graphics.ts | 95 +++++++++++++++++------------- 1 file changed, 55 insertions(+), 40 deletions(-) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 803d801..3624fd9 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -75,10 +75,12 @@ export abstract class GraphicItemBase setLineOption(options: Partial) { if (!isNil(options.lineWidth)) this.lineWidth = options.lineWidth; if (!isNil(options.lineDash)) this.lineDash = options.lineDash; - if (!isNil(options.lineDashOffset)) this.lineDashOffset = options.lineDashOffset; + if (!isNil(options.lineDashOffset)) + this.lineDashOffset = options.lineDashOffset; if (!isNil(options.lineJoin)) this.lineJoin = options.lineJoin; if (!isNil(options.lineCap)) this.lineCap = options.lineCap; if (!isNil(options.miterLimit)) this.miterLimit = options.miterLimit; + this.update(); } /** @@ -126,7 +128,7 @@ export abstract class GraphicItemBase ctx.fillStyle = this.fill; ctx.strokeStyle = this.stroke; ctx.lineWidth = this.lineWidth; - ctx.setLineDash(this.lineDash) + ctx.setLineDash(this.lineDash); ctx.lineDashOffset = this.lineDashOffset; ctx.lineJoin = this.lineJoin; ctx.lineCap = this.lineCap; @@ -189,7 +191,7 @@ export class Circle extends GraphicItemBase { const ctx = canvas.ctx; this.setCanvasState(canvas); ctx.beginPath(); - ctx.arc(this.x,this.y,this.radius,this.start,this.end); + ctx.arc(this.x, this.y, this.radius, this.start, this.end); switch (this.mode) { case GraphicMode.Fill: @@ -215,7 +217,7 @@ export class Circle extends GraphicItemBase { */ setRadius(radius: number) { this.radius = radius; - this.size(radius*2,radius*2); + this.size(radius * 2, radius * 2); this.update(); } @@ -244,11 +246,11 @@ export class Circle extends GraphicItemBase { return; case 'start': if (!this.assertType(nextValue, 'number', key)) return; - this.setAngle(nextValue,this.end); + this.setAngle(nextValue, this.end); return; case 'end': if (!this.assertType(nextValue, 'number', key)) return; - this.setAngle(this.start,nextValue); + this.setAngle(this.start, nextValue); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -268,7 +270,15 @@ export class Ellipse extends GraphicItemBase { const ctx = canvas.ctx; this.setCanvasState(canvas); ctx.beginPath(); - ctx.ellipse(this.x,this.y,this.radiusX,this.radiusY,0,this.start,this.end); + ctx.ellipse( + this.x, + this.y, + this.radiusX, + this.radiusY, + 0, + this.start, + this.end + ); switch (this.mode) { case GraphicMode.Fill: @@ -299,7 +309,6 @@ export class Ellipse extends GraphicItemBase { this.update(); } - /** * 设置椭圆的起始与终止角度 * @param start 起始角度 @@ -321,19 +330,19 @@ export class Ellipse extends GraphicItemBase { switch (key) { case 'radiusX': if (!this.assertType(nextValue, 'number', key)) return; - this.setRadius(nextValue,this.radiusY); + this.setRadius(nextValue, this.radiusY); return; case 'radiusY': if (!this.assertType(nextValue, 'number', key)) return; - this.setRadius(this.radiusY,nextValue); + this.setRadius(this.radiusY, nextValue); return; case 'start': if (!this.assertType(nextValue, 'number', key)) return; - this.setAngle(nextValue,this.end); + this.setAngle(nextValue, this.end); return; case 'end': if (!this.assertType(nextValue, 'number', key)) return; - this.setAngle(this.start,nextValue); + this.setAngle(this.start, nextValue); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -353,10 +362,9 @@ export class Line extends GraphicItemBase { const ctx = canvas.ctx; this.setCanvasState(canvas); ctx.beginPath(); - ctx.moveTo(this.x1,this.y1) - ctx.lineTo(this.x2,this.y2); + ctx.moveTo(this.x1, this.y1); + ctx.lineTo(this.x2, this.y2); ctx.stroke(); - } /** @@ -387,19 +395,19 @@ export class Line extends GraphicItemBase { switch (key) { case 'x1': if (!this.assertType(nextValue, 'number', key)) return; - this.setPoint1(nextValue,this.y1); + this.setPoint1(nextValue, this.y1); return; case 'y1': if (!this.assertType(nextValue, 'number', key)) return; - this.setPoint1(this.x1,nextValue); + this.setPoint1(this.x1, nextValue); return; case 'x2': if (!this.assertType(nextValue, 'number', key)) return; - this.setPoint2(nextValue,this.y2); + this.setPoint2(nextValue, this.y2); return; case 'y2': if (!this.assertType(nextValue, 'number', key)) return; - this.setPoint2(this.x2,nextValue); + this.setPoint2(this.x2, nextValue); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -423,8 +431,15 @@ export class BezierCurve extends GraphicItemBase { const ctx = canvas.ctx; this.setCanvasState(canvas); ctx.beginPath(); - ctx.moveTo(this.sx,this.sy) - ctx.bezierCurveTo(this.cp1x,this.cp1y,this.cp2x,this.cp2y,this.ex,this.ey); + ctx.moveTo(this.sx, this.sy); + ctx.bezierCurveTo( + this.cp1x, + this.cp1y, + this.cp2x, + this.cp2y, + this.ex, + this.ey + ); ctx.stroke(); } @@ -474,35 +489,35 @@ export class BezierCurve extends GraphicItemBase { switch (key) { case 'sx': if (!this.assertType(nextValue, 'number', key)) return; - this.setStart(nextValue,this.sy); + this.setStart(nextValue, this.sy); return; case 'sy': if (!this.assertType(nextValue, 'number', key)) return; - this.setStart(this.sx,nextValue); + this.setStart(this.sx, nextValue); return; case 'cp1x': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl1(nextValue,this.cp1y); + this.setControl1(nextValue, this.cp1y); return; case 'cp1y': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl1(this.cp1x,nextValue); + this.setControl1(this.cp1x, nextValue); return; case 'cp2x': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl2(nextValue,this.cp2y); + this.setControl2(nextValue, this.cp2y); return; case 'cp2y': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl2(this.cp2x,nextValue); + this.setControl2(this.cp2x, nextValue); return; case 'ex': if (!this.assertType(nextValue, 'number', key)) return; - this.setEnd(nextValue,this.ey); + this.setEnd(nextValue, this.ey); return; case 'ey': if (!this.assertType(nextValue, 'number', key)) return; - this.setEnd(this.ex,nextValue); + this.setEnd(this.ex, nextValue); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -524,8 +539,8 @@ export class QuadraticCurve extends GraphicItemBase { const ctx = canvas.ctx; this.setCanvasState(canvas); ctx.beginPath(); - ctx.moveTo(this.sx,this.sy) - ctx.quadraticCurveTo(this.cpx,this.cpy,this.ex,this.ey); + ctx.moveTo(this.sx, this.sy); + ctx.quadraticCurveTo(this.cpx, this.cpy, this.ex, this.ey); ctx.stroke(); } @@ -566,27 +581,27 @@ export class QuadraticCurve extends GraphicItemBase { switch (key) { case 'sx': if (!this.assertType(nextValue, 'number', key)) return; - this.setStart(nextValue,this.sy); + this.setStart(nextValue, this.sy); return; case 'sy': if (!this.assertType(nextValue, 'number', key)) return; - this.setStart(this.sx,nextValue); + this.setStart(this.sx, nextValue); return; case 'cpx': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl(nextValue,this.cpy); + this.setControl(nextValue, this.cpy); return; case 'cpy': if (!this.assertType(nextValue, 'number', key)) return; - this.setControl(this.cpx,nextValue); + this.setControl(this.cpx, nextValue); return; case 'ex': if (!this.assertType(nextValue, 'number', key)) return; - this.setEnd(nextValue,this.ey); + this.setEnd(nextValue, this.ey); return; case 'ey': if (!this.assertType(nextValue, 'number', key)) return; - this.setEnd(this.ex,nextValue); + this.setEnd(this.ex, nextValue); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -605,18 +620,18 @@ export class Path extends GraphicItemBase { this.setCanvasState(canvas); switch (this.mode) { case GraphicMode.Fill: - ctx.fill(this.path,this.fillRule); + ctx.fill(this.path, this.fillRule); break; case GraphicMode.Stroke: ctx.stroke(this.path); break; case GraphicMode.FillAndStroke: - ctx.fill(this.path,this.fillRule); + ctx.fill(this.path, this.fillRule); ctx.stroke(this.path); break; case GraphicMode.StrokeAndFill: ctx.stroke(this.path); - ctx.fill(this.path,this.fillRule); + ctx.fill(this.path, this.fillRule); break; } } From 2aa0ffe12ac0cf353c002a31a19fa37a33a9b4c8 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Tue, 24 Dec 2024 19:55:52 +0800 Subject: [PATCH 12/22] feat: patchProp for GraphicItemBase --- src/core/render/preset/graphics.ts | 104 +++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 3624fd9..d75c4ef 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -51,6 +51,12 @@ export const enum GraphicMode { StrokeAndFill } +const enum GraphicModeProp { + Fill, + Stroke, + StrokeAndFill +} + export interface EGraphicItemEvent extends ERenderItemEvent {} export abstract class GraphicItemBase @@ -68,6 +74,11 @@ export abstract class GraphicItemBase miterLimit: number = 10; fillRule: CanvasFillRule = 'nonzero'; + private propFill: boolean = true; + private propStroke: boolean = false; + private strokeAndFill: boolean = false; + private propFillSet: boolean = false; + /** * 设置描边绘制的信息 * @param options 线的信息 @@ -119,6 +130,46 @@ export abstract class GraphicItemBase this.update(); } + /** + * 检查渲染模式,参考 {@link GraphicPropsBase} 中的 fill stroke strokeAndFill 属性 + */ + private checkMode(mode: GraphicModeProp, value: boolean) { + switch (mode) { + case GraphicModeProp.Fill: + this.propFill = value; + this.propFillSet = true; + break; + case GraphicModeProp.Stroke: + this.propStroke = value; + break; + case GraphicModeProp.StrokeAndFill: + this.strokeAndFill = true; + break; + } + if (this.strokeAndFill) { + this.mode = GraphicMode.StrokeAndFill; + } else { + if (!this.propFillSet) { + if (this.propStroke) { + this.mode = GraphicMode.Stroke; + } else { + this.mode = GraphicMode.Fill; + } + } else { + if (this.propFill && this.propStroke) { + this.mode = GraphicMode.FillAndStroke; + } else if (this.propFill) { + this.mode = GraphicMode.Fill; + } else if (this.propStroke) { + this.mode = GraphicMode.Stroke; + } else { + this.mode = GraphicMode.Fill; + } + } + } + this.update(); + } + /** * 设置画布的渲染状态,在实际渲染前调用 * @param canvas 要设置的画布 @@ -144,7 +195,60 @@ export abstract class GraphicItemBase namespace?: ElementNamespace, parentComponent?: ComponentInternalInstance | null ): void { + if (isNil(prevValue) && isNil(nextValue)) return; switch (key) { + case 'fill': + if (!this.assertType(nextValue, 'number', key)) return; + this.checkMode(GraphicModeProp.Fill, nextValue); + break; + case 'stroke': + if (!this.assertType(nextValue, 'number', key)) return; + this.checkMode(GraphicModeProp.Stroke, nextValue); + break; + case 'strokeAndFill': + if (!this.assertType(nextValue, 'number', key)) return; + this.checkMode(GraphicModeProp.StrokeAndFill, nextValue); + break; + case 'fillRule': + if (!this.assertType(nextValue, 'string', key)) return; + this.setFillRule(nextValue); + break; + case 'fillStyle': + this.setFillStyle(nextValue); + break; + case 'strokeStyle': + this.setStrokeStyle(nextValue); + break; + case 'lineWidth': + if (!this.assertType(nextValue, 'number', key)) return; + this.lineWidth = nextValue; + this.update(); + break; + case 'lineDash': + if (!this.assertType(nextValue, Array, key)) return; + this.lineDash = nextValue; + this.update(); + break; + case 'lineDashOffset': + if (!this.assertType(nextValue, 'number', key)) return; + this.lineDashOffset = nextValue; + this.update(); + break; + case 'lineJoin': + if (!this.assertType(nextValue, 'string', key)) return; + this.lineJoin = nextValue; + this.update(); + break; + case 'lineCap': + if (!this.assertType(nextValue, 'string', key)) return; + this.lineCap = nextValue; + this.update(); + break; + case 'miterLimit': + if (!this.assertType(nextValue, 'number', key)) return; + this.miterLimit = nextValue; + this.update(); + break; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } From d61beada0b89132ff296b667fff07cc4f77c5833 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Tue, 24 Dec 2024 19:57:44 +0800 Subject: [PATCH 13/22] fix: strokeAndFill in checkMode --- src/core/render/preset/graphics.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index d75c4ef..6e1a048 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -143,7 +143,7 @@ export abstract class GraphicItemBase this.propStroke = value; break; case GraphicModeProp.StrokeAndFill: - this.strokeAndFill = true; + this.strokeAndFill = value; break; } if (this.strokeAndFill) { From dbe633290e6b6905e976c7702a51ccc4d264f299 Mon Sep 17 00:00:00 2001 From: strawberry42271 <2806566736@qq.com> Date: Wed, 25 Dec 2024 17:56:59 +0800 Subject: [PATCH 14/22] =?UTF-8?q?feat:=20Icon\winskin=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/preset/misc.ts | 231 +++++++++++++++++++++++++++++- src/core/render/renderer/props.ts | 12 +- 2 files changed, 234 insertions(+), 9 deletions(-) diff --git a/src/core/render/preset/misc.ts b/src/core/render/preset/misc.ts index 4310b14..7fa69fd 100644 --- a/src/core/render/preset/misc.ts +++ b/src/core/render/preset/misc.ts @@ -1,9 +1,18 @@ import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d'; import { Sprite } from '../sprite'; -import { ERenderItemEvent, RenderItem, RenderItemPosition } from '../item'; +import { + ERenderItemEvent, + IAnimateFrame, + renderEmits, + RenderItem, + RenderItemPosition +} from '../item'; import { Transform } from '../transform'; import { ElementNamespace, ComponentInternalInstance } from 'vue'; import { AutotileRenderable, RenderableData } from '../cache'; +import { texture } from '../cache'; +import { isNil } from 'lodash-es'; +import { logger } from '@/core/common/logger'; type CanvasStyle = string | CanvasGradient | CanvasPattern; @@ -207,7 +216,7 @@ export class Comment extends RenderItem { export interface EIconEvent extends ERenderItemEvent {} -export class Icon extends RenderItem { +export class Icon extends RenderItem implements IAnimateFrame { /** 图标id */ icon: AllNumbers = 0; /** 帧数 */ @@ -220,13 +229,69 @@ export class Icon extends RenderItem { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + const renderable = this.renderable; + if (!renderable) return; + const [x, y, w, h] = renderable.render[0]; + const cw = canvas.width; + const ch = canvas.height; + const frame = this.animate + ? RenderItem.animatedFrame % renderable.frame + : 0; + if (this.animate) { + if (renderable.autotile) { + ctx.drawImage(renderable.image[0], x, y, w, h, 0, 0, cw, ch); + } else { + ctx.drawImage(renderable.image, x, y, w, h, 0, 0, cw, ch); + } + } else { + const [x1, y1, w1, h1] = renderable.render[frame]; + if (renderable.autotile) { + ctx.drawImage( + renderable.image[0], + x1, + y1, + w1, + h1, + 0, + 0, + cw, + ch + ); + } else { + ctx.drawImage(renderable.image, x1, y1, w1, h1, 0, 0, cw, ch); + } + this.update(this), renderEmits.addFramer(this); + } + } /** * 设置图标 * @param id 图标id */ - setIcon(id: AllIds | AllNumbers) {} + setIcon(id: AllIds | AllNumbers) { + const num = typeof id === 'number' ? id : texture.idNumberMap[id]; + const renderable = texture.getRenderable(num); + + if (!renderable) { + //todo: logger.warn() + return; + } else { + this.icon = num; + renderable.animate = 0; + this.renderable = renderable; + this.frame = renderable.frame; + } + this.update(); + } + + /** + * 更新动画帧 + */ + updateFrameAnimate(): void { + this.update(this); + } patchProp( key: string, @@ -242,10 +307,12 @@ export class Icon extends RenderItem { case 'animate': if (!this.assertType(nextValue, 'boolean', key)) return; this.animate = nextValue; + this.update(); return; case 'frame': if (!this.assertType(nextValue, 'number', key)) return; this.frame = nextValue; + this.update(); return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); @@ -270,19 +337,162 @@ export class Winskin extends RenderItem { protected render( canvas: MotaOffscreenCanvas2D, transform: Transform - ): void {} + ): void { + const ctx = canvas.ctx; + const img = this.image; + const x = 0; + const y = 0; + const w = canvas.width; + const h = canvas.height; + const sz = this.borderSize / 32; + ctx.drawImage(img, 128, 0, 16, 16, x, y, 16 * sz, 16 * sz); + for (var dx = 0; dx < w - 64 * sz; dx += 32 * sz) { + ctx.drawImage( + img, + 144, + 0, + 32, + 16, + x + dx + 16, + y, + 32 * sz, + 16 * sz + ); + ctx.drawImage( + img, + 144, + 48, + 32, + 16, + x + dx + 16, + y + h - 16 * sz, + 32 * sz, + 16 * sz + ); + } + ctx.drawImage( + img, + 144, + 0, + w - dx - 32, + 16, + x + dx + 16 * sz, + y, + w - dx - 32 * sz, + 16 * sz + ); + ctx.drawImage( + img, + 144, + 48, + w - dx - 32, + 16, + x + dx + 16 * sz, + y + h - 16 * sz, + w - dx - 32 * sz, + 16 * sz + ); + ctx.drawImage( + img, + 176, + 0, + 16, + 16, + x + w - 16 * sz, + y, + 16 * sz, + 16 * sz + ); + // 左右 + for (var dy = 0; dy < h - 64 * sz; dy += 32 * sz) { + ctx.drawImage( + img, + 128, + 16, + 16, + 32, + x, + y + dy + 16 * sz, + 16 * sz, + 32 * sz + ); + ctx.drawImage( + img, + 176, + 16, + 16, + 32, + x + w - 16 * sz, + y + dy + 16 * sz, + 16 * sz, + 32 * sz + ); + } + ctx.drawImage( + img, + 128, + 16, + 16, + h - dy - 32, + x, + y + dy + 16 * sz, + 16 * sz, + h - dy - 32 * sz + ); + ctx.drawImage( + img, + 176, + 16, + 16, + h - dy - 32, + x + w - 16 * sz, + y + dy + 16 * sz, + 16 * sz, + h - dy - 32 * sz + ); + // 下方 + ctx.drawImage( + img, + 128, + 48, + 16, + 16, + x, + y + h - 16 * sz, + 16 * sz, + 16 * sz + ); + ctx.drawImage( + img, + 176, + 48, + 16, + 16, + x + w - 16 * sz, + y + h - 16 * sz, + 16 * sz, + 16 * sz + ); + this.update(); + } /** * 设置winskin图片 * @param image winskin图片 */ - setImage(image: SizedCanvasImageSource) {} + setImage(image: SizedCanvasImageSource) { + this.image = image; + this.update(); + } /** * 设置边框大小 * @param size 边框大小 */ - setBorderSize(size: number) {} + setBorderSize(size: number) { + this.borderSize = size; + this.update(); + } patchProp( key: string, @@ -292,6 +502,13 @@ export class Winskin extends RenderItem { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { + case 'image': + this.setImage(nextValue); + return; + case 'borderSize': + if (!this.assertType(nextValue, 'number', key)) return; + this.setBorderSize(nextValue); + return; } super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } diff --git a/src/core/render/renderer/props.ts b/src/core/render/renderer/props.ts index ddc9cfc..71a55dc 100644 --- a/src/core/render/renderer/props.ts +++ b/src/core/render/renderer/props.ts @@ -7,6 +7,7 @@ import { } from '../preset/layer'; import type { EnemyCollection } from '@/game/enemy/damage'; import { ILineProperty } from '../preset/graphics'; +import { SizedCanvasImageSource } from '../preset'; export interface CustomProps { _item: (props: BaseProps) => RenderItem; @@ -152,6 +153,13 @@ export interface PathProps extends GraphicPropsBase { path?: Path2D; } -export interface IconProps extends BaseProps {} +export interface IconProps extends BaseProps { + icon: AllNumbers; + frame: number; + animate: boolean; +} -export interface WinskinProps extends BaseProps {} +export interface WinskinProps extends BaseProps { + image: SizedCanvasImageSource; + borderSize: number; +} From 285dc2e48f1c0ab4e383839bedb6d63091a55d36 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Thu, 26 Dec 2024 18:16:59 +0800 Subject: [PATCH 15/22] =?UTF-8?q?feat:=20=E5=9C=86=E8=A7=92=E7=9F=A9?= =?UTF-8?q?=E5=BD=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/preset/graphics.ts | 102 +++++++++++++++++++++++++- src/core/render/renderer/elements.tsx | 2 + src/core/render/renderer/map.ts | 3 +- src/core/render/renderer/props.ts | 23 ++++++ 4 files changed, 128 insertions(+), 2 deletions(-) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 6e1a048..56dc874 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -1,5 +1,5 @@ import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d'; -import { ERenderItemEvent, RenderItem } from '../item'; +import { ERenderItemEvent, RenderItem, RenderItemPosition } from '../item'; import { Transform } from '../transform'; import { ElementNamespace, ComponentInternalInstance } from 'vue'; import { isNil } from 'lodash-es'; @@ -773,3 +773,103 @@ export class Path extends GraphicItemBase { super.patchProp(key, prevValue, nextValue, namespace, parentComponent); } } + +const enum RectRType { + /** 圆角为椭圆 */ + Ellipse, + /** 圆角为二次贝塞尔曲线 */ + Quad, + /** 圆角为三次贝塞尔曲线。该模式下,包含两个控制点,一个控制点位于上下矩形边延长线,另一个控制点位于左右矩形边延长线 */ + Cubic, + /** 圆角为直线连接 */ + Line +} + +export class RectR extends GraphicItemBase { + /** 矩形路径 */ + private path: Path2D; + + /** 圆角类型 */ + roundType: RectRType = RectRType.Ellipse; + /** 横向圆角半径 */ + radiusX: number = 0; + /** 纵向圆角半径 */ + radiusY: number = 0; + /** + * 二次贝塞尔曲线下,表示控制点的横向比例,控制点在上下矩形边与圆角的交界处为0,在左右矩形边与圆角的交界处延长线为1 + * 三次贝塞尔曲线下,表示在上下矩形边延长线上的控制点的比例 + */ + cpx: number = 0; + /** + * 二次贝塞尔曲线下,表示控制点的纵向比例,控制点在左右矩形边与圆角的交界处为0,在上下矩形边与圆角的交界处延长线为1 + * 三次贝塞尔曲线下,表示在左右矩形边延长线上的控制点的比例 + */ + cpy: number = 0; + + constructor( + type: RenderItemPosition, + cache: boolean = false, + fall: boolean = false + ) { + super(type, cache, fall); + + const path = new Path2D(); + path.rect(this.x, this.y, this.width, this.height); + this.path = path; + } + + /** + * 更新路径 + */ + private updatePath() {} + + /** + * 设置圆角半径 + * @param x 横向半径 + * @param y 纵向半径 + */ + setRadius(x: number, y: number) {} + + /** + * 设置贝塞尔曲线模式下的控制点 + * @param x cpx + * @param y cpy + */ + setControl(x: number, y: number) {} + + protected render( + canvas: MotaOffscreenCanvas2D, + transform: Transform + ): void { + const ctx = canvas.ctx; + this.setCanvasState(canvas); + switch (this.mode) { + case GraphicMode.Fill: + ctx.fill(this.path, this.fillRule); + break; + case GraphicMode.Stroke: + ctx.stroke(this.path); + break; + case GraphicMode.FillAndStroke: + ctx.fill(this.path, this.fillRule); + ctx.stroke(this.path); + break; + case GraphicMode.StrokeAndFill: + ctx.stroke(this.path); + ctx.fill(this.path, this.fillRule); + break; + } + } + + patchProp( + key: string, + prevValue: any, + nextValue: any, + namespace?: ElementNamespace, + parentComponent?: ComponentInternalInstance | null + ): void { + switch (key) { + } + super.patchProp(key, prevValue, nextValue, namespace, parentComponent); + } +} diff --git a/src/core/render/renderer/elements.tsx b/src/core/render/renderer/elements.tsx index 2d08c29..4b9e1cc 100644 --- a/src/core/render/renderer/elements.tsx +++ b/src/core/render/renderer/elements.tsx @@ -26,6 +26,7 @@ import { PathProps, QuadraticProps, RectProps, + RectRProps, ShaderProps, SpriteProps, TextProps, @@ -101,6 +102,7 @@ declare module 'vue/jsx-runtime' { 'g-bezier': TagDefine; 'g-quad': TagDefine; 'g-path': TagDefine; + 'g-rectr': TagDefine; icon: TagDefine; winskin: TagDefine; } diff --git a/src/core/render/renderer/map.ts b/src/core/render/renderer/map.ts index f85689f..01f5158 100644 --- a/src/core/render/renderer/map.ts +++ b/src/core/render/renderer/map.ts @@ -21,7 +21,8 @@ import { Line, Path, QuadraticCurve, - Rect + Rect, + RectR } from '../preset/graphics'; import { BaseProps } from './props'; diff --git a/src/core/render/renderer/props.ts b/src/core/render/renderer/props.ts index 71a55dc..10bf408 100644 --- a/src/core/render/renderer/props.ts +++ b/src/core/render/renderer/props.ts @@ -153,6 +153,29 @@ export interface PathProps extends GraphicPropsBase { path?: Path2D; } +export interface RectRProps extends GraphicPropsBase { + /** 圆角半径,此参数传入时,radiusX 和 radiusY 应保持一致 */ + radius: number; + /** 圆角横向半径 */ + radiusX?: number; + /** 圆角纵向半径 */ + radiusY?: number; + /** 圆角为线模式 */ + line?: boolean; + /** 圆角为椭圆模式,默认值 */ + ellipse?: boolean; + /** 圆角为二次贝塞尔曲线模式 */ + quad?: boolean; + /** 圆角为三次贝塞尔曲线模式 */ + cubic?: boolean; + /** 控制点,此参数传入时,cpx 和 cpy 应保持一致 */ + cp?: number; + /** 横向控制点 */ + cpx?: number; + /** 纵向控制点 */ + cpy?: number; +} + export interface IconProps extends BaseProps { icon: AllNumbers; frame: number; From 7ae1eb1e21d41baecdb73dd606399e9afc3a689d Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sat, 28 Dec 2024 16:46:22 +0800 Subject: [PATCH 16/22] =?UTF-8?q?fix:=20graphic=E5=85=83=E7=B4=A0=E9=94=99?= =?UTF-8?q?=E4=BD=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/renderer/map.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/render/renderer/map.ts b/src/core/render/renderer/map.ts index 01f5158..81ac6b2 100644 --- a/src/core/render/renderer/map.ts +++ b/src/core/render/renderer/map.ts @@ -21,8 +21,7 @@ import { Line, Path, QuadraticCurve, - Rect, - RectR + Rect } from '../preset/graphics'; import { BaseProps } from './props'; @@ -231,6 +230,7 @@ tagMap.register('g-line', se(Line, 'absolute', ElementState.None)); tagMap.register('g-bezier', se(BezierCurve, 'absolute', ElementState.None)); tagMap.register('g-quad', se(QuadraticCurve, 'absolute', ElementState.None)); tagMap.register('g-path', se(Path, 'absolute', ElementState.None)); +tagMap.register('g-rectr', se(Path, 'absolute', ElementState.None)); tagMap.register('icon', standardElementNoCache(Icon)); tagMap.register('winskin', (_0, _1, props) => { if (!props) return new Winskin(core.material.images.images['winskin.png']); From f29c76ffc9e4dc9b2a8aa6ca8a8d08bb126799b9 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Thu, 2 Jan 2025 13:52:43 +0800 Subject: [PATCH 17/22] =?UTF-8?q?fix:=20rectr=20=E6=A0=87=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/renderer/map.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/render/renderer/map.ts b/src/core/render/renderer/map.ts index 81ac6b2..f249d54 100644 --- a/src/core/render/renderer/map.ts +++ b/src/core/render/renderer/map.ts @@ -21,9 +21,9 @@ import { Line, Path, QuadraticCurve, - Rect + Rect, + RectR } from '../preset/graphics'; -import { BaseProps } from './props'; type OnItemCreate< E extends ERenderItemEvent = ERenderItemEvent, @@ -217,10 +217,10 @@ tagMap.register('layer-group', (_0, _1, props) => { return l; } }); -tagMap.register('damage', (_0, _1, props) => { +tagMap.register('damage', (_0, _1, _props) => { return new Damage(); }); -tagMap.register('animation', (_0, _1, props) => { +tagMap.register('animation', (_0, _1, _props) => { return new Animate(); }); tagMap.register('g-rect', se(Rect, 'absolute', ElementState.None)); @@ -230,7 +230,7 @@ tagMap.register('g-line', se(Line, 'absolute', ElementState.None)); tagMap.register('g-bezier', se(BezierCurve, 'absolute', ElementState.None)); tagMap.register('g-quad', se(QuadraticCurve, 'absolute', ElementState.None)); tagMap.register('g-path', se(Path, 'absolute', ElementState.None)); -tagMap.register('g-rectr', se(Path, 'absolute', ElementState.None)); +tagMap.register('g-rectr', se(RectR, 'absolute', ElementState.None)); tagMap.register('icon', standardElementNoCache(Icon)); tagMap.register('winskin', (_0, _1, props) => { if (!props) return new Winskin(core.material.images.images['winskin.png']); From 2a03d7c98d316cc10ddb321bc4815b945e6c46a6 Mon Sep 17 00:00:00 2001 From: strawberry42271 <2806566736@qq.com> Date: Sun, 5 Jan 2025 14:12:11 +0800 Subject: [PATCH 18/22] =?UTF-8?q?refactor:=20=E4=BA=8B=E4=BB=B6=E5=9D=97?= =?UTF-8?q?=E6=9B=B4=E6=94=B9=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/_server/MotaAction.g4 | 479 ++++--------------------- public/_server/MotaActionParser.js | 136 +------ public/_server/editor_blocklyconfig.js | 18 +- src/core/render/preset/graphics.ts | 18 +- src/core/render/preset/misc.ts | 23 +- 5 files changed, 107 insertions(+), 567 deletions(-) diff --git a/public/_server/MotaAction.g4 b/public/_server/MotaAction.g4 index 4b9753f..df19cf6 100644 --- a/public/_server/MotaAction.g4 +++ b/public/_server/MotaAction.g4 @@ -806,22 +806,13 @@ return code; //为了避免关键字冲突,全部加了_s //动作 action - : text_0_s - | text_1_s - | text_2_s - | moveTextBox_s - | clearTextBox_s + : text_s | comment_s | autoText_s | scrollText_s | setText_s | tip_s | setValue_s - | setEnemy_s - | setEnemyOnPoint_s - | resetEnemyOnPoint_s - | moveEnemyOnPoint_s - | moveEnemyOnPoint_1_s | setEquip_s | setFloor_s | setGlobalAttribute_s @@ -831,7 +822,6 @@ action | show_s | hide_s | setBlockOpacity_s - | setBlockFilter_s | trigger_s | insert_1_s | insert_2_s @@ -866,8 +856,6 @@ action | unloadEquip_s | openShop_s | disableShop_s - | follow_s - | unfollow_s | animate_s | animate_1_s | stopAnimate_s @@ -879,7 +867,6 @@ action | moveImage_s | rotateImage_s | scaleImage_s - | showGif_s | setCurtain_0_s | setCurtain_1_s | screenFlash_s @@ -950,188 +937,31 @@ action | pass_s ; -text_0_s - : '显示文章' ':' EvalString_Multi Newline + + +text_s + : '标题' EvalString? '图标' EvalString? '像素坐标 x' IntString? 'y' IntString? '宽' IntString? '高' IntString? '维持文本' Bool '打字间隔' IntString? '行高' IntString? BGNL? Newline + EvalString_Multi Newline -/* text_0_s -tooltip : text:显示一段文字(剧情) -helpUrl : /_docs/#/instruction -previewBlock : true -default : ["欢迎使用事件编辑器(双击方块可直接预览)"] -var code = '"'+EvalString_Multi_0+'"'; -if (block.isCollapsed() || !block.isEnabled()) { - code = '{"type": "text", "text": '+code; - if (block.isCollapsed()) code += ', "_collapsed": true'; - if (!block.isEnabled()) code += ', "_disabled": true'; - code += '}'; -} -return code+',\n'; -*/; - -text_1_s - : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点 px' PosString? 'py' PosString? '宽' PosString? '编号' Int '不等待操作' Bool BGNL? Newline EvalString_Multi Newline - - -/* text_1_s +/* text_s tooltip : text:显示一段文字(剧情),选项较多请右键点击帮助 helpUrl : /_docs/#/instruction previewBlock : true allIds : ['EvalString_1'] -default : ["小妖精","fairy","","","","",0,false,"欢迎使用事件编辑器(双击方块可直接预览)"] -var title=''; -if (EvalString_0==''){ - if (EvalString_1=='' )title=''; - else title='\\t['+EvalString_1+']'; -} else { - if (EvalString_1=='')title='\\t['+EvalString_0+']'; - else title='\\t['+EvalString_0+','+EvalString_1+']'; -} -var pos = ''; -if (PosString_0 || PosString_1) { - if (EvalString_2) throw new Error('对话框效果和起点像素位置只能设置一项!'); - pos = '[' + (PosString_0||0) + ',' + (PosString_1||0); - if (PosString_2) pos += ',' + PosString_2; - pos += ']'; -} -if(EvalString_2 && !(/^(up|center|down|hero|this)(,(hero|null|\d+,\d+|\d+))?$/.test(EvalString_2))) { - throw new Error('对话框效果的用法请右键点击帮助'); -} -EvalString_2 = EvalString_2 && ('\\b['+EvalString_2+']'); -var code = '"'+title+EvalString_2+EvalString_Multi_0+'"'; -if (block.isCollapsed() || !block.isEnabled() || pos || Int_0 || Bool_0) { - code = '{"type": "text", "text": '+code; - if (pos) code += ', "pos": ' + pos; - if (Int_0) code += ', "code": ' + Int_0; - if (Bool_0) code += ', "async": true'; - if (block.isCollapsed()) code += ', "_collapsed": true'; - if (!block.isEnabled()) code += ', "_disabled": true'; - code += '}'; -} -return code+',\n'; +default : ["小妖精","fairy","","","","",false,"","","欢迎使用事件编辑器"] +EvalString_0= EvalString_0 ? (', "title": "'+EvalString_0+'"') : ''; +EvalString_1= EvalString_1 ? (', "icon": "'+EvalString_1+'"') : ''; +IntString_0= IntString_0 ? (', "x": '+IntString_0) : ''; +IntString_1= IntString_1 ? (', "y": '+IntString_1) : ''; +IntString_2= IntString_2 ? (', "width": '+IntString_2) : ''; +IntString_3= IntString_3 ? (', "height": '+IntString_3) : ''; +IntString_4= IntString_4 ? (', "interval": '+IntString_4) : ''; +IntString_5= IntString_5 ? (', "lineHeight": '+IntString_5) : ''; +var code = '{"type": "text"'+EvalString_0+EvalString_1+IntString_0+IntString_1+IntString_2+IntString_3+',"keepLast":'+Bool_0+IntString_4+IntString_5+'"text":"'+EvalString_Multi_0+'"},\n'; +return code */; -text_2_s - : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点 px' PosString? 'py' PosString? '宽' PosString? '编号' Int '不等待操作' Bool BGNL? Newline EvalString_Multi BGNL? Newline textDrawingList* Newline - - -/* text_2_s -tooltip : text:显示一段文字(剧情),选项较多请右键点击帮助 -helpUrl : /_docs/#/instruction -previewBlock : true -allIds : ['EvalString_1'] -default : ["小妖精","fairy","","","","",0,"欢迎使用事件编辑器(双击方块可直接预览)",null] -var title=''; -if (EvalString_0==''){ - if (EvalString_1=='' )title=''; - else title='\\t['+EvalString_1+']'; -} else { - if (EvalString_1=='')title='\\t['+EvalString_0+']'; - else title='\\t['+EvalString_0+','+EvalString_1+']'; -} -var pos = ''; -if (PosString_0 || PosString_1) { - if (EvalString_2) throw new Error('对话框效果和起点像素位置只能设置一项!'); - pos = '[' + (PosString_0||0) + ',' + (PosString_1||0); - if (PosString_2) pos += ',' + PosString_2; - pos += ']'; -} -if(EvalString_2 && !(/^(up|center|down|hero|this)(,(hero|null|\d+,\d+|\d+))?$/.test(EvalString_2))) { - throw new Error('对话框效果的用法请右键点击帮助'); -} -EvalString_2 = EvalString_2 && ('\\b['+EvalString_2+']'); -var code = '"'+title+EvalString_2+textDrawingList_0.replace(/\s/g, '')+EvalString_Multi_0+'"'; -if (block.isCollapsed() || !block.isEnabled() || pos || Int_0 || Bool_0) { - code = '{"type": "text", "text": '+code; - if (pos) code += ', "pos": ' + pos; - if (Int_0) code += ', "code": ' + Int_0; - if (Bool_0) code += ', "async": true'; - if (block.isCollapsed()) code += ', "_collapsed": true'; - if (!block.isEnabled()) code += ', "_disabled": true'; - code += '}'; -} -return code+',\n'; -*/; - -textDrawingList - : textDrawing - | textDrawingEmpty; - - -textDrawing - : '立绘' EvalString '翻转' Reverse_List '绘制坐标' 'x' IntString 'y' IntString '宽' IntString? '高' IntString? BGNL? Newline - '裁剪坐标' 'x' IntString? 'y' IntString? '宽' IntString? '高' IntString? '不透明度' EvalString? '旋转角度' IntString? - -/* textDrawing -tooltip : 立绘 -helpUrl : /_docs/#/instruction -default : ["fairy.png","null","0","0","","","","","","","",""] -colour : this.subColor -previewBlock : true -allImages : ['EvalString_0'] -if (Reverse_List_0 && Reverse_List_0 != 'null') EvalString_0 += Reverse_List_0; -var list = [EvalString_0, IntString_0, IntString_1]; -if (IntString_2 || IntString_3) { - if (list.length != 3 || !IntString_2 || !IntString_3) { - throw "绘制的宽和高需同时设置"; - } - list.push(IntString_2); - list.push(IntString_3); -} -if (IntString_4 || IntString_5 || IntString_6 || IntString_7) { - if (list.length != 5) throw "如设置裁剪区域,请先设置绘制区域的宽高"; - if (!IntString_4 || !IntString_5 || !IntString_6 || !IntString_7) { - throw "如设置裁剪区域,请同时设置全部的裁剪坐标和宽高"; - } - list.splice(1, 0, IntString_4, IntString_5, IntString_6, IntString_7); -} -if (EvalString_1) { - if (list.length != 9) throw "如设置不透明度,需填满所有坐标和宽高"; - var opacity = parseFloat(EvalString_1); - if (isNaN(opacity) || opacity < 0 || opacity > 1) throw "不合法的不透明度,必须是0到1之间" - list.push(opacity); -} -if (IntString_8) { - if (list.length != 10) throw "如设置旋转角度,需填满所有坐标和宽高,以及不透明度"; - list.push(IntString_8); -} -return "\\f[" + list.join(",")+"]"; -*/; - -textDrawingEmpty - : Newline - -/* textDrawingEmpty -var code = ''; -return code; -*/; - -moveTextBox_s - : '移动对话框' ':' Int 'px' PosString 'py' PosString '使用增量' Bool '移动方式' MoveMode_List '动画时间' Int '不等待执行完毕' Bool Newline - -/* moveTextBox_s -tooltip : 移动对话框 -helpUrl : /_docs/#/instruction -default : [1,"0","0",false,'',500,false] -MoveMode_List_0 = (MoveMode_List_0!=='') ? (', "moveMode": "'+MoveMode_List_0+'"'):''; -Bool_0 = Bool_0 ?', "relative": true':''; -Bool_1 = Bool_1 ?', "async": true':''; -var code = '{"type": "moveTextBox", "code": '+Int_0+', "loc": ['+PosString_0+','+PosString_1+']'+Bool_0+MoveMode_List_0+', "time": '+Int_1+Bool_1+'},\n'; -return code; -*/; - -clearTextBox_s - : '清除对话框' ':' EvalString? Newline - -/* clearTextBox_s -tooltip : 清除对话框 -helpUrl : /_docs/#/instruction -default : ["1"] -if (EvalString_0 && !/^\d+(,\d+)*$/.test(EvalString_0)) throw new Error('对话框编号需要以逗号分隔'); -EvalString_0 = EvalString_0 ? (', "code": ['+EvalString_0+']') : ''; -var code = '{"type": "clearTextBox"'+EvalString_0+'},\n'; -return code; -*/; comment_s @@ -1189,39 +1019,38 @@ return code; */; setText_s - : '设置剧情文本的属性' '位置' SetTextPosition_List '偏移像素' IntString? '对齐' TextAlign_List? '粗体' B_1_List? BGNL? '标题颜色' ColorString? Colour '正文颜色' ColorString? Colour '背景色' EvalString? Colour BGNL? '标题大小' IntString? '正文大小' IntString? '行距' IntString? '打字间隔' IntString? '字符间距' IntString? '淡入淡出时间' IntString? Newline + : '设置剧情文本的属性' '位置像素x' IntString? 'y' IntString? '宽' IntString? '高' IntString? '字体类型' EvalString? '字体大小' IntString? '字体线宽' IntString? BGNL? + '是否斜体' Bool? '维持文本' Bool? '打字间隔' IntString? '行高' IntString? '文字颜色' ColorString? Colour '文字描边颜色' ColorString? Colour '描边线宽' IntString? '是否填充' Bool '是否描边' Bool BGNL? + '背景色' ColorString? Colour '背景winskin' EvalString? '文字与边框距离' IntString? '标题是否填充' Bool '标题是否描边' Bool'标题与边框的距离' IntString? BGNL? + '对齐方式' TextAlign_List '分词原则' WordBreak_List '行首禁则' EvalString? '行尾禁则' EvalString? '分词规则识别字符' EvalString? Newline /* setText_s -tooltip : setText:设置剧情文本的属性,颜色为RGB三元组或RGBA四元组,打字间隔为剧情文字添加的时间间隔,为整数或不填,字符间距为字符之间的距离,为整数或不填。 +tooltip : setText:设置文本的属性,颜色为RGB三元组或RGBA四元组,打字间隔为剧情文字添加的时间间隔,为整数或不填,字符间距为字符之间的距离,为整数或不填。 helpUrl : /_docs/#/instruction previewBlock : true -default : [null,"",null,null,"",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',"","","","","",""] -SetTextPosition_List_0 =SetTextPosition_List_0==='null'?'': ', "position": "'+SetTextPosition_List_0+'"'; -TextAlign_List_0 = TextAlign_List_0==='null'?'': ', "align": "'+TextAlign_List_0+'"'; -var colorRe = MotaActionFunctions.pattern.colorRe; -IntString_0 = IntString_0 ? (', "offset": '+IntString_0) : ''; -ColorString_0 = ColorString_0 ? (', "title": ['+ColorString_0+']') : ''; -ColorString_1 = ColorString_1 ? (', "text": ['+ColorString_1+']') : ''; -if (EvalString_0) { - if (colorRe.test(EvalString_0)) { - EvalString_0 = ', "background": ['+EvalString_0+']'; - } - else if (/^\w+\.png$/.test(EvalString_0)) { - EvalString_0 = ', "background": "'+EvalString_0+'"'; - } - else { - throw new Error('背景格式错误,必须是形如0~255,0~255,0~255,0~1的颜色,或一个WindowSkin的png图片名称'); - } -} -IntString_1 = IntString_1 ? (', "titlefont": '+IntString_1) : ''; -IntString_2 = IntString_2 ? (', "textfont": '+IntString_2) : ''; -IntString_3 = IntString_3 ? (', "lineHeight": '+IntString_3) : ''; -IntString_4 = IntString_4 ? (', "time": '+IntString_4) : ''; -IntString_5 = IntString_5 ? (', "letterSpacing": '+IntString_5) : ''; -IntString_6 = IntString_6 ? (', "animateTime": ' + IntString_6) : ''; -B_1_List_0 = B_1_List_0==='null'?'':', "bold": '+B_1_List_0; -var code = '{"type": "setText"'+SetTextPosition_List_0+IntString_0+TextAlign_List_0+B_1_List_0+ColorString_0+ColorString_1+EvalString_0+IntString_1+IntString_2+IntString_3+IntString_4+IntString_5+IntString_6+'},\n'; +default : ["","","","","","","",false,false,"","","",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',"",true,false,"",'rgba(255,255,255,1)',"","",true,false,"",'null','space',"","",""] +IntString_0= IntString_0 ? (', "x": '+IntString_0) : ''; +IntString_1 = IntString_1 ? (', "y": '+IntString_1) : ''; +IntString_2 = IntString_2 ? (', "width": '+IntString_2) : ''; +IntString_3 = IntString_3 ? (', "height": '+IntString_3) : ''; +EvalString_0 = EvalString_0 ? (', "fontFamily": '+EvalString_0) : ''; +IntString_4 = IntString_4 ? (', "fontSize": '+IntString_4) : ''; +IntString_5 = IntString_5 ? (', " interval": '+IntString_5) : ''; +IntString_6 = IntString_6 ? (', "lineHeight": ' + IntString_6) : ''; +IntString_7 = IntString_7? (', "strokeWidth": ' + IntString_7) : ''; +EvalString_1 = EvalString_1 ? (', "winskin": '+EvalString_1) : ''; +IntString_8 = IntString_8? (', "padding": ' + IntString_8) : ''; +IntString_9 = IntString_9? (', "titlePadding": ' + IntString_9) : ''; +TextAlign_List_0 = TextAlign_List_0==='null'?'':', "textAlign": "'+TextAlign_List_0+'"'; +WordBreak_List_0 = WordBreak_List_0==='null'?'':', "wordBreak": "'+WordBreak_List_0+'"'; +EvalString_2 = EvalString_2? (', "ignoreLineStart": '+EvalString_2) : ''; +EvalString_3 = EvalString_3 ? (', "ignoreLineEnd": '+EvalString_3) : ''; +EvalString_4 = EvalString_4 ? (', "breakChars": '+EvalString_4) : ''; +ColorString_0=ColorString_0?(', "fillStyle": ['+ColorString_0+']'):''; +ColorString_1=ColorString_1?(', "strokeStyle": ['+ColorString_1+']'):''; +ColorString_2=ColorString_2?(', "backColor": ['+ColorString_2+']'):''; +var code = '{"type": "setText"'+IntString_0+IntString_1+IntString_2+IntString_3+EvalString_0+IntString_4+', " fontItalic": '+Bool_0+', " keepLast": '+Bool_1+IntString_5+IntString_6+ColorString_0+ColorString_1+IntString_7 +',"fill":'+Bool_2+',"stroke":'+Bool_3+ColorString_2+EvalString_1+IntString_8+',"titleFill":'+Bool_4+',"titleStroke":'+Bool_5+IntString_9 +TextAlign_List_0+WordBreak_List_0+EvalString_2+EvalString_3+EvalString_4+'},\n'; return code; */; @@ -1257,23 +1086,6 @@ return code; */; -setEnemy_s - : '设置怪物属性' ':' '怪物ID' IdString '的' EnemyId_List AssignOperator_List expression '不刷新显伤' Bool Newline - - -/* setEnemy_s -tooltip : setEnemy:设置某个怪物的属性 -helpUrl : /_docs/#/instruction -default : ["greenSlime", "atk", "=", "", false] -allEnemys : ['IdString_0'] -colour : this.dataColor -if (AssignOperator_List_0 && AssignOperator_List_0 != '=') { - AssignOperator_List_0 = ', "operator": "' + AssignOperator_List_0 + '"'; -} else AssignOperator_List_0 = ''; -Bool_0 = Bool_0 ? ', "norefresh": true' : ''; -var code = '{"type": "setEnemy", "id": "'+IdString_0+'", "name": "'+EnemyId_List_0+'"'+AssignOperator_List_0+', "value": "'+expression_0+'"'+Bool_0+'},\n'; -return code; -*/; setEquip_s @@ -1295,84 +1107,6 @@ return code; */; -setEnemyOnPoint_s - : '设置某点怪物属性' ':' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? '的' EnemyPoint_List AssignOperator_List expression '不刷新显伤' Bool Newline - - -/* setEnemyOnPoint_s -tooltip : setEnemyOnPoint:设置某个点上怪物的属性 -helpUrl : /_docs/#/instruction -default : ["", "", "", "atk", "=", "", false] -selectPoint : ["EvalString_0", "EvalString_1", "IdString_0"] -allFloorIds : ['IdString_0'] -colour : this.dataColor -var floorstr = MotaActionFunctions.processMultiLoc(EvalString_0, EvalString_1); -if (AssignOperator_List_0 && AssignOperator_List_0 != '=') { - AssignOperator_List_0 = ', "operator": "' + AssignOperator_List_0 + '"'; -} else AssignOperator_List_0 = ''; -IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); -Bool_0 = Bool_0 ? ', "norefresh": true' : ''; -var code = '{"type": "setEnemyOnPoint"'+floorstr+IdString_0+', "name": "'+EnemyPoint_List_0+'"'+AssignOperator_List_0+', "value": "'+expression_0+'"'+Bool_0+'},\n'; -return code; -*/; - -resetEnemyOnPoint_s - : '重置某点怪物属性' ':' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? '不刷新显伤' Bool Newline - - -/* resetEnemyOnPoint_s -tooltip : resetEnemyOnPoint:重置某个点上怪物的属性 -helpUrl : /_docs/#/instruction -default : ["", "", "", false] -selectPoint : ["EvalString_0", "EvalString_1", "IdString_0"] -allFloorIds : ['IdString_0'] -colour : this.dataColor -var floorstr = MotaActionFunctions.processMultiLoc(EvalString_0, EvalString_1); -IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); -Bool_0 = Bool_0 ? ', "norefresh": true' : ''; -var code = '{"type": "resetEnemyOnPoint"'+floorstr+IdString_0+Bool_0+'},\n'; -return code; -*/; - -moveEnemyOnPoint_s - : '移动某点怪物属性' ':' '起点' 'x' PosString? ',' 'y' PosString? '终点' 'x' PosString? 'y' PosString? '楼层' IdString? '不刷新显伤' Bool Newline - - -/* moveEnemyOnPoint_s -tooltip : moveEnemyOnPoint:移动某个点上怪物的属性到其他点 -helpUrl : /_docs/#/instruction -default : ["", "", "", "", "", false] -allFloorIds : ['IdString_0'] -selectPoint : ["PosString_2", "PosString_3"] -menu : [['选择起点位置','editor_blockly.selectPoint(block,["PosString_0", "PosString_1"])']] -colour : this.dataColor -IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); -var floorstr = PosString_0 && PosString_1 ? ', "from": ['+PosString_0+','+PosString_1+']' : ''; -if (PosString_2 && PosString_3) floorstr += ', "to": ['+PosString_2+','+PosString_3+']' -Bool_0 = Bool_0 ? ', "norefresh": true' : ''; -var code = '{"type": "moveEnemyOnPoint"'+floorstr+IdString_0+Bool_0+'},\n'; -return code; -*/; - -moveEnemyOnPoint_1_s - : '移动某点怪物属性' ':' '起点' 'x' PosString? ',' 'y' PosString? '增量' 'dx' PosString? 'dy' PosString? '楼层' IdString? '不刷新显伤' Bool Newline - - -/* moveEnemyOnPoint_1_s -tooltip : moveEnemyOnPoint:移动某个点上怪物的属性到其他点 -helpUrl : /_docs/#/instruction -default : ["", "", "", "", "", false] -allFloorIds : ['IdString_0'] -selectPoint : ["PosString_0", "PosString_1"] -colour : this.dataColor -IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); -var floorstr = PosString_0 && PosString_1 ? ', "from": ['+PosString_0+','+PosString_1+']' : ''; -if (PosString_2 && PosString_3) floorstr += ', "dxy": ['+PosString_2+','+PosString_3+']' -Bool_0 = Bool_0 ? ', "norefresh": true' : ''; -var code = '{"type": "moveEnemyOnPoint"'+floorstr+IdString_0+Bool_0+'},\n'; -return code; -*/; - setFloor_s : '设置楼层属性' ':' Floor_Meta_List '楼层名' IdString? '为' JsonEvalString Newline @@ -1432,7 +1166,7 @@ return code; setNameMap_s - : '设置文件别名' ':' EvalString '为' EvalString? Newline + : '(已弃用)设置文件别名' ':' EvalString '为' EvalString? Newline /* setNameMap_s @@ -1504,27 +1238,6 @@ var code = '{"type": "setBlockOpacity"'+floorstr+IdString_0+', "opacity": '+Numb return code; */; -setBlockFilter_s - : '设置图块特效' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? '虚化' Number '色相' Int '灰度' Number '反色' Bool '阴影' Number Newline - - -/* setBlockFilter_s -tooltip : setBlockFilter: 设置图块特效 -helpUrl : /_docs/#/instruction -default : ["","","",0,0,0,false,0] -selectPoint : ["EvalString_0", "EvalString_1", "IdString_0"] -allFloorIds : ['IdString_0'] -colour : this.mapColor -var floorstr = MotaActionFunctions.processMultiLoc(EvalString_0, EvalString_1); -if (Number_0 < 0) throw '虚化不得小于0;0为完全没有虚化'; -if (Int_0 < 0 || Int_0 >= 360) throw '色相需要在0~359之间'; -if (Number_1 < 0 || Number_1 > 1) throw '灰度需要在0~1之间'; -if (Number_2 < 0) throw '阴影不得小于0;0为完全没有阴影'; - -var code = '{"type": "setBlockFilter"'+floorstr+IdString_0+', "blur": '+Number_0+', "hue": '+Int_0+', "grayscale": '+Number_1+', "invert": '+Bool_0+', "shadow": '+Number_2+'},\n'; -return code; -*/; - trigger_s : '触发系统事件' 'x' PosString? ',' 'y' PosString? Newline @@ -2003,36 +1716,6 @@ var code = '{"type": "disableShop", "id": "'+IdString_0+'"},\n'; return code; */; -follow_s - : '跟随勇士' '行走图' EvalString Newline - - -/* follow_s -tooltip : follow: 跟随勇士 -helpUrl : /_docs/#/instruction -default : ["npc.png"] -allImages : ['EvalString_0'] -material : ["./project/images/:images", "EvalString_0"] -colour : this.dataColor -var code = '{"type": "follow", "name": "'+EvalString_0+'"},\n'; -return code; -*/; - -unfollow_s - : '取消跟随' '行走图' EvalString? Newline - - -/* unfollow_s -tooltip : unfollow: 取消跟随 -helpUrl : /_docs/#/instruction -default : [""] -allImages : ['EvalString_0'] -material : ["./project/images/:images", "EvalString_0"] -colour : this.dataColor -EvalString_0 = EvalString_0 ? (', "name": "' + EvalString_0 + '"') : ""; -var code = '{"type": "unfollow"' + EvalString_0 + '},\n'; -return code; -*/; vibrate_s : '画面震动' '方向' Vibrate_List '时间' Int '速度' Int '振幅' Int '不等待执行完毕' Bool Newline @@ -2229,22 +1912,6 @@ var code = '{"type": "hideImage", "code": '+NInt_0+', "time": '+Int_0+async+'},\ return code; */; -showGif_s - : '显示或清除动图' EvalString? '起点像素位置' 'x' PosString? 'y' PosString? Newline - - -/* showGif_s -tooltip : showGif:显示动图 -helpUrl : /_docs/#/instruction -default : ["","",""] -allImages : ['EvalString_0'] -previewBlock : true -colour : this.imageColor -EvalString_0 = EvalString_0 ? (', "name": "'+EvalString_0+'"') : ''; -var loc = (PosString_0 && PosString_1) ? (', "loc": ['+PosString_0+','+PosString_1+']') : ''; -var code = '{"type": "showGif"'+EvalString_0+loc+'},\n'; -return code; -*/; moveImage_s : '图片移动' '图片编号' NInt '终点像素位置' 'x' PosString? 'y' PosString? BGNL? @@ -2354,7 +2021,7 @@ return code; */; setWeather_s - : '更改天气' Weather_List '强度' Int '持续到下个本事件' Bool Newline + : '(已弃用)更改天气' Weather_List '强度' Int '持续到下个本事件' Bool Newline /* setWeather_s @@ -2964,7 +2631,7 @@ return code; wait_s - : '等待用户操作并获得按键或点击信息' '仅检测子块' Bool '超时毫秒数' Int BGNL? Newline waitContext* BEND Newline + : '(已弃用)等待用户操作并获得按键或点击信息' '仅检测子块' Bool '超时毫秒数' Int BGNL? Newline waitContext* BEND Newline /* wait_s @@ -3162,7 +2829,7 @@ return code; previewUI_s - : 'ui绘制并预览' '(双击此项可进行预览)' BGNL? Newline action+ BEND Newline + : '(已弃用)ui绘制并预览' '(双击此项可进行预览)' BGNL? Newline action+ BEND Newline /* previewUI_s @@ -3177,7 +2844,7 @@ return code; clearMap_s - : '清除画布' '起点像素' 'x' PosString? 'y' PosString? '宽' PosString? '高' PosString? Newline + : '(已弃用)清除画布' '起点像素' 'x' PosString? 'y' PosString? '宽' PosString? '高' PosString? Newline /* clearMap_s tooltip : clearMap: 清除画布 @@ -3195,7 +2862,7 @@ return code; setAttribute_s - : '设置画布属性' '字体' FontString? '填充样式' ColorString? Colour '边框样式' ColorString? Colour BGNL? '线宽度' IntString? '不透明度' EvalString? '对齐' TextAlign_List '基准线' TextBaseline_List 'z值' IntString? Newline + : '(已弃用)设置画布属性' '字体' FontString? '填充样式' ColorString? Colour '边框样式' ColorString? Colour BGNL? '线宽度' IntString? '不透明度' EvalString? '对齐' TextAlign_List '基准线' TextBaseline_List 'z值' IntString? Newline /* setAttribute_s tooltip : setAttribute:设置画布属性 @@ -3222,7 +2889,7 @@ return code; setFilter_s - : '设置画布特效' '虚化' Number '色相' Int '灰度' Number '反色' Bool '阴影' Number Newline + : '(已弃用)设置画布特效' '虚化' Number '色相' Int '灰度' Number '反色' Bool '阴影' Number Newline /* setFilter_s @@ -3241,7 +2908,7 @@ return code; fillText_s - : '绘制文本' 'x' PosString 'y' PosString '样式' ColorString? Colour '字体' FontString? '最大宽度' IntString? BGNL? EvalString Newline + : '(已弃用)绘制文本' 'x' PosString 'y' PosString '样式' ColorString? Colour '字体' FontString? '最大宽度' IntString? BGNL? EvalString Newline /* fillText_s tooltip : fillText:绘制一行文本;可以设置最大宽度进行放缩 @@ -3257,7 +2924,7 @@ return code; */; fillBoldText_s - : '绘制描边文本' 'x' PosString 'y' PosString '样式' ColorString? Colour '描边颜色' ColorString? Colour '字体' FontString? BGNL? EvalString Newline + : '(已弃用)绘制描边文本' 'x' PosString 'y' PosString '样式' ColorString? Colour '描边颜色' ColorString? Colour '字体' FontString? BGNL? EvalString Newline /* fillBoldText_s tooltip : fillBoldText:绘制一行描边文本 @@ -3273,7 +2940,7 @@ return code; */; drawTextContent_s - : '绘制多行文本' EvalString_Multi BGNL? '起点像素' 'x' PosString 'y' PosString '最大宽度' IntString? '颜色' ColorString? Colour BGNL? '对齐' TextAlign_List '字体大小' IntString? '行距' IntString? '粗体' Bool Newline + : '(已弃用)绘制多行文本' EvalString_Multi BGNL? '起点像素' 'x' PosString 'y' PosString '最大宽度' IntString? '颜色' ColorString? Colour BGNL? '对齐' TextAlign_List '字体大小' IntString? '行距' IntString? '粗体' Bool Newline /* drawTextContent_s tooltip : drawTextContent:绘制多行文本 @@ -3293,7 +2960,7 @@ return code; */; fillRect_s - : '绘制矩形' '起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString '圆角半径' PosString? '旋转度数' PosString? '颜色' ColorString? Colour Newline + : '(已弃用)绘制矩形' '起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString '圆角半径' PosString? '旋转度数' PosString? '颜色' ColorString? Colour Newline /* fillRect_s tooltip : fillRect:绘制矩形 @@ -3309,7 +2976,7 @@ return code; */; strokeRect_s - : '绘制矩形边框' '起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString '圆角半径' PosString? '旋转度数' PosString? '颜色' ColorString? Colour '线宽' IntString? Newline + : '(已弃用)绘制矩形边框' '起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString '圆角半径' PosString? '旋转度数' PosString? '颜色' ColorString? Colour '线宽' IntString? Newline /* strokeRect_s tooltip : strokeRect:绘制矩形边框 @@ -3326,7 +2993,7 @@ return code; */; drawLine_s - : '绘制线段' '起点像素' 'x' PosString 'y' PosString '终点像素' 'x' PosString 'y' PosString '颜色' ColorString? Colour '线宽' IntString? Newline + : '(已弃用)绘制线段' '起点像素' 'x' PosString 'y' PosString '终点像素' 'x' PosString 'y' PosString '颜色' ColorString? Colour '线宽' IntString? Newline /* drawLine_s tooltip : drawLine:绘制线段 @@ -3341,7 +3008,7 @@ return code; */; drawArrow_s - : '绘制箭头' '起点像素' 'x' PosString 'y' PosString '终点像素' 'x' PosString 'y' PosString '颜色' ColorString? Colour '线宽' IntString? Newline + : '(已弃用)绘制箭头' '起点像素' 'x' PosString 'y' PosString '终点像素' 'x' PosString 'y' PosString '颜色' ColorString? Colour '线宽' IntString? Newline /* drawArrow_s tooltip : drawArrow:绘制箭头 @@ -3357,7 +3024,7 @@ return code; fillPolygon_s - : '绘制多边形' '顶点像素列表' 'x' EvalString 'y' EvalString '颜色' ColorString? Colour Newline + : '(已弃用)绘制多边形' '顶点像素列表' 'x' EvalString 'y' EvalString '颜色' ColorString? Colour Newline /* fillPolygon_s tooltip : fillPolygon:绘制多边形 @@ -3378,7 +3045,7 @@ return code; strokePolygon_s - : '绘制多边形边框' '顶点像素列表' 'x' EvalString 'y' EvalString '颜色' ColorString? Colour '线宽' IntString? Newline + : '(已弃用)绘制多边形边框' '顶点像素列表' 'x' EvalString 'y' EvalString '颜色' ColorString? Colour '线宽' IntString? Newline /* strokePolygon_s tooltip : strokePolygon:绘制多边形边框 @@ -3399,7 +3066,7 @@ return code; */; fillEllipse_s - : '绘制椭圆' '中心' 'x' PosString 'y' PosString '长半径' PosString '短半径' PosString '旋转度数' PosString? '颜色' ColorString? Colour Newline + : '(已弃用)绘制椭圆' '中心' 'x' PosString 'y' PosString '长半径' PosString '短半径' PosString '旋转度数' PosString? '颜色' ColorString? Colour Newline /* fillEllipse_s tooltip : fillEllipse:绘制椭圆 @@ -3414,7 +3081,7 @@ return code; */; strokeEllipse_s - : '绘制椭圆边框' '中心' 'x' PosString 'y' PosString '长半径' PosString '短半径' PosString '旋转度数' PosString? '颜色' ColorString? Colour '线宽' IntString? Newline + : '(已弃用)绘制椭圆边框' '中心' 'x' PosString 'y' PosString '长半径' PosString '短半径' PosString '旋转度数' PosString? '颜色' ColorString? Colour '线宽' IntString? Newline /* strokeEllipse_s tooltip : strokeEllipse:绘制椭圆边框 @@ -3430,7 +3097,7 @@ return code; */; fillArc_s - : '绘制扇形' '中心' 'x' PosString 'y' PosString '半径' PosString '起点角度' PosString '终点角度' PosString '颜色' ColorString? Colour Newline + : '(已弃用)绘制扇形' '中心' 'x' PosString 'y' PosString '半径' PosString '起点角度' PosString '终点角度' PosString '颜色' ColorString? Colour Newline /* fillArc_s tooltip : fillArc:绘制扇形 @@ -3444,7 +3111,7 @@ return code; strokeArc_s - : '绘制弧' '中心' 'x' PosString 'y' PosString '半径' PosString '起点角度' PosString '终点角度' PosString '颜色' ColorString? Colour '线宽' IntString? Newline + : '(已弃用)绘制弧' '中心' 'x' PosString 'y' PosString '半径' PosString '起点角度' PosString '终点角度' PosString '颜色' ColorString? Colour '线宽' IntString? Newline /* strokeArc_s tooltip : strokeArc:绘制弧 @@ -3460,7 +3127,7 @@ return code; drawImage_s - : '绘制图片' EvalString '翻转' Reverse_List '起点像素' 'x' PosString 'y' PosString '宽' PosString? '高' PosString? '旋转度数' PosString? Newline + : '(已弃用)绘制图片' EvalString '翻转' Reverse_List '起点像素' 'x' PosString 'y' PosString '宽' PosString? '高' PosString? '旋转度数' PosString? Newline /* drawImage_s @@ -3481,7 +3148,7 @@ return code; */; drawImage_1_s - : '绘制图片' EvalString '翻转' Reverse_List '裁剪的起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString BGNL? + : '(已弃用)绘制图片' EvalString '翻转' Reverse_List '裁剪的起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString BGNL? '绘制的起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString '旋转度数' PosString? Newline @@ -3503,7 +3170,7 @@ return code; */; drawIcon_s - : '绘制图标' 'ID' IdString '帧' Int '起点像素' 'x' PosString 'y' PosString '宽' PosString? '高' PosString? Newline + : '(已弃用)绘制图标' 'ID' IdString '帧' Int '起点像素' 'x' PosString 'y' PosString '宽' PosString? '高' PosString? Newline /* drawIcon_s @@ -3521,7 +3188,7 @@ return code; */; drawBackground_s - : '绘制背景图' EvalString Colour '起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString Newline + : '(已弃用)绘制背景图' EvalString Colour '起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString Newline /* drawBackground_s @@ -3545,7 +3212,7 @@ return code; */; drawSelector_s - : '绘制闪烁光标' EvalString '编号' Int '起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString Newline + : '(已弃用)绘制闪烁光标' EvalString '编号' Int '起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString Newline /* drawSelector_s @@ -3559,7 +3226,7 @@ return code; */; drawSelector_1_s - : '清除闪烁光标' '编号' Int Newline + : '(已弃用)清除闪烁光标' '编号' Int Newline /* drawSelector_1_s @@ -4005,6 +3672,10 @@ TextAlign_List : '不改变'|'左对齐'|'左右居中'|'右对齐' /*TextAlign_List ['null','left','center','right']*/; +WordBreak_List + : '不改变'|'不分词'|'空格分词'|'全部分词' + /*WordBreak_List ['null','none','space','all']*/; + TextBaseline_List : '不改变'|'顶部'|'悬挂'|'居中'|'标准值'|'ideographic'|'底部' /*TextBaseline_List ['null','top','hanging','middle','alphabetic','ideographic','bottom']*/; diff --git a/public/_server/MotaActionParser.js b/public/_server/MotaActionParser.js index 23cac8a..115e78e 100644 --- a/public/_server/MotaActionParser.js +++ b/public/_server/MotaActionParser.js @@ -249,10 +249,6 @@ ActionParser.prototype.parseAction = function() { // 不同种类的事件 - // 如果是文字:显示 - if (typeof data == "string") { - data={"type": "text", "text": data} - } this.event.data.type=data.type; switch (data.type) { case "_next": @@ -260,57 +256,9 @@ ActionParser.prototype.parseAction = function() { this.next = data.next; return; case "text": // 文字/对话 - var info = this.getTitleAndPosition(data.text); - var textDrawing = []; - info[3] = (info[3] || "").replace(/(\f|\\f)\[(.*?)]/g, function (text, sympol, str) { - var ss = str.split(","); - if (ss.length == 3 || ss.length == 5 || ss.length >=9) { - var swap = function (i, j) { var x = ss[i]; ss[i] = ss[j]; ss[j] = x;} - if (ss.length >= 9) { - swap(1,5); swap(2,6); swap(3,7); swap(4,8); - } - textDrawing.push(ss); - } - return ''; - }); - if (textDrawing.length > 0) { - var buildTextDrawing = function (obj) { - if(!obj) obj=[]; - var text_choices = null; - for(var ii=obj.length-1,choice;choice=obj[ii];ii--) { - var reverse = 'null'; - if (choice[0].endsWith(':o') || choice[0].endsWith(':x') || choice[0].endsWith(':y')) { - reverse = choice[0].substring(choice[0].length - 2); - choice[0] = choice[0].substring(0, choice[0].length - 2); - } - text_choices=MotaActionBlocks['textDrawing'].xmlText([ - choice[0], reverse, choice[1], choice[2], choice[3], choice[4], choice[5], choice[6], - choice[7], choice[8], choice[9], choice[10], text_choices]); - } - return text_choices; - } - data.pos = data.pos || []; - this.next = MotaActionFunctions.xmlText('text_2_s', [ - info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], data.code||0, data.async||false, info[3], buildTextDrawing(textDrawing), this.next - ], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); - } else if (info[0] || info[1] || info[2] || data.pos || data.code) { - data.pos = data.pos || []; - this.next = MotaActionFunctions.xmlText('text_1_s',[ - info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], data.code||0, data.async||false, info[3], this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); - } - else { - this.next = MotaActionFunctions.xmlText('text_0_s', [info[3],this.next], - /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); - } - break; - case "moveTextBox": // 移动对话框 - data.loc = data.loc || ['','']; - this.next = MotaActionBlocks['moveTextBox_s'].xmlText([ - data.code, data.loc[0], data.loc[1], data.relative||false, data.moveMode, data.time, data.async, this.next]); - break; - case "clearTextBox": // 清除对话框 - this.next = MotaActionBlocks['clearTextBox_s'].xmlText([(data.code||"").toString(),this.next]); - break; + this.next = MotaActionBlocks['text_s'].xmlText([ + data.title, data.icon, data.x, data.y, data.width, data.height, data.keepLast,data.interval,data.lineHeight, this.next]); + break; case "autoText": // 自动剧情文本 var info = this.getTitleAndPosition(data.text); this.next = MotaActionBlocks['autoText_s'].xmlText([ @@ -324,14 +272,14 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['comment_s'].xmlText([this.EvalString_Multi(data.text),this.next]); break; case "setText": // 设置剧情文本的属性 - data.title=this.Colour(data.title); - data.text=this.Colour(data.text); - if (!/^\w+\.png$/.test(data.background)) - data.background=this.Colour(data.background); + //data.backColor=this.Colour(data.backColor); + //data.fillStyle=this.Colour(data.fillStyle); + //data.strokeStyle=this.Colour(data.strokeStyle); this.next = MotaActionBlocks['setText_s'].xmlText([ - data.position,data.offset,data.align,data.bold,data.title,'rgba('+data.title+')', - data.text,'rgba('+data.text+')',data.background,'rgba('+data.background+')', - data.titlefont,data.textfont,data.lineHeight,data.time,data.letterSpacing,data.animateTime,this.next]); + data.x,data.y,data.width,data.height,data.fontFamily,data.fontSize,data.fontWeight, + data.fontItalic,data.keepLast,data.interval,data.lineHeight,,data.fillStyle,'rgba('+data.fillStyle+')', + data.strokeStyle,'rgba('+data.strokeStyle+')',data.strokeWidth,data.fill,data.stroke,data.backColor,'rgba('+data.backColor+')', + data.winskin,data.padding,data.titleFill,data.titleStroke,data.titlePadding,data.textAlign,data.wordBreak,data.ignoreLineStart,data.ignoreLineEnd,data.breakChars,this.next]); break; case "tip": this.next = MotaActionBlocks['tip_s'].xmlText([ @@ -385,18 +333,6 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['setBlockOpacity_s'].xmlText([ x_str.join(','),y_str.join(','),data.floorId||'',data.opacity,data.time,data.async||false,this.next]); break; - case "setBlockFilter": // 设置图块不透明度 - data.loc=data.loc||[]; - if (!(data.loc[0] instanceof Array)) - data.loc = [data.loc]; - var x_str=[],y_str=[]; - data.loc.forEach(function (t) { - x_str.push(t[0]); - y_str.push(t[1]); - }) - this.next = MotaActionBlocks['setBlockFilter_s'].xmlText([ - x_str.join(','),y_str.join(','),data.floorId||'',data.blur,data.hue,data.grayscale,data.invert||false,data.shadow,this.next]); - break; case "turnBlock": // 事件转向 data.loc=data.loc||[]; if (!(data.loc[0] instanceof Array)) @@ -542,12 +478,6 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['changePos_s'].xmlText([ data.loc[0],data.loc[1],data.direction,this.next]); break; - case "follow": // 跟随勇士 - this.next = MotaActionBlocks['follow_s'].xmlText([data.name||"", this.next]); - break; - case "unfollow": // 取消跟随 - this.next = MotaActionBlocks['unfollow_s'].xmlText([data.name||"", this.next]); - break; case "animate": // 显示动画 if (data.loc == 'hero') { this.next = MotaActionBlocks['animate_1_s'].xmlText([ @@ -616,11 +546,6 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['scaleImage_s'].xmlText([ data.code, data.center[0], data.center[1], data.moveMode||'', data.scale, data.time||0, data.async||false, this.next]); break; - case "showGif": // 显示动图 - data.loc=data.loc||['',''] - this.next = MotaActionBlocks['showGif_s'].xmlText([ - data.name,data.loc[0],data.loc[1],this.next]); - break; case "setCurtain": // 颜色渐变 if(this.isset(data.color)){ data.color = this.Colour(data.color); @@ -750,47 +675,6 @@ ActionParser.prototype.parseAction = function() { data.norefresh || false, this.next]); break; - case "setEnemy": - this.next = MotaActionBlocks['setEnemy_s'].xmlText([ - MotaActionFunctions.replaceToName_token(data.id), data.name, data["operator"]||'=', this.expandEvalBlock([data.value]), - data.norefresh||false, this.next]); - break; - case "setEnemyOnPoint": - data.loc=data.loc||[]; - if (!(data.loc[0] instanceof Array)) - data.loc = [data.loc]; - var x_str=[],y_str=[]; - data.loc.forEach(function (t) { - x_str.push(t[0]); - y_str.push(t[1]); - }) - this.next = MotaActionBlocks['setEnemyOnPoint_s'].xmlText([ - x_str.join(','),y_str.join(','),data.floorId||'',data.name, data["operator"]||'=', this.expandEvalBlock([data.value]), - data.norefresh||false, this.next]); - break; - case "resetEnemyOnPoint": - data.loc=data.loc||[]; - if (!(data.loc[0] instanceof Array)) - data.loc = [data.loc]; - var x_str=[],y_str=[]; - data.loc.forEach(function (t) { - x_str.push(t[0]); - y_str.push(t[1]); - }) - this.next = MotaActionBlocks['resetEnemyOnPoint_s'].xmlText([ - x_str.join(','),y_str.join(','), data.floorId||'',data.norefresh||false,this.next]); - break; - case "moveEnemyOnPoint": - data.from=data.from||['',''] - if (data.dxy) { - this.next = MotaActionBlocks['moveEnemyOnPoint_1_s'].xmlText([ - data.from[0], data.from[1], data.dxy[0], data.dxy[1], data.floorId||'',data.norefresh||false,this.next]); - } else { - data.to=data.to||['',''] - this.next = MotaActionBlocks['moveEnemyOnPoint_s'].xmlText([ - data.from[0], data.from[1], data.to[0], data.to[1], data.floorId||'',data.norefresh||false,this.next]); - } - break; case "setEquip": this.next = MotaActionBlocks['setEquip_s'].xmlText([ MotaActionFunctions.replaceToName_token(data.id), data.valueType||'value', data.name, data["operator"]||'=', this.expandEvalBlock([data.value]), this.next]); diff --git a/public/_server/editor_blocklyconfig.js b/public/_server/editor_blocklyconfig.js index 5d95776..f12a973 100644 --- a/public/_server/editor_blocklyconfig.js +++ b/public/_server/editor_blocklyconfig.js @@ -96,11 +96,8 @@ editor_blocklyconfig=(function(){ ], 'splitImages'), ], '显示文字':[ - MotaActionBlocks['text_0_s'].xmlText(), - MotaActionBlocks['text_1_s'].xmlText(), - MotaActionFunctions.actionParser.parseList("\t[小妖精,fairy]\f[fairy.png,0,0]欢迎使用事件编辑器(双击方块可直接预览)"), - MotaActionBlocks['moveTextBox_s'].xmlText(), - MotaActionBlocks['clearTextBox_s'].xmlText(), + MotaActionBlocks['text_s'].xmlText(), + MotaActionBlocks['comment_s'].xmlText(), MotaActionBlocks['autoText_s'].xmlText(), MotaActionBlocks['scrollText_s'].xmlText(), @@ -120,11 +117,6 @@ editor_blocklyconfig=(function(){ MotaActionBlocks['setValue_s'].xmlText([ MotaActionBlocks['idIdList_e'].xmlText(['status','生命']), '=', '', false ]), - MotaActionBlocks['setEnemy_s'].xmlText(), - MotaActionBlocks['setEnemyOnPoint_s'].xmlText(), - MotaActionBlocks['resetEnemyOnPoint_s'].xmlText(), - MotaActionBlocks['moveEnemyOnPoint_s'].xmlText(), - MotaActionBlocks['moveEnemyOnPoint_1_s'].xmlText(), MotaActionBlocks['setEquip_s'].xmlText(), MotaActionBlocks['setFloor_s'].xmlText(), MotaActionBlocks['setGlobalAttribute_s'].xmlText(), @@ -143,9 +135,7 @@ editor_blocklyconfig=(function(){ MotaActionBlocks['unloadEquip_s'].xmlText(), MotaActionBlocks['openShop_s'].xmlText(), MotaActionBlocks['disableShop_s'].xmlText(), - MotaActionBlocks['setHeroIcon_s'].xmlText(), - MotaActionBlocks['follow_s'].xmlText(), - MotaActionBlocks['unfollow_s'].xmlText(), + MotaActionBlocks['setHeroIcon_s'].xmlText() ], '地图处理':[ MotaActionBlocks['battle_1_s'].xmlText(), @@ -155,7 +145,6 @@ editor_blocklyconfig=(function(){ MotaActionBlocks['hide_s'].xmlText(), MotaActionBlocks['setBlock_s'].xmlText(), MotaActionBlocks['setBlockOpacity_s'].xmlText(), - MotaActionBlocks['setBlockFilter_s'].xmlText(), MotaActionBlocks['turnBlock_s'].xmlText(), MotaActionBlocks['moveHero_s'].xmlText(), MotaActionBlocks['move_s'].xmlText(), @@ -225,7 +214,6 @@ editor_blocklyconfig=(function(){ MotaActionBlocks['moveImage_s'].xmlText(), MotaActionBlocks['rotateImage_s'].xmlText(), MotaActionBlocks['scaleImage_s'].xmlText(), - MotaActionBlocks['showGif_s'].xmlText(), MotaActionBlocks['playBgm_s'].xmlText(), MotaActionBlocks['pauseBgm_s'].xmlText(), MotaActionBlocks['resumeBgm_s'].xmlText(), diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 56dc874..4328b8d 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -184,8 +184,6 @@ export abstract class GraphicItemBase ctx.lineJoin = this.lineJoin; ctx.lineCap = this.lineCap; ctx.miterLimit = this.miterLimit; - ctx.fill(this.fillRule); - this.update(); } patchProp( @@ -257,7 +255,7 @@ export abstract class GraphicItemBase export class Rect extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; this.setCanvasState(canvas); @@ -290,7 +288,7 @@ export class Circle extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; this.setCanvasState(canvas); @@ -369,7 +367,7 @@ export class Ellipse extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; this.setCanvasState(canvas); @@ -461,7 +459,7 @@ export class Line extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; this.setCanvasState(canvas); @@ -530,7 +528,7 @@ export class BezierCurve extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; this.setCanvasState(canvas); @@ -638,7 +636,7 @@ export class QuadraticCurve extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; this.setCanvasState(canvas); @@ -718,7 +716,7 @@ export class Path extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; this.setCanvasState(canvas); @@ -839,7 +837,7 @@ export class RectR extends GraphicItemBase { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; this.setCanvasState(canvas); diff --git a/src/core/render/preset/misc.ts b/src/core/render/preset/misc.ts index 7fa69fd..523aa68 100644 --- a/src/core/render/preset/misc.ts +++ b/src/core/render/preset/misc.ts @@ -1,5 +1,4 @@ import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d'; -import { Sprite } from '../sprite'; import { ERenderItemEvent, IAnimateFrame, @@ -11,8 +10,6 @@ import { Transform } from '../transform'; import { ElementNamespace, ComponentInternalInstance } from 'vue'; import { AutotileRenderable, RenderableData } from '../cache'; import { texture } from '../cache'; -import { isNil } from 'lodash-es'; -import { logger } from '@/core/common/logger'; type CanvasStyle = string | CanvasGradient | CanvasPattern; @@ -42,7 +39,7 @@ export class Text extends RenderItem { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; ctx.textBaseline = 'bottom'; @@ -171,7 +168,7 @@ export class Image extends RenderItem { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; ctx.drawImage(this.image, 0, 0, canvas.width, canvas.height); @@ -209,8 +206,8 @@ export class Comment extends RenderItem { } protected render( - canvas: MotaOffscreenCanvas2D, - transform: Transform + _canvas: MotaOffscreenCanvas2D, + _transform: Transform ): void {} } @@ -228,7 +225,7 @@ export class Icon extends RenderItem implements IAnimateFrame { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; const renderable = this.renderable; @@ -239,7 +236,7 @@ export class Icon extends RenderItem implements IAnimateFrame { const frame = this.animate ? RenderItem.animatedFrame % renderable.frame : 0; - if (this.animate) { + if (!this.animate) { if (renderable.autotile) { ctx.drawImage(renderable.image[0], x, y, w, h, 0, 0, cw, ch); } else { @@ -336,7 +333,7 @@ export class Winskin extends RenderItem { protected render( canvas: MotaOffscreenCanvas2D, - transform: Transform + _transform: Transform ): void { const ctx = canvas.ctx; const img = this.image; @@ -346,7 +343,8 @@ export class Winskin extends RenderItem { const h = canvas.height; const sz = this.borderSize / 32; ctx.drawImage(img, 128, 0, 16, 16, x, y, 16 * sz, 16 * sz); - for (var dx = 0; dx < w - 64 * sz; dx += 32 * sz) { + let dx; + for (dx = 0; dx < w - 64 * sz; dx += 32 * sz) { ctx.drawImage( img, 144, @@ -404,7 +402,8 @@ export class Winskin extends RenderItem { 16 * sz ); // 左右 - for (var dy = 0; dy < h - 64 * sz; dy += 32 * sz) { + let dy; + for (dy = 0; dy < h - 64 * sz; dy += 32 * sz) { ctx.drawImage( img, 128, From ba1e7ea228d326957066e4c7bc627db9396109e2 Mon Sep 17 00:00:00 2001 From: strawberry42271 <2806566736@qq.com> Date: Sun, 12 Jan 2025 12:53:32 +0800 Subject: [PATCH 19/22] =?UTF-8?q?fix=20:=20=20graphic=E7=B1=BB=E5=88=AB?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/render/preset/graphics.ts | 4 ++-- src/core/render/preset/misc.ts | 28 ++++++++++++---------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/core/render/preset/graphics.ts b/src/core/render/preset/graphics.ts index 4328b8d..def6470 100644 --- a/src/core/render/preset/graphics.ts +++ b/src/core/render/preset/graphics.ts @@ -196,11 +196,11 @@ export abstract class GraphicItemBase if (isNil(prevValue) && isNil(nextValue)) return; switch (key) { case 'fill': - if (!this.assertType(nextValue, 'number', key)) return; + if (!this.assertType(nextValue, 'boolean', key)) return; this.checkMode(GraphicModeProp.Fill, nextValue); break; case 'stroke': - if (!this.assertType(nextValue, 'number', key)) return; + if (!this.assertType(nextValue, 'boolean', key)) return; this.checkMode(GraphicModeProp.Stroke, nextValue); break; case 'strokeAndFill': diff --git a/src/core/render/preset/misc.ts b/src/core/render/preset/misc.ts index 523aa68..37d8126 100644 --- a/src/core/render/preset/misc.ts +++ b/src/core/render/preset/misc.ts @@ -217,9 +217,9 @@ export class Icon extends RenderItem implements IAnimateFrame { /** 图标id */ icon: AllNumbers = 0; /** 帧数 */ - frame: number = 0; + frame?: number = 0; /** 是否启用动画 */ - animate: boolean = false; + animate?: boolean = false; /** 图标的渲染信息 */ private renderable?: RenderableData | AutotileRenderable; @@ -245,21 +245,13 @@ export class Icon extends RenderItem implements IAnimateFrame { } else { const [x1, y1, w1, h1] = renderable.render[frame]; if (renderable.autotile) { - ctx.drawImage( - renderable.image[0], - x1, - y1, - w1, - h1, - 0, - 0, - cw, - ch - ); + const img = renderable.image[0]; + ctx.drawImage(img, x1, y1, w1, h1, 0, 0, cw, ch); } else { ctx.drawImage(renderable.image, x1, y1, w1, h1, 0, 0, cw, ch); } - this.update(this), renderEmits.addFramer(this); + this.update(this); + renderEmits.addFramer(this); } } @@ -276,13 +268,17 @@ export class Icon extends RenderItem implements IAnimateFrame { return; } else { this.icon = num; - renderable.animate = 0; - this.renderable = renderable; + this.frame = renderable.frame; } this.update(); } + destroy(): void { + renderEmits.removeFramer(this); + super.destroy(); + } + /** * 更新动画帧 */ From b2a391a21240f3d8491d130d2bb3c3a0dbea92cd Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sun, 12 Jan 2025 13:09:10 +0800 Subject: [PATCH 20/22] fix: icon --- src/core/render/cache.ts | 3 +++ src/core/render/index.tsx | 1 + src/core/render/preset/misc.ts | 45 ++++++++++++++++++++++++------- src/core/render/renderer/props.ts | 4 +-- src/data/logger.json | 1 + src/game/game.ts | 6 ++++- 6 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/core/render/cache.ts b/src/core/render/cache.ts index c1f9940..cb2165d 100644 --- a/src/core/render/cache.ts +++ b/src/core/render/cache.ts @@ -211,6 +211,7 @@ class TextureCache extends EventEmitter { // enemy48和npc48都应该视为大怪物 if (cls === 'enemy48' || cls === 'npc48') { const img = core.material.images[cls]; + if (!img) return null; // @ts-ignore const line = icons[cls][id]; const w = 32; @@ -234,6 +235,7 @@ class TextureCache extends EventEmitter { } // 自动元件 if (cls === 'autotile') { + if (!this.autotile) return null; const auto = this.autotile[num as AllNumbersOf<'autotile'>]; const cell = 32; const render: [number, number, number, number][] = []; @@ -264,6 +266,7 @@ class TextureCache extends EventEmitter { core.material.images[ cls as Exclude ]; + if (!image) return null; const frame = core.getAnimateFrames(cls); const cell = 32; // @ts-ignore diff --git a/src/core/render/index.tsx b/src/core/render/index.tsx index 5bbbb9f..c08f463 100644 --- a/src/core/render/index.tsx +++ b/src/core/render/index.tsx @@ -69,6 +69,7 @@ Mota.require('var', 'loading').once('coreInit', () => { + ); }); diff --git a/src/core/render/preset/misc.ts b/src/core/render/preset/misc.ts index 37d8126..7a94540 100644 --- a/src/core/render/preset/misc.ts +++ b/src/core/render/preset/misc.ts @@ -10,6 +10,8 @@ import { Transform } from '../transform'; import { ElementNamespace, ComponentInternalInstance } from 'vue'; import { AutotileRenderable, RenderableData } from '../cache'; import { texture } from '../cache'; +import { isNil } from 'lodash-es'; +import { logger } from '@/core/common/logger'; type CanvasStyle = string | CanvasGradient | CanvasPattern; @@ -223,6 +225,14 @@ export class Icon extends RenderItem implements IAnimateFrame { /** 图标的渲染信息 */ private renderable?: RenderableData | AutotileRenderable; + private pendingIcon?: AllNumbers; + + constructor(type: RenderItemPosition, cache?: boolean, fall?: boolean) { + super(type, cache, fall); + this.setAntiAliasing(false); + this.setHD(false); + } + protected render( canvas: MotaOffscreenCanvas2D, _transform: Transform @@ -236,6 +246,7 @@ export class Icon extends RenderItem implements IAnimateFrame { const frame = this.animate ? RenderItem.animatedFrame % renderable.frame : 0; + if (!this.animate) { if (renderable.autotile) { ctx.drawImage(renderable.image[0], x, y, w, h, 0, 0, cw, ch); @@ -250,8 +261,6 @@ export class Icon extends RenderItem implements IAnimateFrame { } else { ctx.drawImage(renderable.image, x1, y1, w1, h1, 0, 0, cw, ch); } - this.update(this); - renderEmits.addFramer(this); } } @@ -261,24 +270,35 @@ export class Icon extends RenderItem implements IAnimateFrame { */ setIcon(id: AllIds | AllNumbers) { const num = typeof id === 'number' ? id : texture.idNumberMap[id]; + + const loading = Mota.require('var', 'loading'); + if (loading.loaded) { + this.setIconRenderable(num); + } else { + if (isNil(this.pendingIcon)) { + loading.once('loaded', () => { + this.setIconRenderable(this.pendingIcon ?? 0); + this.pendingIcon = void 0; + }); + } + this.pendingIcon = num; + } + } + + private setIconRenderable(num: AllNumbers) { const renderable = texture.getRenderable(num); if (!renderable) { - //todo: logger.warn() + logger.warn(42, num.toString()); return; } else { this.icon = num; - + this.renderable = renderable; this.frame = renderable.frame; } this.update(); } - destroy(): void { - renderEmits.removeFramer(this); - super.destroy(); - } - /** * 更新动画帧 */ @@ -286,6 +306,11 @@ export class Icon extends RenderItem implements IAnimateFrame { this.update(this); } + destroy(): void { + renderEmits.removeFramer(this); + super.destroy(); + } + patchProp( key: string, prevValue: any, @@ -300,6 +325,8 @@ export class Icon extends RenderItem implements IAnimateFrame { case 'animate': if (!this.assertType(nextValue, 'boolean', key)) return; this.animate = nextValue; + if (nextValue) renderEmits.addFramer(this); + else renderEmits.removeFramer(this); this.update(); return; case 'frame': diff --git a/src/core/render/renderer/props.ts b/src/core/render/renderer/props.ts index 10bf408..e57777c 100644 --- a/src/core/render/renderer/props.ts +++ b/src/core/render/renderer/props.ts @@ -178,8 +178,8 @@ export interface RectRProps extends GraphicPropsBase { export interface IconProps extends BaseProps { icon: AllNumbers; - frame: number; - animate: boolean; + frame?: number; + animate?: boolean; } export interface WinskinProps extends BaseProps { diff --git a/src/data/logger.json b/src/data/logger.json index ae0a740..4561353 100644 --- a/src/data/logger.json +++ b/src/data/logger.json @@ -70,6 +70,7 @@ "40": "Cannot return canvas that is not provided by this pool.", "41": "Width of text content components must be positive. receive: $1", "42": "Repeated Textbox id: '$1'.", + "43": "Cannot set icon of '$1', since it does not exists. Please ensure you have delivered correct icon id or number.", "1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency.", "1101": "Cannot add new effect to point effect instance, for there's no more reserve space for it. Please increase the max count of the instance." } diff --git a/src/game/game.ts b/src/game/game.ts index 1973e9d..e4ee54d 100644 --- a/src/game/game.ts +++ b/src/game/game.ts @@ -13,12 +13,16 @@ class GameLoading extends EventEmitter { private autotileLoaded: number = 0; private autotileNum?: number; private autotileListened: boolean = false; + loaded: boolean = false; constructor() { super(); - this.on('coreInit', () => { + this.once('coreInit', () => { this.autotileNum = Object.keys(core.material.icons.autotile).length; }); + this.once('loaded', () => { + this.loaded = true; + }); } addAutotileLoaded() { From 52c5126997337c09cd0190b8d5ebaaf08f8aecfb Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sun, 12 Jan 2025 13:10:52 +0800 Subject: [PATCH 21/22] fix: warn code. --- src/core/render/preset/misc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/render/preset/misc.ts b/src/core/render/preset/misc.ts index 7a94540..e93290b 100644 --- a/src/core/render/preset/misc.ts +++ b/src/core/render/preset/misc.ts @@ -289,7 +289,7 @@ export class Icon extends RenderItem implements IAnimateFrame { const renderable = texture.getRenderable(num); if (!renderable) { - logger.warn(42, num.toString()); + logger.warn(43, num.toString()); return; } else { this.icon = num; From c7b2e6dd30b64cac1ed2a1add7d514b4c7507482 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sun, 12 Jan 2025 14:16:52 +0800 Subject: [PATCH 22/22] refactor: Winskin.image --- src/core/render/preset/misc.ts | 30 ++++++++++++++++++++++++++++-- src/core/render/renderer/props.ts | 4 ++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/core/render/preset/misc.ts b/src/core/render/preset/misc.ts index e93290b..c9f5912 100644 --- a/src/core/render/preset/misc.ts +++ b/src/core/render/preset/misc.ts @@ -278,7 +278,7 @@ export class Icon extends RenderItem implements IAnimateFrame { if (isNil(this.pendingIcon)) { loading.once('loaded', () => { this.setIconRenderable(this.pendingIcon ?? 0); - this.pendingIcon = void 0; + delete this.pendingIcon; }); } this.pendingIcon = num; @@ -346,6 +346,8 @@ export class Winskin extends RenderItem { /** 边框宽度 */ borderSize: number = 32; + private pendingImage?: ImageIds; + constructor( image: SizedCanvasImageSource, type: RenderItemPosition = 'static' @@ -507,6 +509,29 @@ export class Winskin extends RenderItem { this.update(); } + /** + * 通过图片名称设置winskin + * @param name 图片名称 + */ + setImageByName(name: ImageIds) { + const loading = Mota.require('var', 'loading'); + if (loading.loaded) { + const image = core.material.images.images[name]; + this.setImage(image); + } else { + if (isNil(this.pendingImage)) { + loading.once('loaded', () => { + const id = this.pendingImage; + if (!id) return; + const image = core.material.images.images[id]; + this.setImage(image); + delete this.pendingImage; + }); + } + this.pendingImage = name; + } + } + /** * 设置边框大小 * @param size 边框大小 @@ -525,7 +550,8 @@ export class Winskin extends RenderItem { ): void { switch (key) { case 'image': - this.setImage(nextValue); + if (!this.assertType(nextValue, 'string', key)) return; + this.setImageByName(nextValue); return; case 'borderSize': if (!this.assertType(nextValue, 'number', key)) return; diff --git a/src/core/render/renderer/props.ts b/src/core/render/renderer/props.ts index e57777c..c71fe3d 100644 --- a/src/core/render/renderer/props.ts +++ b/src/core/render/renderer/props.ts @@ -183,6 +183,6 @@ export interface IconProps extends BaseProps { } export interface WinskinProps extends BaseProps { - image: SizedCanvasImageSource; - borderSize: number; + image: ImageIds; + borderSize?: number; }