feat: Icon\winskin完成

This commit is contained in:
草莓 2024-12-25 17:56:59 +08:00 committed by unanmed
parent d61beada0b
commit dbe633290e
2 changed files with 234 additions and 9 deletions

View File

@ -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<EIconEvent> {
export class Icon extends RenderItem<EIconEvent> implements IAnimateFrame {
/** 图标id */
icon: AllNumbers = 0;
/** 帧数 */
@ -220,13 +229,69 @@ export class Icon extends RenderItem<EIconEvent> {
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<EIconEvent> {
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<EWinskinEvent> {
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<EWinskinEvent> {
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);
}

View File

@ -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;
}