diff --git a/src/plugin/layout/layout.ts b/src/plugin/layout/layout.ts index 8810e47..7fe5316 100644 --- a/src/plugin/layout/layout.ts +++ b/src/plugin/layout/layout.ts @@ -1,3 +1,5 @@ +import { has } from '../utils'; + type CanvasStyle = string | CanvasPattern | CanvasGradient; export class Layout { @@ -18,23 +20,23 @@ export class Layout { this.ctx = canvas.getContext('2d')!; } - image(layout: Layout | HTMLCanvasElement | Path2D, type: number): Layout; + image(layout: Layout | CanvasImageSource | Path2D, type: number): this; image( - layout: Layout | HTMLCanvasElement | Path2D, + layout: Layout | CanvasImageSource | Path2D, type: number, x: number, y: number - ): Layout; + ): this; image( - layout: Layout | HTMLCanvasElement | Path2D, + layout: Layout | CanvasImageSource | Path2D, type: number, x: number, y: number, w: number, h: number - ): Layout; + ): this; image( - layout: Layout | HTMLCanvasElement | Path2D, + layout: Layout | CanvasImageSource | Path2D, type: number, sx: number, sy: number, @@ -44,12 +46,12 @@ export class Layout { dy: number, dw: number, dh: number - ): Layout; + ): this; image( - layout: Layout | HTMLCanvasElement | Path2D, + layout: Layout | CanvasImageSource | Path2D, type: number, - sx?: number, - sy?: number, + sx: number = 0, + sy: number = 0, sw?: number, sh?: number, dx?: number, @@ -57,6 +59,40 @@ export class Layout { dw?: number, dh?: number ) { + const img = layout instanceof Layout ? layout.canvas : layout; + const fill = () => { + if (img instanceof Path2D) { + this.ctx.fill(img); + } else { + this.ctx.drawImage(img, sx, sy, sw!, sh!, dx!, dy!, dw!, dh!); + } + }; + if (type & Layout.IMAGE) { + // 绘制图片 + fill(); + } + if (type & Layout.CLEAR) { + // 按照图片清除一个区域 + this.ctx.save(); + this.ctx.globalCompositeOperation = 'destination-out'; + fill(); + this.ctx.restore(); + } + if (type & Layout.MASK) { + // 蒙版,只显示蒙版内的东西 + this.ctx.save(); + this.ctx.globalCompositeOperation = 'destination-in'; + fill(); + this.ctx.restore(); + } + return this; + } + + /** + * 擦除一个矩形 + */ + clear(x: number, y: number, w: number, h: number): this { + this.ctx.clearRect(x, y, w, h); return this; } @@ -74,7 +110,9 @@ export class Layout { x: number, y: number, maxWidth?: number - ): Layout { + ): this { + if (type & Layout.FILL) this.ctx.fillText(str, x, y, maxWidth); + if (type & Layout.STROKE) this.ctx.strokeText(str, x, y, maxWidth); return this; } @@ -83,21 +121,25 @@ export class Layout { * @param path 路径 * @param type 绘制类型 */ - path(path: Path2D, type: number): Layout { + path(path: Path2D, type: number, rule?: CanvasFillRule): this { + if (type & Layout.FILL) this.ctx.fill(path, rule); + if (type & Layout.STROKE) this.ctx.stroke(path); return this; } /** * 保存画布状态 */ - save(): Layout { + save(): this { + this.ctx.save(); return this; } /** * 回退画布状态 */ - restore(): Layout { + restore(): this { + this.ctx.restore(); return this; } @@ -105,7 +147,8 @@ export class Layout { * 设置填充样式 * @param style 样式 */ - fillStyle(style: CanvasStyle): Layout { + fillStyle(style: CanvasStyle): this { + this.ctx.fillStyle = style; return this; } @@ -113,7 +156,8 @@ export class Layout { * 设置描边样式 * @param style 样式 */ - strokeStyle(style: CanvasStyle): Layout { + strokeStyle(style: CanvasStyle): this { + this.ctx.strokeStyle = style; return this; } @@ -121,7 +165,8 @@ export class Layout { * 设置文本对齐 * @param align 文本左右对齐方式 */ - textAlign(align: CanvasTextAlign): Layout { + textAlign(align: CanvasTextAlign): this { + this.ctx.textAlign = align; return this; } @@ -129,7 +174,8 @@ export class Layout { * 设置文本基线 * @param align 文本基线,即文本上下对齐方式 */ - textBaseline(align: CanvasTextBaseline): Layout { + textBaseline(align: CanvasTextBaseline): this { + this.ctx.textBaseline = align; return this; } @@ -137,7 +183,8 @@ export class Layout { * 设置滤镜 * @param filter 滤镜 */ - filter(filter: string): Layout { + filter(filter: string): this { + this.ctx.filter = filter; return this; } @@ -145,7 +192,11 @@ export class Layout { * 设置阴影信息 * @param shadow 阴影信息 */ - shadow(shadow: Partial): Layout { + shadow(shadow: Partial): this { + for (const [p, v] of Object.entries(shadow)) { + // @ts-ignore + this.ctx[p] = v; + } return this; } @@ -153,7 +204,8 @@ export class Layout { * 设置线宽(描边宽度,包括字体描边) * @param width 宽度 */ - lineWidth(width: number): Layout { + lineWidth(width: number): this { + this.ctx.lineWidth = width; return this; } @@ -161,7 +213,8 @@ export class Layout { * 设置线尾样式 * @param cap 线尾样式 */ - lineCap(cap: CanvasLineCap): Layout { + lineCap(cap: CanvasLineCap): this { + this.ctx.lineCap = cap; return this; } @@ -169,7 +222,8 @@ export class Layout { * 设置线段连接方式样式 * @param join 线段连接方式 */ - lineJoin(join: CanvasLineJoin): Layout { + lineJoin(join: CanvasLineJoin): this { + this.ctx.lineJoin = join; return this; } @@ -177,7 +231,8 @@ export class Layout { * 设置画布的字体 * @param font 字体 */ - font(font: string): Layout { + font(font: string): this { + this.ctx.font = font; return this; } @@ -185,7 +240,8 @@ export class Layout { * 设置画布之后绘制的不透明度 * @param alpha 不透明度 */ - alpha(alpha: number): Layout { + alpha(alpha: number): this { + this.ctx.globalAlpha = alpha; return this; } @@ -193,7 +249,8 @@ export class Layout { * 设置虚线样式 * @param dash 虚线样式 */ - lineDash(dash: number[]): Layout { + lineDash(dash: number[]): this { + this.ctx.setLineDash(dash); return this; } @@ -202,7 +259,8 @@ export class Layout { * @param x 横向放缩量 * @param y 纵向放缩量 */ - scale(x: number, y: number): Layout { + scale(x: number, y: number): this { + this.ctx.scale(x, y); return this; } @@ -210,7 +268,8 @@ export class Layout { * 旋转画布 * @param rad 顺时针旋转的弧度数 */ - rotate(rad: number): Layout { + rotate(rad: number): this { + this.ctx.rotate(rad); return this; } @@ -219,7 +278,8 @@ export class Layout { * @param x 水平平移量 * @param y 竖直平移量 */ - translate(x: number, y: number): Layout { + translate(x: number, y: number): this { + this.ctx.translate(x, y); return this; } @@ -256,6 +316,8 @@ export class Layout { e?: number, f?: number ) { + if (!has(a)) this.ctx.resetTransform(); + else this.ctx.transform(a, b!, c!, d!, e!, f!); return this; } @@ -263,7 +325,15 @@ export class Layout { * 设置混合方式,像image的蒙版功能与擦除功能本质上也是通过设置混合方式实现的 * @param value 混合方式 */ - composite(value: GlobalCompositeOperation): Layout { + composite(value: GlobalCompositeOperation): this { + this.ctx.globalCompositeOperation = value; return this; } + + /** + * 删除这个布局 + */ + destroy() { + this.canvas.remove(); + } } diff --git a/src/plugin/layout/layoutGame.ts b/src/plugin/layout/layoutGame.ts new file mode 100644 index 0000000..7e84604 --- /dev/null +++ b/src/plugin/layout/layoutGame.ts @@ -0,0 +1,255 @@ +import { Layout } from './layout'; + +export class LayoutGame extends Layout { + /** 画布id */ + id: string; + + constructor( + id: string, + x: number, + y: number, + w: number, + h: number, + z: number + ) { + const ctx = core.createCanvas(id, x, y, w, h, z); + super(ctx.canvas); + this.id = id; + } + + image2( + layout: Layout | CanvasImageSource | Path2D | ImageIds, + type: number + ): LayoutGame; + image2( + layout: Layout | CanvasImageSource | Path2D | ImageIds, + type: number, + x: number, + y: number + ): LayoutGame; + image2( + layout: Layout | CanvasImageSource | Path2D | ImageIds, + type: number, + x: number, + y: number, + w: number, + h: number + ): LayoutGame; + image2( + layout: Layout | CanvasImageSource | Path2D | ImageIds, + type: number, + sx: number, + sy: number, + sw: number, + sh: number, + dx: number, + dy: number, + dw: number, + dh: number + ): LayoutGame; + image2( + layout: Layout | CanvasImageSource | Path2D | ImageIds, + type: number, + sx?: number, + sy?: number, + sw?: number, + sh?: number, + dx?: number, + dy?: number, + dw?: number, + dh?: number + ): this { + const img = + typeof layout === 'string' + ? core.material.images.images[layout] + : layout; + + this.image(img, type, sx!, sy!, sw!, sh!, dx!, dy!, dw!, dh!); + return this; + } + + /** + * 绘制一个图标 + * @param id 图标id + * @param x 横坐标 + * @param y 纵坐标 + * @param w 宽度 + * @param h 高度 + * @param frame 绘制第几帧 + */ + icon( + id: AllIds, + x: number, + y: number, + w?: number, + h?: number, + frame?: number + ): this { + core.drawIcon(this.ctx, id, x, y, w, h, frame); + return this; + } + + /** + * 绘制WindowSkin + * @param direction 指向箭头的方向 + */ + winskin( + background: any, + x: number, + y: number, + w: number, + h: number, + direction?: 'up' | 'down', + px?: number, + py?: number + ): this { + core.drawWindowSkin( + background, + this.ctx, + x, + y, + w, + h, + direction, + px, + py + ); + return this; + } + + /** + * 绘制一个箭头 + * @param x1 起始点横坐标 + * @param y1 起始点纵坐标 + * @param x2 终止点横坐标 + * @param y2 终止点纵坐标 + */ + arrow(x1: number, y1: number, x2: number, y2: number): this { + core.drawArrow(this.ctx, x1, y1, x2, y2); + return this; + } + + /** + * 绘制线段 + */ + line(x1: number, y1: number, x2: number, y2: number): this { + this.ctx.beginPath(); + this.ctx.moveTo(x1, y1); + this.ctx.lineTo(x2, y2); + this.ctx.stroke(); + return this; + } + + /** + * 绘制圆弧或扇形 + * @param type 绘制类型 + * @param start 起始弧度 + * @param end 终止弧度 + * @param anticlockwise 是否逆时针 + */ + arc( + type: number, + x: number, + y: number, + r: number, + start: number, + end: number, + anticlockwise: boolean = false + ): this { + this.ctx.beginPath(); + this.ctx.arc(x, y, r, start, end, anticlockwise); + this.draw(type); + return this; + } + + /** + * 绘制一个圆 + * @param type 绘制类型 + */ + circle(type: number, x: number, y: number, r: number): this { + return this.arc(type, x, y, r, 0, Math.PI * 2); + } + + /** + * 绘制椭圆 + */ + ellipse( + type: number, + x: number, + y: number, + a: number, + b: number, + rotation: number = 0, + start: number = 0, + end: number = Math.PI * 2, + anticlockwise: boolean = false + ): this { + this.ctx.beginPath(); + this.ctx.ellipse(x, y, a, b, rotation, start, end, anticlockwise); + this.draw(type); + return this; + } + + /** + * 绘制多边形 + * @param type 绘制类型 + * @param nodes 多边形节点 + * @param close 是否闭合路径 + */ + polygon(type: number, nodes: LocArr[], close: boolean = true): this { + this.ctx.beginPath(); + this.ctx.moveTo(nodes[0][0], nodes[0][1]); + for (let i = 1; i < nodes.length; i++) { + this.ctx.lineTo(nodes[i][0], nodes[i][1]); + } + if (close) this.ctx.closePath(); + this.draw(type); + return this; + } + + /** + * 绘制矩形 + */ + rect(type: number, x: number, y: number, w: number, h: number): this { + if (type & Layout.FILL) this.ctx.fillRect(x, y, w, h); + if (type & Layout.STROKE) this.ctx.strokeRect(x, y, w, h); + return this; + } + + /** + * 绘制圆角矩形 + */ + roundRect( + type: number, + x: number, + y: number, + w: number, + h: number, + r: number + ) { + this.ctx.beginPath(); + this.ctx.moveTo(x + r, y); + this.ctx.lineTo(x + w - r, y); + this.ctx.quadraticCurveTo(x + w, y, x + w, y + r); + this.ctx.lineTo(x + w, y + h - r); + this.ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h); + this.ctx.lineTo(x + r, y + h); + this.ctx.quadraticCurveTo(x, y + h, x, y + h - r); + this.ctx.lineTo(x, y + r); + this.ctx.quadraticCurveTo(x, y, x + r, y); + this.ctx.closePath(); + this.draw(type); + } + + /** + * 删除这个布局 + */ + destroy() { + core.deleteCanvas(this.id); + } + + private draw(type: number) { + if (type & Layout.FILL) this.ctx.fill(); + if (type & Layout.STROKE) this.ctx.stroke(); + } +} diff --git a/src/types/core.d.ts b/src/types/core.d.ts index ef55489..7d7137d 100644 --- a/src/types/core.d.ts +++ b/src/types/core.d.ts @@ -528,7 +528,7 @@ type MainDom = { * 自绘状态栏画布的context */ statusCanvasCtx: CanvasRenderingContext2D; - +} & { [key: string]: HTMLElement; }; @@ -806,7 +806,7 @@ type CoreStatusBarElements = { * 状态栏的图标元素 */ readonly image: Record; - +} & { readonly [key: string]: HTMLElement; }; @@ -1079,7 +1079,7 @@ interface Core extends Pick { * @param _this 执行函数的上下文 * @param params 函数的参数 */ - doFunc( + doFunc any>( func: F, _this: any, ...params: Parameters @@ -1210,7 +1210,16 @@ interface Main extends MainData { /** * 所有的素材图片名称 */ - readonly materials: Materials; + readonly materials: [ + 'animates', + 'enemys', + 'items', + 'npcs', + 'terrains', + 'enemy48', + 'npc48', + 'icons' + ]; /** * 要加载的project目录下的文件 diff --git a/src/types/data.d.ts b/src/types/data.d.ts index 157fead..f5fb3e8 100644 --- a/src/types/data.d.ts +++ b/src/types/data.d.ts @@ -24,6 +24,11 @@ interface MainData { */ readonly bgms: BgmIds[]; + /** + * 所有的图片 + */ + readonly images: ImageIds[]; + /** * 所有的音效 */ diff --git a/src/types/eventStatus.d.ts b/src/types/eventStatus.d.ts index 5a13d10..d69b179 100644 --- a/src/types/eventStatus.d.ts +++ b/src/types/eventStatus.d.ts @@ -309,7 +309,7 @@ interface ActionStatusData { /** * 当前的事件类型 */ - type: EventType; + type: string; /** * 当前事件 diff --git a/src/types/map.d.ts b/src/types/map.d.ts index 43c4fee..7e95a41 100644 --- a/src/types/map.d.ts +++ b/src/types/map.d.ts @@ -266,7 +266,7 @@ interface ResolvedFloor extends FloorBase { eachArrive?: MotaEvent; } -interface BlockInfo { +interface BlockInfo { /** * 图块数字 */ @@ -421,16 +421,6 @@ interface DrawThumbnailConfig { */ inFlyMap: boolean; - /** - * 小地图模式下的横坐标 - */ - x: number; - - /** - * 小地图模式下的纵坐标 - */ - y: number; - /** * 小地图模式下的宽度 */ @@ -537,7 +527,7 @@ interface Maps { * 根据数字获得图块 * @param number 图块数字 */ - getBlockByNumber(number: T): Block; + getBlockByNumber(number: T): Block; /** * 根据ID获得图块 @@ -634,7 +624,7 @@ interface Maps { * @param mapArr 地图信息 * @param floorId 地图id */ - decompressMap(mapArr?: number[][], floorId: FloorIds): number[][]; + decompressMap(mapArr?: number[][], floorId?: FloorIds): number[][]; /** * 将所有地图重新变成数字,以便于存档 @@ -1021,7 +1011,7 @@ interface Maps { * 获得某个图块或素材的信息 * @param block 图块信息,可以填图块,数字,id */ - getBlockInfo( + getBlockInfo( block?: Block | NumberToId[T] | T ): BlockInfo; diff --git a/src/types/plugin.d.ts b/src/types/plugin.d.ts index 164cb93..a02e233 100644 --- a/src/types/plugin.d.ts +++ b/src/types/plugin.d.ts @@ -207,7 +207,7 @@ interface PluginUis { readonly shopOpened: Ref; /** ui栈 */ - readonly uiStack: Ref; + readonly uiStack: Ref; /** * 显示章节 @@ -237,7 +237,7 @@ interface PluginUse { fn: DragFn, ondown?: DragFn, onUp?: (e: MouseEvent | TouchEvent) => void, - global: boolean = false + global?: boolean ): void; /** diff --git a/src/types/status.d.ts b/src/types/status.d.ts index 87ce069..ca92ce1 100644 --- a/src/types/status.d.ts +++ b/src/types/status.d.ts @@ -591,7 +591,7 @@ interface InitGameStatus { /** * 是否开始了游戏 */ - played: false; + played: boolean; /** * 游戏是否结束 @@ -648,7 +648,7 @@ interface InitGameStatus { /** * 是否锁定了用户控制 */ - lockControl: false; + lockControl: boolean; /** * 勇士移动状态,每个数字干啥的自己去libs翻,这东西太复杂了,不过应该不会有人用这个东西吧( @@ -718,7 +718,9 @@ interface InitGameStatus { /** * 全局动画对象 */ - globalAnimateObjs: Block>>[]; + globalAnimateObjs: Block< + IdToNumber[AllIdsOf>] + >[]; /** * 楼层贴图 @@ -733,7 +735,7 @@ interface InitGameStatus { /** * 所有的自动元件动画 */ - autotileAnimateObjs: Block>[]; + autotileAnimateObjs: Block]>[]; /** * 全局动画状态,每经过一个全局动画时间便加一 @@ -769,7 +771,7 @@ interface InitGameStatus { * 数字转图块 */ number2block: { - [P in AllNumbers]: Block

; + [P in keyof NumberToId]: Block

; }; /** diff --git a/src/types/util.d.ts b/src/types/util.d.ts index e6d0611..8cbc981 100644 --- a/src/types/util.d.ts +++ b/src/types/util.d.ts @@ -843,7 +843,7 @@ type DeepRequired = { * 使一个对象的所有属性可写 */ type Writable = { - -readonly [P in keyof T]: P[T]; + -readonly [P in keyof T]: T[P]; }; /** @@ -889,4 +889,4 @@ type NonObjectOf = SelectType; */ type EndsWith = `${string}${T}`; -type KeyExcludesUnderline = Excluede; +type KeyExcludesUnderline = Exclude;