Compare commits

..

4 Commits

Author SHA1 Message Date
c7b2e6dd30 refactor: Winskin.image 2025-01-12 14:16:52 +08:00
52c5126997 fix: warn code. 2025-01-12 13:10:52 +08:00
b2a391a212 fix: icon 2025-01-12 13:09:10 +08:00
ba1e7ea228 fix : graphic类别问题 2025-01-12 12:53:32 +08:00
7 changed files with 82 additions and 24 deletions

View File

@ -211,6 +211,7 @@ class TextureCache extends EventEmitter<TextureCacheEvent> {
// 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<TextureCacheEvent> {
}
// 自动元件
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<TextureCacheEvent> {
core.material.images[
cls as Exclude<Cls, 'tileset' | 'autotile'>
];
if (!image) return null;
const frame = core.getAnimateFrames(cls);
const cell = 32;
// @ts-ignore

View File

@ -69,6 +69,7 @@ Mota.require('var', 'loading').once('coreInit', () => {
</layer-group>
<Textbox id="main-textbox" {...mainTextboxProps}></Textbox>
<FloorChange id="floor-change" zIndex={50}></FloorChange>
<icon icon={13} animate></icon>
</container>
);
});

View File

@ -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':

View File

@ -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;
@ -217,12 +219,20 @@ export class Icon extends RenderItem<EIconEvent> implements IAnimateFrame {
/** 图标id */
icon: AllNumbers = 0;
/** 帧数 */
frame: number = 0;
frame?: number = 0;
/** 是否启用动画 */
animate: boolean = false;
animate?: boolean = false;
/** 图标的渲染信息 */
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<EIconEvent> 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);
@ -245,21 +256,11 @@ export class Icon extends RenderItem<EIconEvent> 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);
}
}
@ -269,14 +270,29 @@ export class Icon extends RenderItem<EIconEvent> 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);
delete this.pendingIcon;
});
}
this.pendingIcon = num;
}
}
private setIconRenderable(num: AllNumbers) {
const renderable = texture.getRenderable(num);
if (!renderable) {
//todo: logger.warn()
logger.warn(43, num.toString());
return;
} else {
this.icon = num;
renderable.animate = 0;
this.renderable = renderable;
this.frame = renderable.frame;
}
@ -290,6 +306,11 @@ export class Icon extends RenderItem<EIconEvent> implements IAnimateFrame {
this.update(this);
}
destroy(): void {
renderEmits.removeFramer(this);
super.destroy();
}
patchProp(
key: string,
prevValue: any,
@ -304,6 +325,8 @@ export class Icon extends RenderItem<EIconEvent> 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':
@ -323,6 +346,8 @@ export class Winskin extends RenderItem<EWinskinEvent> {
/** 边框宽度 */
borderSize: number = 32;
private pendingImage?: ImageIds;
constructor(
image: SizedCanvasImageSource,
type: RenderItemPosition = 'static'
@ -484,6 +509,29 @@ export class Winskin extends RenderItem<EWinskinEvent> {
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
@ -502,7 +550,8 @@ export class Winskin extends RenderItem<EWinskinEvent> {
): 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;

View File

@ -178,11 +178,11 @@ 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 {
image: SizedCanvasImageSource;
borderSize: number;
image: ImageIds;
borderSize?: number;
}

View File

@ -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."
}

View File

@ -13,12 +13,16 @@ class GameLoading extends EventEmitter<GameLoadEvent> {
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() {