mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-07-19 03:41:47 +08:00
Compare commits
6 Commits
5cd00534c0
...
e4a6a136ed
Author | SHA1 | Date | |
---|---|---|---|
e4a6a136ed | |||
a3115fff60 | |||
7b4f907bc2 | |||
fc1e9751eb | |||
d72334e80b | |||
86bc383d65 |
@ -2,7 +2,7 @@ import { KeyCode } from '@motajs/client-base';
|
|||||||
import { Hotkey, HotkeyData } from '@motajs/system-action';
|
import { Hotkey, HotkeyData } from '@motajs/system-action';
|
||||||
import { HeroMover, IMoveController } from '@user/data-state';
|
import { HeroMover, IMoveController } from '@user/data-state';
|
||||||
import { Ticker } from 'mutate-animate';
|
import { Ticker } from 'mutate-animate';
|
||||||
import { mainScope } from '@motajs/legacy-ui';
|
import { mainScope } from './hotkey';
|
||||||
|
|
||||||
type MoveKey = Record<Dir, HotkeyData>;
|
type MoveKey = Record<Dir, HotkeyData>;
|
||||||
type MoveKeyConfig = Record<Dir, string>;
|
type MoveKeyConfig = Record<Dir, string>;
|
||||||
|
191
packages-user/client-modules/src/render/components/list.tsx
Normal file
191
packages-user/client-modules/src/render/components/list.tsx
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
import { DefaultProps } from '@motajs/render-vue';
|
||||||
|
import Scroll from 'packages/legacy-ui/src/components/scroll.vue';
|
||||||
|
import { computed, defineComponent, ref, SlotsType, VNode } from 'vue';
|
||||||
|
import { Selection } from './misc';
|
||||||
|
import { ElementLocator } from '@motajs/render-core';
|
||||||
|
import { Font } from '@motajs/render-style';
|
||||||
|
import { SetupComponentOptions } from '@motajs/system-ui';
|
||||||
|
|
||||||
|
export interface ListProps extends DefaultProps {
|
||||||
|
/** 列表内容,第一项表示 id,第二项表示显示的内容 */
|
||||||
|
list: [string, string][];
|
||||||
|
/** 当前选中的项 */
|
||||||
|
selected: string;
|
||||||
|
/** 定位 */
|
||||||
|
loc: ElementLocator;
|
||||||
|
/** 每行的高度,默认 18 */
|
||||||
|
lineHeight?: number;
|
||||||
|
/** 字体 */
|
||||||
|
font?: Font;
|
||||||
|
/** 使用 winskin 作为光标 */
|
||||||
|
winskin?: ImageIds;
|
||||||
|
/** 使用指定样式作为光标背景 */
|
||||||
|
color?: CanvasStyle;
|
||||||
|
/** 使用指定样式作为光标边框 */
|
||||||
|
border?: CanvasStyle;
|
||||||
|
/** 选择图标的不透明度范围 */
|
||||||
|
alphaRange?: [number, number];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ListEmits = {
|
||||||
|
/**
|
||||||
|
* 当用户选中某一项时触发
|
||||||
|
* @param key 选中的项的 id
|
||||||
|
*/
|
||||||
|
update: (key: string) => void;
|
||||||
|
|
||||||
|
'update:selected': (value: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const listProps = {
|
||||||
|
props: [
|
||||||
|
'list',
|
||||||
|
'selected',
|
||||||
|
'loc',
|
||||||
|
'lineHeight',
|
||||||
|
'font',
|
||||||
|
'winskin',
|
||||||
|
'color',
|
||||||
|
'border',
|
||||||
|
'alphaRange'
|
||||||
|
],
|
||||||
|
emits: ['update', 'update:selected']
|
||||||
|
} satisfies SetupComponentOptions<ListProps, ListEmits, keyof ListEmits>;
|
||||||
|
|
||||||
|
export const List = defineComponent<ListProps, ListEmits, keyof ListEmits>(
|
||||||
|
(props, { emit }) => {
|
||||||
|
const selected = ref(props.list[0][0]);
|
||||||
|
const lineHeight = computed(() => props.lineHeight ?? 18);
|
||||||
|
|
||||||
|
const select = (value: string) => {
|
||||||
|
selected.value = value;
|
||||||
|
emit('update', value);
|
||||||
|
emit('update:selected', value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => (
|
||||||
|
<Scroll>
|
||||||
|
{props.list.map((v, i) => {
|
||||||
|
const [key, value] = v;
|
||||||
|
const loc: ElementLocator = [
|
||||||
|
0,
|
||||||
|
lineHeight.value * i,
|
||||||
|
props.loc[2] ?? 200,
|
||||||
|
lineHeight.value
|
||||||
|
];
|
||||||
|
return (
|
||||||
|
<container onClick={() => select(key)}>
|
||||||
|
{selected.value === key && (
|
||||||
|
<Selection
|
||||||
|
loc={loc}
|
||||||
|
color={props.color}
|
||||||
|
border={props.border}
|
||||||
|
winskin={props.winskin}
|
||||||
|
alphaRange={props.alphaRange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<text text={value} font={props.font} />
|
||||||
|
</container>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Scroll>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
listProps
|
||||||
|
);
|
||||||
|
|
||||||
|
export interface ListPageProps extends ListProps {
|
||||||
|
/** 组件定位 */
|
||||||
|
loc: ElementLocator;
|
||||||
|
/** 列表所占比例 */
|
||||||
|
basis?: number;
|
||||||
|
/** 列表是否排列在右侧 */
|
||||||
|
right?: boolean;
|
||||||
|
/** 是否显示关闭按钮 */
|
||||||
|
close?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ListPageEmits = {
|
||||||
|
close: () => void;
|
||||||
|
} & ListEmits;
|
||||||
|
|
||||||
|
export type ListPageSlots = SlotsType<{
|
||||||
|
default: (key: string) => VNode | VNode[];
|
||||||
|
|
||||||
|
[x: string]: (key: string) => VNode | VNode[];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const listPageProps = {
|
||||||
|
props: [
|
||||||
|
'basis',
|
||||||
|
'right',
|
||||||
|
'list',
|
||||||
|
'selected',
|
||||||
|
'loc',
|
||||||
|
'lineHeight',
|
||||||
|
'font',
|
||||||
|
'winskin',
|
||||||
|
'color',
|
||||||
|
'border',
|
||||||
|
'alphaRange'
|
||||||
|
],
|
||||||
|
emits: ['update', 'update:selected', 'close']
|
||||||
|
} satisfies SetupComponentOptions<
|
||||||
|
ListPageProps,
|
||||||
|
ListPageEmits,
|
||||||
|
keyof ListPageEmits,
|
||||||
|
ListPageSlots
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const ListPage = defineComponent<
|
||||||
|
ListPageProps,
|
||||||
|
ListPageEmits,
|
||||||
|
keyof ListPageEmits,
|
||||||
|
ListPageSlots
|
||||||
|
>((props, { emit, slots }) => {
|
||||||
|
const selected = ref(props.selected);
|
||||||
|
|
||||||
|
const basis = computed(() => props.basis ?? 0.3);
|
||||||
|
const width = computed(() => props.loc[2] ?? 200);
|
||||||
|
const height = computed(() => props.loc[3] ?? 200);
|
||||||
|
const listLoc = computed<ElementLocator>(() => {
|
||||||
|
const listWidth = width.value * basis.value;
|
||||||
|
if (props.right) {
|
||||||
|
return [width.value - listWidth, 0, listWidth, height.value];
|
||||||
|
} else {
|
||||||
|
return [0, 0, listWidth, height.value];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const contentLoc = computed<ElementLocator>(() => {
|
||||||
|
const contentWidth = width.value * (1 - basis.value);
|
||||||
|
if (props.right) {
|
||||||
|
return [0, 0, contentWidth, height.value];
|
||||||
|
} else {
|
||||||
|
return [width.value - contentWidth, 0, contentWidth, height.value];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const update = (key: string) => {
|
||||||
|
emit('update', key);
|
||||||
|
emit('update:selected', key);
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => (
|
||||||
|
<container>
|
||||||
|
<List
|
||||||
|
{...props}
|
||||||
|
loc={listLoc.value}
|
||||||
|
list={props.list}
|
||||||
|
v-model:selected={selected.value}
|
||||||
|
onUpdate={update}
|
||||||
|
></List>
|
||||||
|
<container loc={contentLoc.value}>
|
||||||
|
{slots[selected.value]?.(selected.value) ??
|
||||||
|
slots.default?.(selected.value)}
|
||||||
|
</container>
|
||||||
|
{props.close && (
|
||||||
|
<text text="关闭" cursor="pointer" font={props.font}></text>
|
||||||
|
)}
|
||||||
|
</container>
|
||||||
|
);
|
||||||
|
}, listPageProps);
|
@ -1,14 +1,8 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import {
|
import { Font, onTick, MotaOffscreenCanvas2D } from '@motajs/render';
|
||||||
AutotileRenderable,
|
|
||||||
Font,
|
|
||||||
onTick,
|
|
||||||
RenderableData,
|
|
||||||
texture,
|
|
||||||
MotaOffscreenCanvas2D
|
|
||||||
} from '@motajs/render';
|
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
|
import { RenderableData, AutotileRenderable, texture } from '../elements';
|
||||||
|
|
||||||
/** 文字的安全填充,会填充在文字的上侧和下侧,防止削顶和削底 */
|
/** 文字的安全填充,会填充在文字的上侧和下侧,防止削顶和削底 */
|
||||||
const SAFE_PAD = 1;
|
const SAFE_PAD = 1;
|
||||||
@ -596,10 +590,8 @@ export class TextContentParser {
|
|||||||
this.status = { ...initStatus };
|
this.status = { ...initStatus };
|
||||||
|
|
||||||
this.testCanvas = new MotaOffscreenCanvas2D(false);
|
this.testCanvas = new MotaOffscreenCanvas2D(false);
|
||||||
this.testCanvas.withGameScale(false);
|
|
||||||
this.testCanvas.setHD(false);
|
this.testCanvas.setHD(false);
|
||||||
this.testCanvas.size(1, 1);
|
this.testCanvas.size(1, 1);
|
||||||
this.testCanvas.freeze();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { DefaultProps, ElementLocator, Font, texture } from '@motajs/render';
|
import { DefaultProps, ElementLocator, Font } from '@motajs/render';
|
||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { computed, defineComponent, onUnmounted, ref } from 'vue';
|
import { computed, defineComponent, onUnmounted, ref } from 'vue';
|
||||||
import { SetupComponentOptions } from './types';
|
import { SetupComponentOptions } from './types';
|
||||||
import { transitioned } from '../use';
|
import { transitioned } from '../use';
|
||||||
import { hyper } from 'mutate-animate';
|
import { hyper } from 'mutate-animate';
|
||||||
import { debounce } from 'lodash-es';
|
import { debounce } from 'lodash-es';
|
||||||
|
import { texture } from '../elements';
|
||||||
|
|
||||||
export interface TipProps extends DefaultProps {
|
export interface TipProps extends DefaultProps {
|
||||||
loc: ElementLocator;
|
loc: ElementLocator;
|
||||||
|
@ -305,7 +305,5 @@ export interface ICanvasCacheItem extends IBlockCacheable {
|
|||||||
export class CanvasCacheItem implements ICanvasCacheItem {
|
export class CanvasCacheItem implements ICanvasCacheItem {
|
||||||
constructor(public canvas: MotaOffscreenCanvas2D, public symbol: number) {}
|
constructor(public canvas: MotaOffscreenCanvas2D, public symbol: number) {}
|
||||||
|
|
||||||
destroy(): void {
|
destroy(): void {}
|
||||||
this.canvas.delete();
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { MotaOffscreenCanvas2D } from '@motajs/render-core';
|
import { MotaOffscreenCanvas2D } from '@motajs/render-core';
|
||||||
import { SizedCanvasImageSource } from './types';
|
import { SizedCanvasImageSource } from '@motajs/render-elements';
|
||||||
|
|
||||||
// 经过测试(https://www.measurethat.net/Benchmarks/Show/30741/1/drawimage-img-vs-canvas-vs-bitmap-cropping-fix-loading)
|
// 经过测试(https://www.measurethat.net/Benchmarks/Show/30741/1/drawimage-img-vs-canvas-vs-bitmap-cropping-fix-loading)
|
||||||
// 得出结论,ImageBitmap和Canvas的绘制性能不如Image,于是直接画Image就行,所以缓存基本上就是存Image
|
// 得出结论,ImageBitmap和Canvas的绘制性能不如Image,于是直接画Image就行,所以缓存基本上就是存Image
|
||||||
@ -464,11 +464,9 @@ function splitAutotiles(map: IdToNumber): AutotileCaches {
|
|||||||
const master = new MotaOffscreenCanvas2D();
|
const master = new MotaOffscreenCanvas2D();
|
||||||
master.setHD(false);
|
master.setHD(false);
|
||||||
master.setAntiAliasing(false);
|
master.setAntiAliasing(false);
|
||||||
master.withGameScale(false);
|
|
||||||
master.size(32, 32);
|
master.size(32, 32);
|
||||||
master.ctx.drawImage(img, 0, 0, 32, 32, 0, 0, 32, 32);
|
master.ctx.drawImage(img, 0, 0, 32, 32, 0, 0, 32, 32);
|
||||||
masterMap[auto] = master.canvas.toDataURL('image/png');
|
masterMap[auto] = master.canvas.toDataURL('image/png');
|
||||||
master.delete();
|
|
||||||
|
|
||||||
// 自动图块的绘制信息
|
// 自动图块的绘制信息
|
||||||
for (let i = 0; i <= 0b11111111; i++) {
|
for (let i = 0; i <= 0b11111111; i++) {
|
||||||
@ -491,9 +489,7 @@ function splitAutotiles(map: IdToNumber): AutotileCaches {
|
|||||||
const canvas = new MotaOffscreenCanvas2D();
|
const canvas = new MotaOffscreenCanvas2D();
|
||||||
canvas.setHD(false);
|
canvas.setHD(false);
|
||||||
canvas.setAntiAliasing(false);
|
canvas.setAntiAliasing(false);
|
||||||
canvas.withGameScale(false);
|
|
||||||
canvas.size(32 * frame, 32);
|
canvas.size(32 * frame, 32);
|
||||||
canvas.freeze();
|
|
||||||
const ctx = canvas.ctx;
|
const ctx = canvas.ctx;
|
||||||
for (let i = 0; i < frame; i++) {
|
for (let i = 0; i < frame; i++) {
|
||||||
const dx = 32 * i;
|
const dx = 32 * i;
|
||||||
@ -518,7 +514,6 @@ function splitAutotiles(map: IdToNumber): AutotileCaches {
|
|||||||
const judge = new MotaOffscreenCanvas2D();
|
const judge = new MotaOffscreenCanvas2D();
|
||||||
judge.setHD(false);
|
judge.setHD(false);
|
||||||
judge.setAntiAliasing(false);
|
judge.setAntiAliasing(false);
|
||||||
judge.withGameScale(false);
|
|
||||||
judge.size(32, 32);
|
judge.size(32, 32);
|
||||||
// 进行父子关系判断
|
// 进行父子关系判断
|
||||||
for (const [key, img] of Object.entries(core.material.images.autotile)) {
|
for (const [key, img] of Object.entries(core.material.images.autotile)) {
|
||||||
@ -538,7 +533,6 @@ function splitAutotiles(map: IdToNumber): AutotileCaches {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
judge.delete();
|
|
||||||
|
|
||||||
return cache as AutotileCaches;
|
return cache as AutotileCaches;
|
||||||
}
|
}
|
@ -8,19 +8,17 @@ import {
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
import {
|
import { tagMap } from '@motajs/render';
|
||||||
BlockCacher,
|
|
||||||
CanvasCacheItem,
|
|
||||||
ICanvasCacheItem,
|
|
||||||
calNeedRenderOf,
|
|
||||||
ILayerGroupRenderExtends,
|
|
||||||
Layer,
|
|
||||||
LayerGroup,
|
|
||||||
LayerGroupFloorBinder,
|
|
||||||
tagMap
|
|
||||||
} from '@motajs/render';
|
|
||||||
import { IDamageEnemy, IEnemyCollection, MapDamage } from '@motajs/types';
|
import { IDamageEnemy, IEnemyCollection, MapDamage } from '@motajs/types';
|
||||||
import { UserEnemyInfo } from '@user/data-state';
|
import { UserEnemyInfo } from '@user/data-state';
|
||||||
|
import { BlockCacher, ICanvasCacheItem, CanvasCacheItem } from './block';
|
||||||
|
import {
|
||||||
|
ILayerGroupRenderExtends,
|
||||||
|
LayerGroupFloorBinder,
|
||||||
|
LayerGroup,
|
||||||
|
Layer,
|
||||||
|
calNeedRenderOf
|
||||||
|
} from './layer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据伤害大小获取颜色
|
* 根据伤害大小获取颜色
|
||||||
@ -517,7 +515,6 @@ export class Damage extends RenderItem<EDamageEvent> {
|
|||||||
temp.clear();
|
temp.clear();
|
||||||
temp.setHD(true);
|
temp.setHD(true);
|
||||||
temp.setAntiAliasing(true);
|
temp.setAntiAliasing(true);
|
||||||
temp.withGameScale(true);
|
|
||||||
temp.size(size, size);
|
temp.size(size, size);
|
||||||
const { ctx: ct } = temp;
|
const { ctx: ct } = temp;
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
import { RenderAdapter } from '@motajs/render-core';
|
import { RenderAdapter } from '@motajs/render-core';
|
||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { ILayerRenderExtends, Layer, LayerMovingRenderable } from './layer';
|
import { ILayerRenderExtends, Layer, LayerMovingRenderable } from './layer';
|
||||||
import { SizedCanvasImageSource } from './types';
|
import { SizedCanvasImageSource } from '@motajs/render-elements';
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
import { texture } from './cache';
|
import { texture } from './cache';
|
||||||
import { TimingFn } from 'mutate-animate';
|
import { TimingFn } from 'mutate-animate';
|
78
packages-user/client-modules/src/render/elements/index.ts
Normal file
78
packages-user/client-modules/src/render/elements/index.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { standardElementNoCache, tagMap } from '@motajs/render-vue';
|
||||||
|
import { createCache } from './cache';
|
||||||
|
import { createFrame } from './frame';
|
||||||
|
import { createLayer, Layer, LayerGroup } from './layer';
|
||||||
|
import { createViewport } from './viewport';
|
||||||
|
import { Icon, Winskin } from './misc';
|
||||||
|
import { Animate } from './animate';
|
||||||
|
|
||||||
|
export function createElements() {
|
||||||
|
createCache();
|
||||||
|
createFrame();
|
||||||
|
createLayer();
|
||||||
|
createViewport();
|
||||||
|
|
||||||
|
// ----- 注册标签
|
||||||
|
|
||||||
|
tagMap.register('winskin', (_0, _1, props) => {
|
||||||
|
if (!props)
|
||||||
|
return new Winskin(core.material.images.images['winskin.png']);
|
||||||
|
else {
|
||||||
|
const {
|
||||||
|
image = core.material.images.images['winskin.png'],
|
||||||
|
type = 'static'
|
||||||
|
} = props;
|
||||||
|
return new Winskin(image, type);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tagMap.register('layer', (_0, _1, props) => {
|
||||||
|
if (!props) return new Layer();
|
||||||
|
else {
|
||||||
|
const { ex } = props;
|
||||||
|
const l = new Layer();
|
||||||
|
|
||||||
|
if (ex) {
|
||||||
|
(ex as any[]).forEach(v => {
|
||||||
|
l.extends(v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tagMap.register('layer-group', (_0, _1, props) => {
|
||||||
|
if (!props) return new LayerGroup();
|
||||||
|
else {
|
||||||
|
const { ex, layers } = props;
|
||||||
|
const l = new LayerGroup();
|
||||||
|
|
||||||
|
if (ex) {
|
||||||
|
(ex as any[]).forEach(v => {
|
||||||
|
l.extends(v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (layers) {
|
||||||
|
(layers as any[]).forEach(v => {
|
||||||
|
l.addLayer(v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tagMap.register('animation', (_0, _1, _props) => {
|
||||||
|
return new Animate();
|
||||||
|
});
|
||||||
|
tagMap.register('icon', standardElementNoCache(Icon));
|
||||||
|
}
|
||||||
|
|
||||||
|
export * from './animate';
|
||||||
|
export * from './block';
|
||||||
|
export * from './cache';
|
||||||
|
export * from './camera';
|
||||||
|
export * from './frame';
|
||||||
|
export * from './hero';
|
||||||
|
export * from './layer';
|
||||||
|
export * from './misc';
|
||||||
|
export * from './viewport';
|
||||||
|
export * from './utils';
|
@ -1,13 +1,9 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { mainSetting } from '@motajs/legacy-ui';
|
import { mainSetting } from '@motajs/legacy-ui';
|
||||||
import {
|
|
||||||
LayerGroupFloorBinder,
|
|
||||||
ILayerGroupRenderExtends,
|
|
||||||
LayerGroup
|
|
||||||
} from '@motajs/render';
|
|
||||||
import { hook } from '@user/data-base';
|
import { hook } from '@user/data-base';
|
||||||
import { ItemState } from '@user/data-state';
|
import { ItemState } from '@user/data-state';
|
||||||
import { Damage, DamageRenderable, FloorDamageExtends } from './damage';
|
import { Damage, DamageRenderable, FloorDamageExtends } from './damage';
|
||||||
|
import { ILayerGroupRenderExtends, LayerGroup, LayerGroupFloorBinder } from '.';
|
||||||
|
|
||||||
interface ItemDetailData {
|
interface ItemDetailData {
|
||||||
x: number;
|
x: number;
|
||||||
@ -22,7 +18,7 @@ interface ItemData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createItemDetail() {
|
export function createItemDetail() {
|
||||||
hook.on('setBlock', (x, y, floorId, block) => {
|
hook.on('setBlock', (x, y, _floorId, block) => {
|
||||||
FloorItemDetail.listened.forEach(v => {
|
FloorItemDetail.listened.forEach(v => {
|
||||||
v.setBlock(block, x, y);
|
v.setBlock(block, x, y);
|
||||||
});
|
});
|
||||||
@ -261,7 +257,7 @@ export class FloorItemDetail implements ILayerGroupRenderExtends {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(group: LayerGroup): void {
|
onDestroy(_group: LayerGroup): void {
|
||||||
this.sprite.off('beforeDamageRender', this.onBeforeDamageRender);
|
this.sprite.off('beforeDamageRender', this.onBeforeDamageRender);
|
||||||
this.sprite.off('setMapSize', this.onUpdateMapSize);
|
this.sprite.off('setMapSize', this.onUpdateMapSize);
|
||||||
FloorItemDetail.listened.delete(this);
|
FloorItemDetail.listened.delete(this);
|
@ -629,15 +629,12 @@ export class Layer extends Container<ELayerEvent> {
|
|||||||
|
|
||||||
this.staticMap.setHD(false);
|
this.staticMap.setHD(false);
|
||||||
// this.staticMap.setAntiAliasing(false);
|
// this.staticMap.setAntiAliasing(false);
|
||||||
this.staticMap.withGameScale(false);
|
|
||||||
this.staticMap.size(core._PX_, core._PY_);
|
this.staticMap.size(core._PX_, core._PY_);
|
||||||
this.movingMap.setHD(false);
|
this.movingMap.setHD(false);
|
||||||
// this.movingMap.setAntiAliasing(false);
|
// this.movingMap.setAntiAliasing(false);
|
||||||
this.movingMap.withGameScale(false);
|
|
||||||
this.movingMap.size(core._PX_, core._PY_);
|
this.movingMap.size(core._PX_, core._PY_);
|
||||||
this.backMap.setHD(false);
|
this.backMap.setHD(false);
|
||||||
// this.backMap.setAntiAliasing(false);
|
// this.backMap.setAntiAliasing(false);
|
||||||
this.backMap.withGameScale(false);
|
|
||||||
this.backMap.size(core._PX_, core._PY_);
|
this.backMap.size(core._PX_, core._PY_);
|
||||||
this.main.setAntiAliasing(false);
|
this.main.setAntiAliasing(false);
|
||||||
this.main.setHD(false);
|
this.main.setHD(false);
|
||||||
@ -777,7 +774,6 @@ export class Layer extends Container<ELayerEvent> {
|
|||||||
const num = this.background;
|
const num = this.background;
|
||||||
|
|
||||||
const data = texture.getRenderable(num);
|
const data = texture.getRenderable(num);
|
||||||
this.backImage.forEach(v => v.delete());
|
|
||||||
this.backImage = [];
|
this.backImage = [];
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
@ -785,7 +781,6 @@ export class Layer extends Container<ELayerEvent> {
|
|||||||
const temp = this.requireCanvas();
|
const temp = this.requireCanvas();
|
||||||
temp.setHD(false);
|
temp.setHD(false);
|
||||||
temp.setAntiAliasing(false);
|
temp.setAntiAliasing(false);
|
||||||
temp.withGameScale(false);
|
|
||||||
for (let i = 0; i < frame; i++) {
|
for (let i = 0; i < frame; i++) {
|
||||||
const canvas = this.requireCanvas();
|
const canvas = this.requireCanvas();
|
||||||
const ctx = canvas.ctx;
|
const ctx = canvas.ctx;
|
||||||
@ -793,7 +788,6 @@ export class Layer extends Container<ELayerEvent> {
|
|||||||
const [sx, sy, w, h] = data.render[i];
|
const [sx, sy, w, h] = data.render[i];
|
||||||
canvas.setHD(false);
|
canvas.setHD(false);
|
||||||
canvas.setAntiAliasing(false);
|
canvas.setAntiAliasing(false);
|
||||||
canvas.withGameScale(false);
|
|
||||||
canvas.size(core._PX_, core._PY_);
|
canvas.size(core._PX_, core._PY_);
|
||||||
temp.size(w, h);
|
temp.size(w, h);
|
||||||
|
|
||||||
@ -806,7 +800,6 @@ export class Layer extends Container<ELayerEvent> {
|
|||||||
|
|
||||||
this.backImage.push(canvas);
|
this.backImage.push(canvas);
|
||||||
}
|
}
|
||||||
temp.delete();
|
|
||||||
|
|
||||||
for (const ex of this.extend.values()) {
|
for (const ex of this.extend.values()) {
|
||||||
ex.onBackgroundGenerated?.(this, this.backImage);
|
ex.onBackgroundGenerated?.(this, this.backImage);
|
||||||
@ -1208,7 +1201,6 @@ export class Layer extends Container<ELayerEvent> {
|
|||||||
const temp = this.requireCanvas();
|
const temp = this.requireCanvas();
|
||||||
temp.setAntiAliasing(false);
|
temp.setAntiAliasing(false);
|
||||||
temp.setHD(false);
|
temp.setHD(false);
|
||||||
temp.withGameScale(false);
|
|
||||||
temp.size(core._PX_, core._PY_);
|
temp.size(core._PX_, core._PY_);
|
||||||
|
|
||||||
// 先画到临时画布,用于缓存
|
// 先画到临时画布,用于缓存
|
||||||
@ -1512,10 +1504,6 @@ export class Layer extends Container<ELayerEvent> {
|
|||||||
ex.onDestroy?.(this);
|
ex.onDestroy?.(this);
|
||||||
}
|
}
|
||||||
super.destroy();
|
super.destroy();
|
||||||
this.staticMap.delete();
|
|
||||||
this.movingMap.delete();
|
|
||||||
this.backMap.delete();
|
|
||||||
this.backImage.forEach(v => v.delete());
|
|
||||||
this.block.destroy();
|
this.block.destroy();
|
||||||
this.main.destroy();
|
this.main.destroy();
|
||||||
layerAdapter.remove(this);
|
layerAdapter.remove(this);
|
329
packages-user/client-modules/src/render/elements/misc.ts
Normal file
329
packages-user/client-modules/src/render/elements/misc.ts
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
import { logger } from '@motajs/common';
|
||||||
|
import {
|
||||||
|
ERenderItemEvent,
|
||||||
|
RenderItem,
|
||||||
|
RenderItemPosition,
|
||||||
|
MotaOffscreenCanvas2D,
|
||||||
|
Transform
|
||||||
|
} from '@motajs/render-core';
|
||||||
|
import { SizedCanvasImageSource } from '@motajs/render-elements';
|
||||||
|
import { isNil } from 'lodash-es';
|
||||||
|
import { RenderableData, AutotileRenderable, texture } from './cache';
|
||||||
|
import { IAnimateFrame, renderEmits } from './frame';
|
||||||
|
|
||||||
|
export interface EIconEvent extends ERenderItemEvent {}
|
||||||
|
|
||||||
|
export class Icon extends RenderItem<EIconEvent> implements IAnimateFrame {
|
||||||
|
/** 图标id */
|
||||||
|
icon: AllNumbers = 0;
|
||||||
|
/** 帧数 */
|
||||||
|
frame: number = 0;
|
||||||
|
/** 是否启用动画 */
|
||||||
|
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
|
||||||
|
): void {
|
||||||
|
const ctx = canvas.ctx;
|
||||||
|
const renderable = this.renderable;
|
||||||
|
if (!renderable) return;
|
||||||
|
const [x, y, w, h] = renderable.render[0];
|
||||||
|
const cw = this.width;
|
||||||
|
const ch = this.height;
|
||||||
|
const frame = this.animate
|
||||||
|
? RenderItem.animatedFrame % renderable.frame
|
||||||
|
: this.frame;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置图标
|
||||||
|
* @param id 图标id
|
||||||
|
*/
|
||||||
|
setIcon(id: AllIds | AllNumbers) {
|
||||||
|
if (id === 0) {
|
||||||
|
this.renderable = void 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const num = typeof id === 'number' ? id : texture.idNumberMap[id];
|
||||||
|
|
||||||
|
const { loading } = Mota.require('@user/data-base');
|
||||||
|
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) {
|
||||||
|
logger.warn(43, num.toString());
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
this.icon = num;
|
||||||
|
this.renderable = renderable;
|
||||||
|
this.frame = renderable.frame;
|
||||||
|
}
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新动画帧
|
||||||
|
*/
|
||||||
|
updateFrameAnimate(): void {
|
||||||
|
if (this.animate) this.update(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(): void {
|
||||||
|
renderEmits.removeFramer(this);
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected handleProps(
|
||||||
|
key: string,
|
||||||
|
_prevValue: any,
|
||||||
|
nextValue: any
|
||||||
|
): boolean {
|
||||||
|
switch (key) {
|
||||||
|
case 'icon':
|
||||||
|
this.setIcon(nextValue);
|
||||||
|
return true;
|
||||||
|
case 'animate':
|
||||||
|
if (!this.assertType(nextValue, 'boolean', key)) return false;
|
||||||
|
this.animate = nextValue;
|
||||||
|
if (nextValue) renderEmits.addFramer(this);
|
||||||
|
else renderEmits.removeFramer(this);
|
||||||
|
this.update();
|
||||||
|
return true;
|
||||||
|
case 'frame':
|
||||||
|
if (!this.assertType(nextValue, 'number', key)) return false;
|
||||||
|
this.frame = nextValue;
|
||||||
|
this.update();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WinskinPatterns {
|
||||||
|
top: CanvasPattern;
|
||||||
|
left: CanvasPattern;
|
||||||
|
bottom: CanvasPattern;
|
||||||
|
right: CanvasPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EWinskinEvent extends ERenderItemEvent {}
|
||||||
|
|
||||||
|
export class Winskin extends RenderItem<EWinskinEvent> {
|
||||||
|
image: SizedCanvasImageSource;
|
||||||
|
/** 边框宽度,32表示原始宽度 */
|
||||||
|
borderSize: number = 32;
|
||||||
|
/** 图片名称 */
|
||||||
|
imageName?: string;
|
||||||
|
|
||||||
|
private pendingImage?: ImageIds;
|
||||||
|
private patternCache?: WinskinPatterns;
|
||||||
|
private patternTransform: DOMMatrix;
|
||||||
|
|
||||||
|
private static patternMap: Map<string, WinskinPatterns> = new Map();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
image: SizedCanvasImageSource,
|
||||||
|
type: RenderItemPosition = 'static'
|
||||||
|
) {
|
||||||
|
super(type, false, false);
|
||||||
|
this.image = image;
|
||||||
|
this.setAntiAliasing(false);
|
||||||
|
|
||||||
|
if (window.DOMMatrix) {
|
||||||
|
this.patternTransform = new DOMMatrix();
|
||||||
|
} else if (window.WebKitCSSMatrix) {
|
||||||
|
this.patternTransform = new WebKitCSSMatrix();
|
||||||
|
} else {
|
||||||
|
this.patternTransform = new SVGMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generatePattern() {
|
||||||
|
const pattern = this.requireCanvas();
|
||||||
|
const img = this.image;
|
||||||
|
pattern.size(32, 16);
|
||||||
|
pattern.setHD(false);
|
||||||
|
pattern.setAntiAliasing(false);
|
||||||
|
const ctx = pattern.ctx;
|
||||||
|
ctx.drawImage(img, 144, 0, 32, 16, 0, 0, 32, 16);
|
||||||
|
const topPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
||||||
|
ctx.clearRect(0, 0, 32, 16);
|
||||||
|
ctx.drawImage(img, 144, 48, 32, 16, 0, 0, 32, 16);
|
||||||
|
const bottomPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
||||||
|
ctx.clearRect(0, 0, 32, 16);
|
||||||
|
pattern.size(16, 32);
|
||||||
|
ctx.drawImage(img, 128, 16, 16, 32, 0, 0, 16, 32);
|
||||||
|
const leftPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
||||||
|
ctx.clearRect(0, 0, 16, 32);
|
||||||
|
ctx.drawImage(img, 176, 16, 16, 32, 0, 0, 16, 32);
|
||||||
|
const rightPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
||||||
|
if (!topPattern || !bottomPattern || !leftPattern || !rightPattern) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const winskinPattern: WinskinPatterns = {
|
||||||
|
top: topPattern,
|
||||||
|
bottom: bottomPattern,
|
||||||
|
left: leftPattern,
|
||||||
|
right: rightPattern
|
||||||
|
};
|
||||||
|
if (this.imageName) {
|
||||||
|
Winskin.patternMap.set(this.imageName, winskinPattern);
|
||||||
|
}
|
||||||
|
this.patternCache = winskinPattern;
|
||||||
|
return winskinPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getPattern() {
|
||||||
|
if (!this.imageName) {
|
||||||
|
if (this.patternCache) return this.patternCache;
|
||||||
|
return this.generatePattern();
|
||||||
|
} else {
|
||||||
|
const pattern = Winskin.patternMap.get(this.imageName);
|
||||||
|
if (pattern) return pattern;
|
||||||
|
return this.generatePattern();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(
|
||||||
|
canvas: MotaOffscreenCanvas2D,
|
||||||
|
_transform: Transform
|
||||||
|
): void {
|
||||||
|
const ctx = canvas.ctx;
|
||||||
|
const img = this.image;
|
||||||
|
const w = this.width;
|
||||||
|
const h = this.height;
|
||||||
|
const pad = this.borderSize / 2;
|
||||||
|
// 背景
|
||||||
|
ctx.drawImage(img, 0, 0, 128, 128, 2, 2, w - 4, h - 4);
|
||||||
|
const pattern = this.getPattern();
|
||||||
|
if (!pattern) return;
|
||||||
|
const { top, left, right, bottom } = pattern;
|
||||||
|
top.setTransform(this.patternTransform);
|
||||||
|
left.setTransform(this.patternTransform);
|
||||||
|
right.setTransform(this.patternTransform);
|
||||||
|
bottom.setTransform(this.patternTransform);
|
||||||
|
// 上下左右边框
|
||||||
|
ctx.save();
|
||||||
|
ctx.fillStyle = top;
|
||||||
|
ctx.translate(pad, 0);
|
||||||
|
ctx.fillRect(0, 0, w - pad * 2, pad);
|
||||||
|
ctx.fillStyle = bottom;
|
||||||
|
ctx.translate(0, h - pad);
|
||||||
|
ctx.fillRect(0, 0, w - pad * 2, pad);
|
||||||
|
ctx.fillStyle = left;
|
||||||
|
ctx.translate(-pad, pad * 2 - h);
|
||||||
|
ctx.fillRect(0, 0, pad, h - pad * 2);
|
||||||
|
ctx.fillStyle = right;
|
||||||
|
ctx.translate(w - pad, 0);
|
||||||
|
ctx.fillRect(0, 0, pad, h - pad * 2);
|
||||||
|
ctx.restore();
|
||||||
|
// 四个角的边框
|
||||||
|
ctx.drawImage(img, 128, 0, 16, 16, 0, 0, pad, pad);
|
||||||
|
ctx.drawImage(img, 176, 0, 16, 16, w - pad, 0, pad, pad);
|
||||||
|
ctx.drawImage(img, 128, 48, 16, 16, 0, h - pad, pad, pad);
|
||||||
|
ctx.drawImage(img, 176, 48, 16, 16, w - pad, h - pad, pad, pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置winskin图片
|
||||||
|
* @param image winskin图片
|
||||||
|
*/
|
||||||
|
setImage(image: SizedCanvasImageSource) {
|
||||||
|
this.image = image;
|
||||||
|
this.patternCache = void 0;
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过图片名称设置winskin
|
||||||
|
* @param name 图片名称
|
||||||
|
*/
|
||||||
|
setImageByName(name: ImageIds) {
|
||||||
|
const { loading } = Mota.require('@user/data-base');
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
this.imageName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置边框大小
|
||||||
|
* @param size 边框大小
|
||||||
|
*/
|
||||||
|
setBorderSize(size: number) {
|
||||||
|
this.borderSize = size;
|
||||||
|
this.patternTransform.a = size / 32;
|
||||||
|
this.patternTransform.d = size / 32;
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected handleProps(
|
||||||
|
key: string,
|
||||||
|
_prevValue: any,
|
||||||
|
nextValue: any
|
||||||
|
): boolean {
|
||||||
|
switch (key) {
|
||||||
|
case 'image':
|
||||||
|
if (!this.assertType(nextValue, 'string', key)) return false;
|
||||||
|
this.setImageByName(nextValue);
|
||||||
|
return true;
|
||||||
|
case 'borderSize':
|
||||||
|
if (!this.assertType(nextValue, 'number', key)) return false;
|
||||||
|
this.setBorderSize(nextValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
61
packages-user/client-modules/src/render/elements/props.ts
Normal file
61
packages-user/client-modules/src/render/elements/props.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { BaseProps, TagDefine } from '@motajs/render-vue';
|
||||||
|
import { Transform } from '@motajs/render-core';
|
||||||
|
import {
|
||||||
|
ILayerGroupRenderExtends,
|
||||||
|
FloorLayer,
|
||||||
|
ILayerRenderExtends,
|
||||||
|
ELayerEvent,
|
||||||
|
ELayerGroupEvent
|
||||||
|
} from './layer';
|
||||||
|
import { EAnimateEvent } from './animate';
|
||||||
|
import { EIconEvent, EWinskinEvent } from './misc';
|
||||||
|
|
||||||
|
export interface AnimateProps extends BaseProps {}
|
||||||
|
|
||||||
|
export interface IconProps extends BaseProps {
|
||||||
|
/** 图标 id 或数字 */
|
||||||
|
icon: AllNumbers | AllIds;
|
||||||
|
/** 显示图标的第几帧 */
|
||||||
|
frame?: number;
|
||||||
|
/** 是否开启动画,开启后 frame 参数无效 */
|
||||||
|
animate?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WinskinProps extends BaseProps {
|
||||||
|
/** winskin 的图片 id */
|
||||||
|
image: ImageIds;
|
||||||
|
/** 边框大小 */
|
||||||
|
borderSize?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LayerGroupProps extends BaseProps {
|
||||||
|
cellSize?: number;
|
||||||
|
blockSize?: number;
|
||||||
|
floorId?: FloorIds;
|
||||||
|
bindThisFloor?: boolean;
|
||||||
|
camera?: Transform;
|
||||||
|
ex?: readonly ILayerGroupRenderExtends[];
|
||||||
|
layers?: readonly FloorLayer[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LayerProps extends BaseProps {
|
||||||
|
layer?: FloorLayer;
|
||||||
|
mapWidth?: number;
|
||||||
|
mapHeight?: number;
|
||||||
|
cellSize?: number;
|
||||||
|
background?: AllNumbers;
|
||||||
|
floorImage?: FloorAnimate[];
|
||||||
|
ex?: readonly ILayerRenderExtends[];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'vue/jsx-runtime' {
|
||||||
|
namespace JSX {
|
||||||
|
export interface IntrinsicElements {
|
||||||
|
layer: TagDefine<LayerProps, ELayerEvent>;
|
||||||
|
'layer-group': TagDefine<LayerGroupProps, ELayerGroupEvent>;
|
||||||
|
animation: TagDefine<AnimateProps, EAnimateEvent>;
|
||||||
|
icon: TagDefine<IconProps, EIconEvent>;
|
||||||
|
winskin: TagDefine<WinskinProps, EWinskinEvent>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,16 @@
|
|||||||
import { MotaRenderer, createApp } from '@motajs/render';
|
import { createApp } from '@motajs/render';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { UIController } from '@motajs/system-ui';
|
import { UIController } from '@motajs/system-ui';
|
||||||
import { mainSceneUI } from './ui/main';
|
import { mainSceneUI } from './ui/main';
|
||||||
import { MAIN_HEIGHT, MAIN_WIDTH } from './shared';
|
import { MAIN_HEIGHT, MAIN_WIDTH } from './shared';
|
||||||
import { hook } from '@user/data-base';
|
import { hook } from '@user/data-base';
|
||||||
import { createItemDetail } from './itemDetail';
|
import { createItemDetail } from './elements/itemDetail';
|
||||||
import { createLoopMap } from './loopMap';
|
import { createLoopMap } from './loopMap';
|
||||||
import { createGameCanvas } from './legacy/gameCanvas';
|
import { createGameCanvas } from './legacy/gameCanvas';
|
||||||
|
import { createElements } from './elements';
|
||||||
|
import { mainRenderer } from './renderer';
|
||||||
|
|
||||||
export function createGameRenderer() {
|
export function createGameRenderer() {
|
||||||
const main = new MotaRenderer();
|
|
||||||
main.size(MAIN_WIDTH, MAIN_HEIGHT);
|
|
||||||
|
|
||||||
const App = defineComponent(_props => {
|
const App = defineComponent(_props => {
|
||||||
const ui = new UIController('root-ui');
|
const ui = new UIController('root-ui');
|
||||||
ui.open(mainSceneUI, {});
|
ui.open(mainSceneUI, {});
|
||||||
@ -23,26 +22,28 @@ export function createGameRenderer() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
main.hide();
|
mainRenderer.hide();
|
||||||
createApp(App).mount(main);
|
createApp(App).mount(mainRenderer);
|
||||||
|
|
||||||
hook.on('reset', () => {
|
hook.on('reset', () => {
|
||||||
main.show();
|
mainRenderer.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
hook.on('restart', () => {
|
hook.on('restart', () => {
|
||||||
main.hide();
|
mainRenderer.hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(main);
|
console.log(mainRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createRender() {
|
export function createRender() {
|
||||||
createGameCanvas();
|
createGameCanvas();
|
||||||
createItemDetail();
|
createItemDetail();
|
||||||
createLoopMap();
|
createLoopMap();
|
||||||
|
createElements();
|
||||||
}
|
}
|
||||||
|
|
||||||
export * from './components';
|
export * from './components';
|
||||||
export * from './ui';
|
export * from './ui';
|
||||||
export * from './use';
|
export * from './use';
|
||||||
|
export * from './elements';
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import {
|
|
||||||
LayerGroupFloorBinder,
|
|
||||||
ILayerGroupRenderExtends,
|
|
||||||
LayerGroup
|
|
||||||
} from '@motajs/render';
|
|
||||||
import { loading } from '@user/data-base';
|
import { loading } from '@user/data-base';
|
||||||
|
import {
|
||||||
|
ILayerGroupRenderExtends,
|
||||||
|
LayerGroup,
|
||||||
|
LayerGroupFloorBinder
|
||||||
|
} from '../elements';
|
||||||
|
|
||||||
const filterMap: [FloorIds[], string][] = [];
|
const filterMap: [FloorIds[], string][] = [];
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ export class LayerGroupFilter implements ILayerGroupRenderExtends {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(group: LayerGroup): void {
|
onDestroy(_group: LayerGroup): void {
|
||||||
this.binder?.off('floorChange', this.onFloorChange);
|
this.binder?.off('floorChange', this.onFloorChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { MotaOffscreenCanvas2D } from '@motajs/render';
|
import { MotaOffscreenCanvas2D } from '@motajs/render';
|
||||||
import { mainSetting } from '@motajs/legacy-ui';
|
import { mainSetting } from '@motajs/legacy-ui';
|
||||||
|
import { Sprite, Transform } from '@motajs/render';
|
||||||
|
import { gameListener, hook } from '@user/data-base';
|
||||||
import {
|
import {
|
||||||
LayerGroupFloorBinder,
|
|
||||||
ILayerGroupRenderExtends,
|
ILayerGroupRenderExtends,
|
||||||
LayerGroup,
|
LayerGroup,
|
||||||
Sprite,
|
LayerGroupFloorBinder
|
||||||
Transform
|
} from '../elements';
|
||||||
} from '@motajs/render';
|
|
||||||
import { gameListener, hook } from '@user/data-base';
|
|
||||||
|
|
||||||
export class LayerGroupHalo implements ILayerGroupRenderExtends {
|
export class LayerGroupHalo implements ILayerGroupRenderExtends {
|
||||||
id: string = 'halo';
|
id: string = 'halo';
|
||||||
@ -37,7 +36,7 @@ export class LayerGroupHalo implements ILayerGroupRenderExtends {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(group: LayerGroup): void {
|
onDestroy(_group: LayerGroup): void {
|
||||||
this.halo?.destroy();
|
this.halo?.destroy();
|
||||||
LayerGroupHalo.sprites.delete(this.halo);
|
LayerGroupHalo.sprites.delete(this.halo);
|
||||||
}
|
}
|
||||||
@ -67,7 +66,7 @@ class Halo extends Sprite {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
drawHalo(canvas: MotaOffscreenCanvas2D, transform: Transform) {
|
drawHalo(canvas: MotaOffscreenCanvas2D, _transform: Transform) {
|
||||||
if (!mainSetting.getValue('screen.halo', true)) return;
|
if (!mainSetting.getValue('screen.halo', true)) return;
|
||||||
const floorId = this.binder.getFloor();
|
const floorId = this.binder.getFloor();
|
||||||
if (!floorId) return;
|
if (!floorId) return;
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { MotaOffscreenCanvas2D } from '@motajs/render';
|
import { MotaOffscreenCanvas2D } from '@motajs/render';
|
||||||
import { mainSetting, MotaSettingItem } from '@motajs/legacy-ui';
|
import { mainSetting, MotaSettingItem } from '@motajs/legacy-ui';
|
||||||
|
import { Sprite } from '@motajs/render';
|
||||||
|
import { BluePalace } from '@user/data-state';
|
||||||
import {
|
import {
|
||||||
LayerGroupFloorBinder,
|
|
||||||
ILayerGroupRenderExtends,
|
ILayerGroupRenderExtends,
|
||||||
LayerGroup,
|
LayerGroup,
|
||||||
Sprite
|
LayerGroupFloorBinder
|
||||||
} from '@motajs/render';
|
} from '../elements';
|
||||||
import { BluePalace } from '@user/data-state';
|
|
||||||
|
|
||||||
/** 最大粒子数 */
|
/** 最大粒子数 */
|
||||||
const MAX_PARTICLES = 10;
|
const MAX_PARTICLES = 10;
|
||||||
@ -49,7 +49,7 @@ export class LayerGroupPortal implements ILayerGroupRenderExtends {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(group: LayerGroup): void {
|
onDestroy(_group: LayerGroup): void {
|
||||||
this.binder.off('floorChange', this.onFloorChange);
|
this.binder.off('floorChange', this.onFloorChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ export class Portal extends Sprite {
|
|||||||
|
|
||||||
this.setZIndex(35);
|
this.setZIndex(35);
|
||||||
|
|
||||||
this.setRenderFn((canvas, transform) => {
|
this.setRenderFn((canvas, _transform) => {
|
||||||
this.renderPortal(canvas);
|
this.renderPortal(canvas);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import {
|
import { Container, MotaRenderer } from '@motajs/render';
|
||||||
Container,
|
|
||||||
LayerGroupFloorBinder,
|
|
||||||
FloorLayer,
|
|
||||||
LayerGroup,
|
|
||||||
FloorViewport,
|
|
||||||
MotaRenderer
|
|
||||||
} from '@motajs/render';
|
|
||||||
import { hook } from '@user/data-base';
|
import { hook } from '@user/data-base';
|
||||||
import { MiscData } from '@user/data-state';
|
import { MiscData } from '@user/data-state';
|
||||||
import { FloorDamageExtends } from './damage';
|
import { FloorDamageExtends } from './elements/damage';
|
||||||
import { FloorItemDetail } from './itemDetail';
|
import { FloorItemDetail } from './elements/itemDetail';
|
||||||
|
import {
|
||||||
|
LayerGroup,
|
||||||
|
FloorLayer,
|
||||||
|
LayerGroupFloorBinder,
|
||||||
|
FloorViewport
|
||||||
|
} from './elements';
|
||||||
|
|
||||||
const loopMaps = MiscData.loopMaps;
|
const loopMaps = MiscData.loopMaps;
|
||||||
|
|
||||||
@ -19,7 +18,7 @@ let show: boolean = false;
|
|||||||
let delegation: number = -1;
|
let delegation: number = -1;
|
||||||
|
|
||||||
export function createLoopMap() {
|
export function createLoopMap() {
|
||||||
hook.on('changingFloor', (floorId, heroLoc) => {
|
hook.on('changingFloor', (floorId, _heroLoc) => {
|
||||||
enableLoopMapElement(floorId);
|
enableLoopMapElement(floorId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
8
packages-user/client-modules/src/render/renderer.ts
Normal file
8
packages-user/client-modules/src/render/renderer.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { MotaRenderer } from '@motajs/render-core';
|
||||||
|
import { MAIN_WIDTH, MAIN_HEIGHT } from './shared';
|
||||||
|
|
||||||
|
export const mainRenderer = new MotaRenderer({
|
||||||
|
canvas: '#render-main',
|
||||||
|
width: MAIN_WIDTH,
|
||||||
|
height: MAIN_HEIGHT
|
||||||
|
});
|
@ -1,15 +1,5 @@
|
|||||||
import { LayerShadowExtends } from '@motajs/legacy-ui';
|
import { LayerShadowExtends } from '@motajs/legacy-ui';
|
||||||
import {
|
import { Props, Font } from '@motajs/render';
|
||||||
ILayerGroupRenderExtends,
|
|
||||||
LayerGroupAnimate,
|
|
||||||
FloorViewport,
|
|
||||||
ILayerRenderExtends,
|
|
||||||
HeroRenderer,
|
|
||||||
LayerDoorAnimate,
|
|
||||||
Props,
|
|
||||||
LayerGroup,
|
|
||||||
Font
|
|
||||||
} from '@motajs/render';
|
|
||||||
import { WeatherController } from '../../weather';
|
import { WeatherController } from '../../weather';
|
||||||
import { defineComponent, onMounted, reactive, ref } from 'vue';
|
import { defineComponent, onMounted, reactive, ref } from 'vue';
|
||||||
import { Textbox, Tip } from '../components';
|
import { Textbox, Tip } from '../components';
|
||||||
@ -31,14 +21,23 @@ import { ReplayingStatus } from './toolbar';
|
|||||||
import { getHeroStatusOn, HeroSkill, NightSpecial } from '@user/data-state';
|
import { getHeroStatusOn, HeroSkill, NightSpecial } from '@user/data-state';
|
||||||
import { jumpIgnoreFloor } from '@user/legacy-plugin-data';
|
import { jumpIgnoreFloor } from '@user/legacy-plugin-data';
|
||||||
import { hook } from '@user/data-base';
|
import { hook } from '@user/data-base';
|
||||||
import { FloorDamageExtends } from '../damage';
|
import { FloorDamageExtends } from '../elements/damage';
|
||||||
import { FloorItemDetail } from '../itemDetail';
|
import { FloorItemDetail } from '../elements/itemDetail';
|
||||||
import { LayerGroupPortal } from '../legacy/portal';
|
import { LayerGroupPortal } from '../legacy/portal';
|
||||||
import { LayerGroupFilter } from '../legacy/gameCanvas';
|
import { LayerGroupFilter } from '../legacy/gameCanvas';
|
||||||
import { LayerGroupHalo } from '../legacy/halo';
|
import { LayerGroupHalo } from '../legacy/halo';
|
||||||
import { FloorChange } from '../legacy/fallback';
|
import { FloorChange } from '../legacy/fallback';
|
||||||
import { PopText } from '../legacy/pop';
|
import { PopText } from '../legacy/pop';
|
||||||
import { mainUIController } from './controller';
|
import { mainUIController } from './controller';
|
||||||
|
import {
|
||||||
|
ILayerGroupRenderExtends,
|
||||||
|
LayerGroupAnimate,
|
||||||
|
FloorViewport,
|
||||||
|
ILayerRenderExtends,
|
||||||
|
HeroRenderer,
|
||||||
|
LayerDoorAnimate,
|
||||||
|
LayerGroup
|
||||||
|
} from '../elements';
|
||||||
|
|
||||||
const MainScene = defineComponent(() => {
|
const MainScene = defineComponent(() => {
|
||||||
const layerGroupExtends: ILayerGroupRenderExtends[] = [
|
const layerGroupExtends: ILayerGroupRenderExtends[] = [
|
||||||
|
198
packages-user/client-modules/src/render/ui/statistics.tsx
Normal file
198
packages-user/client-modules/src/render/ui/statistics.tsx
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
import {
|
||||||
|
GameUI,
|
||||||
|
IUIMountable,
|
||||||
|
SetupComponentOptions,
|
||||||
|
UIComponentProps
|
||||||
|
} from '@motajs/system-ui';
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { ListPage } from '../components/list';
|
||||||
|
import { waitbox } from '../components';
|
||||||
|
import { DefaultProps } from '@motajs/render-vue';
|
||||||
|
import { ItemState } from '@user/data-state';
|
||||||
|
|
||||||
|
interface StatisticsDataOneFloor {
|
||||||
|
enemyCount: number;
|
||||||
|
potionCount: number;
|
||||||
|
gemCount: number;
|
||||||
|
potionValue: number;
|
||||||
|
atkValue: number;
|
||||||
|
defValue: number;
|
||||||
|
mdefValue: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StatisticsData {
|
||||||
|
total: StatisticsDataOneFloor;
|
||||||
|
floors: Map<FloorIds, StatisticsDataOneFloor>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StatisticsProps extends UIComponentProps, DefaultProps {
|
||||||
|
data: StatisticsData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const statisticsProps = {
|
||||||
|
props: ['data']
|
||||||
|
} satisfies SetupComponentOptions<StatisticsProps>;
|
||||||
|
|
||||||
|
export const Statistics = defineComponent<StatisticsProps>(props => {
|
||||||
|
const list: [string, string][] = [
|
||||||
|
['total', '总览'],
|
||||||
|
['floor', '楼层'],
|
||||||
|
['enemy', '怪物'],
|
||||||
|
['potion', '血瓶宝石']
|
||||||
|
];
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
props.controller.close(props.instance);
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => (
|
||||||
|
<ListPage
|
||||||
|
list={list}
|
||||||
|
selected="total"
|
||||||
|
loc={[180, 0, 480, 480]}
|
||||||
|
close
|
||||||
|
onClose={close}
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
total: () => <TotalStatistics data={props.data} />,
|
||||||
|
floor: () => <FloorStatistics data={props.data} />,
|
||||||
|
enemy: () => <EnemyStatistics data={props.data} />,
|
||||||
|
potion: () => <PotionStatistics data={props.data} />
|
||||||
|
}}
|
||||||
|
</ListPage>
|
||||||
|
);
|
||||||
|
}, statisticsProps);
|
||||||
|
|
||||||
|
interface StatisticsPanelProps extends DefaultProps {
|
||||||
|
data: StatisticsData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TotalStatistics = defineComponent<StatisticsPanelProps>(props => {
|
||||||
|
return () => <container></container>;
|
||||||
|
}, statisticsProps);
|
||||||
|
|
||||||
|
const FloorStatistics = defineComponent<StatisticsPanelProps>(props => {
|
||||||
|
return () => <container></container>;
|
||||||
|
}, statisticsProps);
|
||||||
|
|
||||||
|
const EnemyStatistics = defineComponent<StatisticsPanelProps>(props => {
|
||||||
|
return () => <container></container>;
|
||||||
|
}, statisticsProps);
|
||||||
|
|
||||||
|
const PotionStatistics = defineComponent<StatisticsPanelProps>(props => {
|
||||||
|
return () => <container></container>;
|
||||||
|
}, statisticsProps);
|
||||||
|
|
||||||
|
function calculateStatistics(): StatisticsData {
|
||||||
|
core.setFlag('__statistics__', true);
|
||||||
|
const hero = core.status.hero;
|
||||||
|
const diff: Record<string | symbol, number> = {};
|
||||||
|
const handler: ProxyHandler<HeroStatus> = {
|
||||||
|
set(_target, p, newValue) {
|
||||||
|
if (typeof newValue === 'number') {
|
||||||
|
diff[p] ??= 0;
|
||||||
|
diff[p] += newValue;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const proxy = new Proxy(hero, handler);
|
||||||
|
core.status.hero = proxy;
|
||||||
|
|
||||||
|
const floors = new Map<FloorIds, StatisticsDataOneFloor>();
|
||||||
|
core.floorIds.forEach(v => {
|
||||||
|
core.extractBlocks(v);
|
||||||
|
const statistics: StatisticsDataOneFloor = {
|
||||||
|
enemyCount: 0,
|
||||||
|
potionCount: 0,
|
||||||
|
gemCount: 0,
|
||||||
|
potionValue: 0,
|
||||||
|
atkValue: 0,
|
||||||
|
defValue: 0,
|
||||||
|
mdefValue: 0
|
||||||
|
};
|
||||||
|
core.status.maps[v].blocks.forEach(v => {
|
||||||
|
if (v.event.cls === 'enemys' || v.event.cls === 'enemy48') {
|
||||||
|
statistics.enemyCount++;
|
||||||
|
} else if (v.event.cls === 'items') {
|
||||||
|
const item = ItemState.items.get(
|
||||||
|
v.event.id as AllIdsOf<'items'>
|
||||||
|
);
|
||||||
|
if (!item) return;
|
||||||
|
if (item.cls === 'items') {
|
||||||
|
try {
|
||||||
|
item.itemEffectFn?.();
|
||||||
|
} catch {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
if (diff.hp > 0) {
|
||||||
|
statistics.potionCount++;
|
||||||
|
statistics.potionValue += diff.hp;
|
||||||
|
}
|
||||||
|
if (diff.atk > 0 || diff.def > 0 || diff.mdef > 0) {
|
||||||
|
statistics.gemCount++;
|
||||||
|
}
|
||||||
|
if (diff.atk > 0) {
|
||||||
|
statistics.atkValue += diff.atk;
|
||||||
|
}
|
||||||
|
if (diff.def > 0) {
|
||||||
|
statistics.defValue += diff.def;
|
||||||
|
}
|
||||||
|
if (diff.mdef > 0) {
|
||||||
|
statistics.mdefValue += diff.mdef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const key of Object.keys(diff)) {
|
||||||
|
diff[key] = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
floors.set(v, statistics);
|
||||||
|
});
|
||||||
|
|
||||||
|
core.status.hero = hero;
|
||||||
|
window.hero = hero;
|
||||||
|
window.flags = core.status.hero.flags;
|
||||||
|
core.removeFlag('__statistics__');
|
||||||
|
|
||||||
|
const total = floors.values().reduce((prev, curr) => {
|
||||||
|
prev.atkValue += curr.atkValue;
|
||||||
|
prev.defValue += curr.defValue;
|
||||||
|
prev.enemyCount += curr.enemyCount;
|
||||||
|
prev.gemCount += curr.gemCount;
|
||||||
|
prev.mdefValue += curr.mdefValue;
|
||||||
|
prev.potionCount += curr.potionCount;
|
||||||
|
prev.potionValue += curr.potionValue;
|
||||||
|
return prev;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
total,
|
||||||
|
floors
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开数据统计界面
|
||||||
|
* @param controller 要在哪个 UI 控制器上打开
|
||||||
|
*/
|
||||||
|
export async function openStatistics(controller: IUIMountable) {
|
||||||
|
const cal = Promise.resolve().then<StatisticsData>(() => {
|
||||||
|
return new Promise(res => {
|
||||||
|
const data = calculateStatistics();
|
||||||
|
res(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const data = await waitbox(
|
||||||
|
controller,
|
||||||
|
[240 + 180, void 0, void 0, 240, 0.5, 0.5],
|
||||||
|
240,
|
||||||
|
cal,
|
||||||
|
{
|
||||||
|
text: '正在统计...'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
controller.open(StatisticsUI, { data: data });
|
||||||
|
}
|
||||||
|
|
||||||
|
export const StatisticsUI = new GameUI('statistics', Statistics);
|
@ -1,7 +1,6 @@
|
|||||||
import { backDir, has } from '@user/data-utils';
|
import { backDir, has } from '@user/data-utils';
|
||||||
import { loading } from '@user/data-base';
|
import { loading } from '@user/data-base';
|
||||||
import type { LayerDoorAnimate } from '@motajs/render';
|
import { LayerDoorAnimate } from '@user/client-modules';
|
||||||
import { getSkillLevel } from './skillTree';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一些零散机制的数据
|
* 一些零散机制的数据
|
||||||
@ -87,7 +86,7 @@ export namespace BluePalace {
|
|||||||
|
|
||||||
const Adapter = Mota.require('@motajs/render').RenderAdapter;
|
const Adapter = Mota.require('@motajs/render').RenderAdapter;
|
||||||
const adapter = Adapter.get<LayerDoorAnimate>('door-animate');
|
const adapter = Adapter.get<LayerDoorAnimate>('door-animate');
|
||||||
const texture = Mota.require('@motajs/render').texture;
|
const texture = Mota.require('@user/client-modules').texture;
|
||||||
if (adapter) {
|
if (adapter) {
|
||||||
Promise.all(
|
Promise.all(
|
||||||
toConvert.map(v => {
|
toConvert.map(v => {
|
||||||
|
@ -59,7 +59,7 @@ function getRealStatus(
|
|||||||
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
name: keyof HeroStatus | 'all' | (keyof HeroStatus)[],
|
||||||
floorId: FloorIds = core.status.floorId
|
floorId: FloorIds = core.status.floorId
|
||||||
): any {
|
): any {
|
||||||
const { getSkillLevel } = Mota.require('@user/legacy-plugin-data');
|
const { getSkillLevel } = Mota.require('@user/data-state');
|
||||||
if (name instanceof Array) {
|
if (name instanceof Array) {
|
||||||
const res: any = {};
|
const res: any = {};
|
||||||
name.forEach(v => {
|
name.forEach(v => {
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
import { backDir, checkCanMoveExtended, toDir } from './utils';
|
import { backDir, checkCanMoveExtended, toDir } from './utils';
|
||||||
import { loading } from '@user/data-base';
|
import { loading } from '@user/data-base';
|
||||||
|
import type { RenderAdapter } from '@motajs/render';
|
||||||
import type {
|
import type {
|
||||||
RenderAdapter,
|
|
||||||
HeroRenderer,
|
|
||||||
FloorViewport,
|
|
||||||
FloorLayer,
|
FloorLayer,
|
||||||
|
FloorViewport,
|
||||||
|
HeroKeyMover,
|
||||||
|
HeroRenderer,
|
||||||
Layer,
|
Layer,
|
||||||
|
LayerFloorBinder,
|
||||||
LayerGroup,
|
LayerGroup,
|
||||||
LayerMovingRenderable,
|
LayerMovingRenderable
|
||||||
LayerFloorBinder
|
} from '@user/client-modules';
|
||||||
} from '@motajs/render';
|
|
||||||
import type { HeroKeyMover } from '@user/client-modules';
|
|
||||||
import { BluePalace, MiscData } from '../mechanism/misc';
|
import { BluePalace, MiscData } from '../mechanism/misc';
|
||||||
import { sleep } from '@motajs/common';
|
import { sleep } from '@motajs/common';
|
||||||
|
|
||||||
@ -318,7 +318,7 @@ export class BlockMover extends ObjectMoverBase {
|
|||||||
this.blockNum = blockNum;
|
this.blockNum = blockNum;
|
||||||
|
|
||||||
Mota.r(() => {
|
Mota.r(() => {
|
||||||
const { Layer } = Mota.require('@motajs/render');
|
const { Layer } = Mota.require('@user/client-modules');
|
||||||
const r = Layer.getMovingRenderable(blockNum, this.x, this.y);
|
const r = Layer.getMovingRenderable(blockNum, this.x, this.y);
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
|
@ -50,7 +50,6 @@ export function create() {
|
|||||||
|
|
||||||
async function createModule() {
|
async function createModule() {
|
||||||
LegacyUI.create();
|
LegacyUI.create();
|
||||||
RenderElements.create();
|
|
||||||
ClientModules.create();
|
ClientModules.create();
|
||||||
|
|
||||||
await import('ant-design-vue/dist/antd.dark.css');
|
await import('ant-design-vue/dist/antd.dark.css');
|
||||||
|
@ -2,7 +2,6 @@ import { IStateDamageable } from '@user/data-state';
|
|||||||
import { BarrageBoss, BossSprite, Hitbox } from './barrage';
|
import { BarrageBoss, BossSprite, Hitbox } from './barrage';
|
||||||
import {
|
import {
|
||||||
Container,
|
Container,
|
||||||
LayerGroup,
|
|
||||||
MotaRenderer,
|
MotaRenderer,
|
||||||
RenderItem,
|
RenderItem,
|
||||||
Shader,
|
Shader,
|
||||||
@ -14,6 +13,7 @@ import { SplittableBall } from './palaceBossProjectile';
|
|||||||
import { PointEffect } from '../fx/pointShader';
|
import { PointEffect } from '../fx/pointShader';
|
||||||
import { loading } from '@user/data-base';
|
import { loading } from '@user/data-base';
|
||||||
import { clip } from '@user/legacy-plugin-data';
|
import { clip } from '@user/legacy-plugin-data';
|
||||||
|
import { LayerGroup } from '@user/client-modules';
|
||||||
|
|
||||||
loading.once('coreInit', () => {
|
loading.once('coreInit', () => {
|
||||||
const shader = new Shader();
|
const shader = new Shader();
|
||||||
|
@ -3,6 +3,7 @@ import { IStateDamageable } from '@user/data-state';
|
|||||||
import { Hitbox, Projectile } from './barrage';
|
import { Hitbox, Projectile } from './barrage';
|
||||||
import type { PalaceBoss } from './palaceBoss';
|
import type { PalaceBoss } from './palaceBoss';
|
||||||
import { clamp } from '@motajs/legacy-ui';
|
import { clamp } from '@motajs/legacy-ui';
|
||||||
|
import { mainRenderer } from 'packages-user/client-modules/src/render/renderer';
|
||||||
|
|
||||||
function popDamage(damage: number, boss: PalaceBoss, color: string) {
|
function popDamage(damage: number, boss: PalaceBoss, color: string) {
|
||||||
const { x, y } = core.status.hero.loc;
|
const { x, y } = core.status.hero.loc;
|
||||||
@ -74,9 +75,8 @@ export class SplittableBall extends Projectile<PalaceBoss> {
|
|||||||
static init(colors: Record<string, string[]>) {
|
static init(colors: Record<string, string[]>) {
|
||||||
this.ball.clear();
|
this.ball.clear();
|
||||||
for (const [key, color] of Object.entries(colors)) {
|
for (const [key, color] of Object.entries(colors)) {
|
||||||
const canvas = new MotaOffscreenCanvas2D();
|
const canvas = mainRenderer.requireCanvas();
|
||||||
canvas.size(32, 32);
|
canvas.size(32, 32);
|
||||||
canvas.withGameScale(true);
|
|
||||||
canvas.setHD(true);
|
canvas.setHD(true);
|
||||||
const ctx = canvas.ctx;
|
const ctx = canvas.ctx;
|
||||||
const gradient = ctx.createRadialGradient(16, 16, 8, 16, 16, 16);
|
const gradient = ctx.createRadialGradient(16, 16, 8, 16, 16, 16);
|
||||||
@ -87,7 +87,6 @@ export class SplittableBall extends Projectile<PalaceBoss> {
|
|||||||
ctx.fillStyle = gradient;
|
ctx.fillStyle = gradient;
|
||||||
ctx.arc(16, 16, 16, 0, Math.PI * 2);
|
ctx.arc(16, 16, 16, 0, Math.PI * 2);
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
canvas.freeze();
|
|
||||||
this.ball.set(key, canvas);
|
this.ball.set(key, canvas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,7 +94,7 @@ export class SplittableBall extends Projectile<PalaceBoss> {
|
|||||||
static end() {
|
static end() {
|
||||||
this.ball.forEach(v => {
|
this.ball.forEach(v => {
|
||||||
v.clear();
|
v.clear();
|
||||||
v.delete();
|
mainRenderer.deleteCanvas(v);
|
||||||
});
|
});
|
||||||
this.ball.clear();
|
this.ball.clear();
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
Shader,
|
Shader,
|
||||||
MotaRenderer,
|
MotaRenderer,
|
||||||
LayerGroup,
|
|
||||||
RenderItem,
|
RenderItem,
|
||||||
MotaOffscreenCanvas2D,
|
MotaOffscreenCanvas2D,
|
||||||
Container,
|
Container
|
||||||
HeroRenderer
|
|
||||||
} from '@motajs/render';
|
} from '@motajs/render';
|
||||||
import { PointEffect } from '../fx/pointShader';
|
import { PointEffect } from '../fx/pointShader';
|
||||||
import { BarrageBoss, BossSprite, Hitbox } from './barrage';
|
import { BarrageBoss, BossSprite, Hitbox } from './barrage';
|
||||||
@ -25,7 +23,11 @@ import { IStateDamageable } from '@user/data-state';
|
|||||||
import { Pop } from '../../../client-modules/src/render/legacy/pop';
|
import { Pop } from '../../../client-modules/src/render/legacy/pop';
|
||||||
import { loading } from '@user/data-base';
|
import { loading } from '@user/data-base';
|
||||||
import { clip } from '@user/legacy-plugin-data';
|
import { clip } from '@user/legacy-plugin-data';
|
||||||
import { WeatherController } from '@user/client-modules';
|
import {
|
||||||
|
HeroRenderer,
|
||||||
|
LayerGroup,
|
||||||
|
WeatherController
|
||||||
|
} from '@user/client-modules';
|
||||||
|
|
||||||
loading.once('coreInit', () => {
|
loading.once('coreInit', () => {
|
||||||
const shader = new Shader();
|
const shader = new Shader();
|
||||||
|
@ -5,6 +5,7 @@ import type { TowerBoss } from './towerBoss';
|
|||||||
import { IStateDamageable } from '@user/data-state';
|
import { IStateDamageable } from '@user/data-state';
|
||||||
import { PointEffect, PointEffectType } from '../fx/pointShader';
|
import { PointEffect, PointEffectType } from '../fx/pointShader';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
|
import { mainRenderer } from 'packages-user/client-modules/src/render/renderer';
|
||||||
|
|
||||||
export const enum ProjectileDirection {
|
export const enum ProjectileDirection {
|
||||||
Vertical,
|
Vertical,
|
||||||
@ -131,12 +132,11 @@ export class ArrowProjectile extends Projectile<TowerBoss> {
|
|||||||
static init() {
|
static init() {
|
||||||
this.easing = power(2, 'in');
|
this.easing = power(2, 'in');
|
||||||
this.dangerEasing = power(3, 'out');
|
this.dangerEasing = power(3, 'out');
|
||||||
this.horizontal = new MotaOffscreenCanvas2D();
|
this.horizontal = mainRenderer.requireCanvas();
|
||||||
this.vertical = new MotaOffscreenCanvas2D();
|
this.vertical = mainRenderer.requireCanvas();
|
||||||
const hor = this.horizontal;
|
const hor = this.horizontal;
|
||||||
hor.size(480, 32);
|
hor.size(480, 32);
|
||||||
hor.setHD(true);
|
hor.setHD(true);
|
||||||
hor.withGameScale(true);
|
|
||||||
const ctxHor = hor.ctx;
|
const ctxHor = hor.ctx;
|
||||||
ctxHor.fillStyle = '#f00';
|
ctxHor.fillStyle = '#f00';
|
||||||
ctxHor.globalAlpha = 0.6;
|
ctxHor.globalAlpha = 0.6;
|
||||||
@ -146,15 +146,12 @@ export class ArrowProjectile extends Projectile<TowerBoss> {
|
|||||||
const ver = this.vertical;
|
const ver = this.vertical;
|
||||||
ver.size(32, 480);
|
ver.size(32, 480);
|
||||||
ver.setHD(true);
|
ver.setHD(true);
|
||||||
ver.withGameScale(true);
|
|
||||||
const ctxVer = ver.ctx;
|
const ctxVer = ver.ctx;
|
||||||
ctxVer.fillStyle = '#f00';
|
ctxVer.fillStyle = '#f00';
|
||||||
ctxVer.globalAlpha = 0.6;
|
ctxVer.globalAlpha = 0.6;
|
||||||
for (let i = 0; i < 15; i++) {
|
for (let i = 0; i < 15; i++) {
|
||||||
ctxVer.fillRect(2, i * 32 + 2, 28, 28);
|
ctxVer.fillRect(2, i * 32 + 2, 28, 28);
|
||||||
}
|
}
|
||||||
hor.freeze();
|
|
||||||
ver.freeze();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -164,10 +161,10 @@ export class ArrowProjectile extends Projectile<TowerBoss> {
|
|||||||
this.easing = void 0;
|
this.easing = void 0;
|
||||||
this.dangerEasing = void 0;
|
this.dangerEasing = void 0;
|
||||||
this.horizontal?.clear();
|
this.horizontal?.clear();
|
||||||
this.horizontal?.delete();
|
if (this.horizontal) mainRenderer.deleteCanvas(this.horizontal);
|
||||||
this.horizontal = null;
|
this.horizontal = null;
|
||||||
this.vertical?.clear();
|
this.vertical?.clear();
|
||||||
this.vertical?.delete();
|
if (this.vertical) mainRenderer.deleteCanvas(this.vertical);
|
||||||
this.vertical = null;
|
this.vertical = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,15 +457,14 @@ export class ThunderProjectile extends Projectile<TowerBoss> {
|
|||||||
private effectId2?: number;
|
private effectId2?: number;
|
||||||
|
|
||||||
static init() {
|
static init() {
|
||||||
this.cache = new MotaOffscreenCanvas2D();
|
this.cache = mainRenderer.requireCanvas();
|
||||||
this.cache.setHD(true);
|
this.cache.setHD(true);
|
||||||
this.cache.withGameScale(true);
|
|
||||||
this.cache.size(480, 480);
|
this.cache.size(480, 480);
|
||||||
}
|
}
|
||||||
|
|
||||||
static end() {
|
static end() {
|
||||||
this.cache?.clear();
|
this.cache?.clear();
|
||||||
this.cache?.delete();
|
if (this.cache) mainRenderer.deleteCanvas(this.cache);
|
||||||
this.cache = null;
|
this.cache = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,12 +618,11 @@ export class ThunderBallProjectile extends Projectile<TowerBoss> {
|
|||||||
*/
|
*/
|
||||||
static init() {
|
static init() {
|
||||||
this.dangerEasing = power(3, 'out');
|
this.dangerEasing = power(3, 'out');
|
||||||
this.horizontal = new MotaOffscreenCanvas2D();
|
this.horizontal = mainRenderer.requireCanvas();
|
||||||
this.vertical = new MotaOffscreenCanvas2D();
|
this.vertical = mainRenderer.requireCanvas();
|
||||||
const hor = this.horizontal;
|
const hor = this.horizontal;
|
||||||
hor.size(480, 32);
|
hor.size(480, 32);
|
||||||
hor.setHD(true);
|
hor.setHD(true);
|
||||||
hor.withGameScale(true);
|
|
||||||
const ctxHor = hor.ctx;
|
const ctxHor = hor.ctx;
|
||||||
ctxHor.fillStyle = '#fff';
|
ctxHor.fillStyle = '#fff';
|
||||||
ctxHor.globalAlpha = 0.6;
|
ctxHor.globalAlpha = 0.6;
|
||||||
@ -637,15 +632,12 @@ export class ThunderBallProjectile extends Projectile<TowerBoss> {
|
|||||||
const ver = this.vertical;
|
const ver = this.vertical;
|
||||||
ver.size(32, 480);
|
ver.size(32, 480);
|
||||||
ver.setHD(true);
|
ver.setHD(true);
|
||||||
ver.withGameScale(true);
|
|
||||||
const ctxVer = ver.ctx;
|
const ctxVer = ver.ctx;
|
||||||
ctxVer.fillStyle = '#fff';
|
ctxVer.fillStyle = '#fff';
|
||||||
ctxVer.globalAlpha = 0.6;
|
ctxVer.globalAlpha = 0.6;
|
||||||
for (let i = 0; i < 15; i++) {
|
for (let i = 0; i < 15; i++) {
|
||||||
ctxVer.fillRect(2, i * 32 + 2, 28, 28);
|
ctxVer.fillRect(2, i * 32 + 2, 28, 28);
|
||||||
}
|
}
|
||||||
hor.freeze();
|
|
||||||
ver.freeze();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -654,10 +646,10 @@ export class ThunderBallProjectile extends Projectile<TowerBoss> {
|
|||||||
static end() {
|
static end() {
|
||||||
this.dangerEasing = void 0;
|
this.dangerEasing = void 0;
|
||||||
this.horizontal?.clear();
|
this.horizontal?.clear();
|
||||||
this.horizontal?.delete();
|
if (this.horizontal) mainRenderer.deleteCanvas(this.horizontal);
|
||||||
this.horizontal = null;
|
this.horizontal = null;
|
||||||
this.vertical?.clear();
|
this.vertical?.clear();
|
||||||
this.vertical?.delete();
|
if (this.vertical) mainRenderer.deleteCanvas(this.vertical);
|
||||||
this.vertical = null;
|
this.vertical = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
import { MotaOffscreenCanvas2D } from '@motajs/render';
|
import { MotaOffscreenCanvas2D } from '@motajs/render';
|
||||||
|
import { Container, MotaRenderer, Shader, Sprite } from '@motajs/render';
|
||||||
import {
|
import {
|
||||||
CameraAnimation,
|
CameraAnimation,
|
||||||
Container,
|
|
||||||
LayerGroup,
|
LayerGroup,
|
||||||
MotaRenderer,
|
|
||||||
Shader,
|
|
||||||
Sprite,
|
|
||||||
disableViewport,
|
disableViewport,
|
||||||
enableViewport
|
enableViewport
|
||||||
} from '@motajs/render';
|
} from '@user/client-modules';
|
||||||
import { loading } from '@user/data-base';
|
import { loading } from '@user/data-base';
|
||||||
import {
|
import {
|
||||||
heroMoveCollection,
|
heroMoveCollection,
|
||||||
@ -16,6 +13,7 @@ import {
|
|||||||
type MoveStep
|
type MoveStep
|
||||||
} from '@user/data-state';
|
} from '@user/data-state';
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
|
import { mainRenderer } from 'packages-user/client-modules/src/render/renderer';
|
||||||
|
|
||||||
export interface IChaseController {
|
export interface IChaseController {
|
||||||
/** 本次追逐战实例 */
|
/** 本次追逐战实例 */
|
||||||
@ -190,7 +188,7 @@ export class Chase extends EventEmitter<ChaseEvent> {
|
|||||||
for (const [key, nodes] of Object.entries(this.data.path)) {
|
for (const [key, nodes] of Object.entries(this.data.path)) {
|
||||||
if (nodes.length === 0) return;
|
if (nodes.length === 0) return;
|
||||||
const floor = key as FloorIds;
|
const floor = key as FloorIds;
|
||||||
const canvas = new MotaOffscreenCanvas2D();
|
const canvas = mainRenderer.requireCanvas();
|
||||||
const ctx = canvas.ctx;
|
const ctx = canvas.ctx;
|
||||||
const cell = 32;
|
const cell = 32;
|
||||||
const half = cell / 2;
|
const half = cell / 2;
|
||||||
@ -345,7 +343,7 @@ export class Chase extends EventEmitter<ChaseEvent> {
|
|||||||
Chase.shader.remove();
|
Chase.shader.remove();
|
||||||
this.emit('end', success);
|
this.emit('end', success);
|
||||||
this.removeAllListeners();
|
this.removeAllListeners();
|
||||||
this.pathMap.forEach(v => v.delete());
|
this.pathMap.forEach(v => mainRenderer.deleteCanvas(v));
|
||||||
this.pathMap.clear();
|
this.pathMap.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
import { Animation, hyper, linear, power, sleep } from 'mutate-animate';
|
import { Animation, hyper, linear, power, sleep } from 'mutate-animate';
|
||||||
import { Chase, ChaseData, IChaseController } from './chase';
|
import { Chase, ChaseData, IChaseController } from './chase';
|
||||||
// import { completeAchievement } from '@motajs/legacy-ui';
|
import { MotaRenderer, Sprite } from '@motajs/render';
|
||||||
|
import { PointEffect, PointEffectType } from '../fx/pointShader';
|
||||||
import {
|
import {
|
||||||
|
bgmController,
|
||||||
Camera,
|
Camera,
|
||||||
CameraAnimation,
|
CameraAnimation,
|
||||||
ICameraScale,
|
ICameraScale,
|
||||||
LayerGroup,
|
LayerGroup
|
||||||
MotaRenderer,
|
} from '@user/client-modules';
|
||||||
Sprite
|
|
||||||
} from '@motajs/render';
|
|
||||||
import { PointEffect, PointEffectType } from '../fx/pointShader';
|
|
||||||
import { bgmController } from '@user/client-modules';
|
|
||||||
import { loading } from '@user/data-base';
|
import { loading } from '@user/data-base';
|
||||||
import { chaseInit1, clip } from '@user/legacy-plugin-data';
|
import { chaseInit1, clip } from '@user/legacy-plugin-data';
|
||||||
|
|
||||||
@ -301,7 +299,7 @@ function processScale(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function wolfMove(chase: Chase) {
|
async function wolfMove(_chase: Chase) {
|
||||||
core.moveBlock(23, 17, Array(6).fill('down'), 80);
|
core.moveBlock(23, 17, Array(6).fill('down'), 80);
|
||||||
await sleep(550);
|
await sleep(550);
|
||||||
core.setBlock(508, 23, 23);
|
core.setBlock(508, 23, 23);
|
||||||
@ -701,7 +699,7 @@ function para3(chase: Chase, ani: Animation) {
|
|||||||
addLargeContrast(61, 7, ani, chase);
|
addLargeContrast(61, 7, ani, chase);
|
||||||
});
|
});
|
||||||
const exploded: Set<number> = new Set();
|
const exploded: Set<number> = new Set();
|
||||||
chase.on('step', (x, y) => {
|
chase.on('step', x => {
|
||||||
if (core.status.floorId !== 'MT14') return;
|
if (core.status.floorId !== 'MT14') return;
|
||||||
if (exploded.has(x)) return;
|
if (exploded.has(x)) return;
|
||||||
if (x > 20 && x < 49) {
|
if (x > 20 && x < 49) {
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import type {
|
import type { RenderAdapter } from '@motajs/render';
|
||||||
RenderAdapter,
|
|
||||||
LayerDoorAnimate,
|
|
||||||
LayerGroupAnimate,
|
|
||||||
LayerFloorBinder,
|
|
||||||
HeroRenderer,
|
|
||||||
Layer,
|
|
||||||
LayerGroup,
|
|
||||||
FloorViewport
|
|
||||||
} from '@motajs/render';
|
|
||||||
import type { TimingFn } from 'mutate-animate';
|
import type { TimingFn } from 'mutate-animate';
|
||||||
import { BlockMover, heroMoveCollection, MoveStep } from '@user/data-state';
|
import { BlockMover, heroMoveCollection, MoveStep } from '@user/data-state';
|
||||||
import { hook, loading } from '@user/data-base';
|
import { hook, loading } from '@user/data-base';
|
||||||
import { Patch, PatchClass } from '@motajs/legacy-common';
|
import { Patch, PatchClass } from '@motajs/legacy-common';
|
||||||
|
import type {
|
||||||
|
HeroRenderer,
|
||||||
|
LayerDoorAnimate,
|
||||||
|
LayerGroupAnimate,
|
||||||
|
Layer,
|
||||||
|
FloorViewport,
|
||||||
|
LayerFloorBinder,
|
||||||
|
LayerGroup
|
||||||
|
} from '@user/client-modules';
|
||||||
|
|
||||||
// 向后兼容用,会充当两个版本间过渡的作用
|
// 向后兼容用,会充当两个版本间过渡的作用
|
||||||
|
|
||||||
@ -88,8 +88,8 @@ export function initFallback() {
|
|||||||
|
|
||||||
Mota.r(() => {
|
Mota.r(() => {
|
||||||
// ----- 引入
|
// ----- 引入
|
||||||
const { Camera, MotaRenderer: Renderer } =
|
const { MotaRenderer: Renderer } = Mota.require('@motajs/render');
|
||||||
Mota.require('@motajs/render');
|
const { Camera } = Mota.require('@user/client-modules');
|
||||||
const Animation = Mota.require('MutateAnimate');
|
const Animation = Mota.require('MutateAnimate');
|
||||||
|
|
||||||
const patch = new Patch(PatchClass.Control);
|
const patch = new Patch(PatchClass.Control);
|
||||||
@ -116,7 +116,7 @@ export function initFallback() {
|
|||||||
'_action_moveAction',
|
'_action_moveAction',
|
||||||
function (data: any, x: number, y: number, prefix: any) {
|
function (data: any, x: number, y: number, prefix: any) {
|
||||||
if (core.canMoveHero()) {
|
if (core.canMoveHero()) {
|
||||||
var nx = core.nextX(),
|
const nx = core.nextX(),
|
||||||
ny = core.nextY();
|
ny = core.nextY();
|
||||||
// 检查noPass决定是撞击还是移动
|
// 检查noPass决定是撞击还是移动
|
||||||
if (core.noPass(nx, ny)) {
|
if (core.noPass(nx, ny)) {
|
||||||
@ -314,10 +314,10 @@ export function initFallback() {
|
|||||||
needKey: boolean,
|
needKey: boolean,
|
||||||
callback?: () => void
|
callback?: () => void
|
||||||
) {
|
) {
|
||||||
var block = core.getBlock(x, y);
|
const block = core.getBlock(x, y);
|
||||||
core.saveAndStopAutomaticRoute();
|
core.saveAndStopAutomaticRoute();
|
||||||
if (!core.events._openDoor_check(block, x, y, needKey)) {
|
if (!core.events._openDoor_check(block, x, y, needKey)) {
|
||||||
var locked = core.status.lockControl;
|
const locked = core.status.lockControl;
|
||||||
core.waitHeroToStop(function () {
|
core.waitHeroToStop(function () {
|
||||||
if (!locked) core.unlockControl();
|
if (!locked) core.unlockControl();
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
@ -383,8 +383,8 @@ export function initFallback() {
|
|||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var block = core.getBlockById(id);
|
const block = core.getBlockById(id);
|
||||||
var doorInfo = (block.event || {}).doorInfo;
|
const doorInfo = (block.event || {}).doorInfo;
|
||||||
if (!doorInfo) {
|
if (!doorInfo) {
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
return;
|
return;
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
import { mat4 } from 'gl-matrix';
|
import { mat4 } from 'gl-matrix';
|
||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { WebGLColorArray, createProgram, isWebGL2Supported } from './webgl';
|
import { WebGLColorArray, createProgram, isWebGL2Supported } from './webgl';
|
||||||
import {
|
import { Sprite } from '@motajs/render';
|
||||||
ILayerRenderExtends,
|
import { ILayerRenderExtends, Layer, HeroRenderer } from '@user/client-modules';
|
||||||
Layer,
|
|
||||||
HeroRenderer,
|
|
||||||
Sprite
|
|
||||||
} from '@motajs/render';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 最大光源数量,必须设置,且光源数不能超过这个值,这个值决定了会预留多少的缓冲区,因此最好尽可能小,同时游戏过程中不可修改
|
* 最大光源数量,必须设置,且光源数不能超过这个值,这个值决定了会预留多少的缓冲区,因此最好尽可能小,同时游戏过程中不可修改
|
||||||
@ -114,7 +110,7 @@ export function createShadow() {
|
|||||||
Shadow.update(true);
|
Shadow.update(true);
|
||||||
LayerShadowExtends.shadowList.forEach(v => v.update());
|
LayerShadowExtends.shadowList.forEach(v => v.update());
|
||||||
});
|
});
|
||||||
hook.on('changingFloor', floorId => {
|
hook.on('changingFloor', () => {
|
||||||
Shadow.clearBuffer();
|
Shadow.clearBuffer();
|
||||||
Shadow.update(true);
|
Shadow.update(true);
|
||||||
// setCanvasFilterByFloorId(floorId);
|
// setCanvasFilterByFloorId(floorId);
|
||||||
|
@ -12,7 +12,6 @@ export * from './ui';
|
|||||||
export * from './settings';
|
export * from './settings';
|
||||||
export * from './danmaku';
|
export * from './danmaku';
|
||||||
export * from './fixed';
|
export * from './fixed';
|
||||||
export * from './hotkey';
|
|
||||||
export * from './keyboard';
|
export * from './keyboard';
|
||||||
export * from './uiIns';
|
export * from './uiIns';
|
||||||
export * from './settingIns';
|
export * from './settingIns';
|
||||||
|
@ -90,7 +90,7 @@ import { isNil } from 'lodash-es';
|
|||||||
|
|
||||||
const props = defineProps<IMountedVBind>();
|
const props = defineProps<IMountedVBind>();
|
||||||
|
|
||||||
const skillTree = Mota.require('@user/legacy-plugin-data');
|
const skillTree = Mota.require('@user/data-state');
|
||||||
|
|
||||||
let canvas: HTMLCanvasElement;
|
let canvas: HTMLCanvasElement;
|
||||||
let ctx: CanvasRenderingContext2D;
|
let ctx: CanvasRenderingContext2D;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import { logger } from '@motajs/common';
|
|
||||||
|
|
||||||
interface OffscreenCanvasEvent {
|
interface OffscreenCanvasEvent {
|
||||||
/** 当被动触发resize时(例如core.domStyle.scale变化、窗口大小变化)时触发,使用size函数并不会触发 */
|
/** 当被动触发resize时(例如core.domStyle.scale变化、窗口大小变化)时触发,使用size函数并不会触发 */
|
||||||
@ -7,16 +6,12 @@ interface OffscreenCanvasEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
||||||
static list: Set<MotaOffscreenCanvas2D> = new Set();
|
|
||||||
|
|
||||||
canvas: HTMLCanvasElement;
|
canvas: HTMLCanvasElement;
|
||||||
ctx: CanvasRenderingContext2D;
|
ctx: CanvasRenderingContext2D;
|
||||||
|
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
|
|
||||||
/** 是否自动跟随样板的core.domStyle.scale进行缩放 */
|
|
||||||
autoScale: boolean = false;
|
|
||||||
/** 是否是高清画布 */
|
/** 是否是高清画布 */
|
||||||
highResolution: boolean = true;
|
highResolution: boolean = true;
|
||||||
/** 是否启用抗锯齿 */
|
/** 是否启用抗锯齿 */
|
||||||
@ -27,12 +22,6 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
|||||||
/** 更新标识符,如果发生变化则说明画布被动清空 */
|
/** 更新标识符,如果发生变化则说明画布被动清空 */
|
||||||
symbol: number = 0;
|
symbol: number = 0;
|
||||||
|
|
||||||
private _freezed: boolean = false;
|
|
||||||
/** 当前画布是否被冻结 */
|
|
||||||
get freezed() {
|
|
||||||
return this._freezed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _active: boolean = true;
|
private _active: boolean = true;
|
||||||
get active() {
|
get active() {
|
||||||
return this._active;
|
return this._active;
|
||||||
@ -46,65 +35,52 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
|||||||
*/
|
*/
|
||||||
constructor(alpha: boolean = true, canvas?: HTMLCanvasElement) {
|
constructor(alpha: boolean = true, canvas?: HTMLCanvasElement) {
|
||||||
super();
|
super();
|
||||||
// console.trace();
|
|
||||||
|
|
||||||
this.canvas = canvas ?? document.createElement('canvas');
|
this.canvas = canvas ?? document.createElement('canvas');
|
||||||
this.ctx = this.canvas.getContext('2d', { alpha })!;
|
this.ctx = this.canvas.getContext('2d', { alpha })!;
|
||||||
this.width = this.canvas.width / devicePixelRatio;
|
this.width = this.canvas.width / devicePixelRatio;
|
||||||
this.height = this.canvas.height / devicePixelRatio;
|
this.height = this.canvas.height / devicePixelRatio;
|
||||||
|
}
|
||||||
|
|
||||||
MotaOffscreenCanvas2D.list.add(this);
|
/**
|
||||||
|
* 设置画布的缩放比
|
||||||
|
* @param scale 缩放比
|
||||||
|
*/
|
||||||
|
setScale(scale: number) {
|
||||||
|
if (scale === this.scale) {
|
||||||
|
this.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.scale = scale;
|
||||||
|
let ratio = this.highResolution ? devicePixelRatio : 1;
|
||||||
|
ratio *= this.scale;
|
||||||
|
this.canvas.width = this.width * ratio;
|
||||||
|
this.canvas.height = this.height * ratio;
|
||||||
|
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
|
this.ctx.scale(ratio, ratio);
|
||||||
|
this.ctx.imageSmoothingEnabled = this.antiAliasing;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置画布的大小
|
* 设置画布的大小
|
||||||
*/
|
*/
|
||||||
size(width: number, height: number) {
|
size(width: number, height: number) {
|
||||||
if (this._freezed) {
|
|
||||||
logger.warn(33);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const w = Math.max(width, 1);
|
const w = Math.max(width, 1);
|
||||||
const h = Math.max(height, 1);
|
const h = Math.max(height, 1);
|
||||||
let ratio = this.highResolution ? devicePixelRatio : 1;
|
let ratio = this.highResolution ? devicePixelRatio : 1;
|
||||||
const scale = core.domStyle.scale;
|
ratio *= this.scale;
|
||||||
if (this.autoScale) {
|
|
||||||
ratio *= scale;
|
|
||||||
}
|
|
||||||
this.scale = ratio;
|
|
||||||
this.canvas.width = w * ratio;
|
this.canvas.width = w * ratio;
|
||||||
this.canvas.height = h * ratio;
|
this.canvas.height = h * ratio;
|
||||||
this.width = w;
|
this.width = w;
|
||||||
this.height = height;
|
this.height = h;
|
||||||
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
this.ctx.scale(ratio, ratio);
|
this.ctx.scale(ratio, ratio);
|
||||||
this.ctx.imageSmoothingEnabled = this.antiAliasing;
|
this.ctx.imageSmoothingEnabled = this.antiAliasing;
|
||||||
if (this.canvas.isConnected) {
|
|
||||||
this.canvas.style.width = `${w * scale}px`;
|
|
||||||
this.canvas.style.height = `${h * scale}px`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置当前画布是否跟随样板的 core.domStyle.scale 一同进行缩放
|
|
||||||
*/
|
|
||||||
withGameScale(auto: boolean) {
|
|
||||||
if (this._freezed) {
|
|
||||||
logger.warn(33);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.autoScale = auto;
|
|
||||||
this.size(this.width, this.height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置当前画布是否为高清画布
|
* 设置当前画布是否为高清画布
|
||||||
*/
|
*/
|
||||||
setHD(hd: boolean) {
|
setHD(hd: boolean) {
|
||||||
if (this._freezed) {
|
|
||||||
logger.warn(33);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.highResolution = hd;
|
this.highResolution = hd;
|
||||||
this.size(this.width, this.height);
|
this.size(this.width, this.height);
|
||||||
}
|
}
|
||||||
@ -113,10 +89,6 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
|||||||
* 设置当前画布的抗锯齿设置
|
* 设置当前画布的抗锯齿设置
|
||||||
*/
|
*/
|
||||||
setAntiAliasing(anti: boolean) {
|
setAntiAliasing(anti: boolean) {
|
||||||
if (this._freezed) {
|
|
||||||
logger.warn(33);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.antiAliasing = anti;
|
this.antiAliasing = anti;
|
||||||
this.ctx.imageSmoothingEnabled = anti;
|
this.ctx.imageSmoothingEnabled = anti;
|
||||||
}
|
}
|
||||||
@ -125,56 +97,12 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
|||||||
* 清空画布
|
* 清空画布
|
||||||
*/
|
*/
|
||||||
clear() {
|
clear() {
|
||||||
if (this._freezed) {
|
|
||||||
logger.warn(33);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.ctx.save();
|
this.ctx.save();
|
||||||
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
this.ctx.restore();
|
this.ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除这个画布
|
|
||||||
*/
|
|
||||||
delete() {
|
|
||||||
this.canvas.remove();
|
|
||||||
this.ctx.reset();
|
|
||||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
||||||
this._freezed = true;
|
|
||||||
MotaOffscreenCanvas2D.list.delete(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 冻结这个画布的属性,之后便不能被修改,同时会从画布列表中删去。
|
|
||||||
*/
|
|
||||||
freeze() {
|
|
||||||
this._freezed = true;
|
|
||||||
MotaOffscreenCanvas2D.list.delete(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使此画布生效,使用前请务必调用此函数,生效后会跟随游戏的放缩比例更改大小,但会导致不会被垃圾回收
|
|
||||||
*/
|
|
||||||
activate() {
|
|
||||||
if (this._active || this._freezed) return;
|
|
||||||
MotaOffscreenCanvas2D.list.add(this);
|
|
||||||
if (this.autoScale) {
|
|
||||||
this.size(this.width, this.height);
|
|
||||||
this.symbol++;
|
|
||||||
this.emit('resize');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使此画布失效,当这个画布暂时不会被使用时请务必调用此函数,失效后若没有对此画布的引用,那么会自动垃圾回收
|
|
||||||
*/
|
|
||||||
deactivate() {
|
|
||||||
if (!this._active || this._freezed) return;
|
|
||||||
MotaOffscreenCanvas2D.list.delete(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 复制一个离屏Canvas2D对象,一般用于缓存等操作
|
* 复制一个离屏Canvas2D对象,一般用于缓存等操作
|
||||||
* @param canvas 被复制的MotaOffscreenCanvas2D对象
|
* @param canvas 被复制的MotaOffscreenCanvas2D对象
|
||||||
@ -183,7 +111,6 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
|||||||
static clone(canvas: MotaOffscreenCanvas2D): MotaOffscreenCanvas2D {
|
static clone(canvas: MotaOffscreenCanvas2D): MotaOffscreenCanvas2D {
|
||||||
const newCanvas = new MotaOffscreenCanvas2D();
|
const newCanvas = new MotaOffscreenCanvas2D();
|
||||||
newCanvas.setHD(canvas.highResolution);
|
newCanvas.setHD(canvas.highResolution);
|
||||||
newCanvas.withGameScale(canvas.autoScale);
|
|
||||||
newCanvas.size(canvas.width, canvas.height);
|
newCanvas.size(canvas.width, canvas.height);
|
||||||
newCanvas.ctx.drawImage(
|
newCanvas.ctx.drawImage(
|
||||||
canvas.canvas,
|
canvas.canvas,
|
||||||
@ -192,23 +119,6 @@ export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
|
|||||||
canvas.width,
|
canvas.width,
|
||||||
canvas.height
|
canvas.height
|
||||||
);
|
);
|
||||||
newCanvas.freeze();
|
|
||||||
return newCanvas;
|
return newCanvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
static refreshAll(force: boolean = false) {
|
|
||||||
this.list.forEach(v => {
|
|
||||||
if (force || v.autoScale) {
|
|
||||||
v.size(v.width, v.height);
|
|
||||||
v.symbol++;
|
|
||||||
v.emit('resize');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
MotaOffscreenCanvas2D.refreshAll();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
@ -42,6 +42,11 @@ export class Container<E extends EContainerEvent = EContainerEvent>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onResize(scale: number): void {
|
||||||
|
this.sortedChildren.forEach(v => v.onResize(scale));
|
||||||
|
super.onResize(scale);
|
||||||
|
}
|
||||||
|
|
||||||
requestSort() {
|
requestSort() {
|
||||||
if (!this.needSort) {
|
if (!this.needSort) {
|
||||||
this.needSort = true;
|
this.needSort = true;
|
||||||
|
@ -184,6 +184,11 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
|
|||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onResize(scale: number): void {
|
||||||
|
this.sizeGL(this.width, this.height);
|
||||||
|
super.onResize(scale);
|
||||||
|
}
|
||||||
|
|
||||||
setHD(hd: boolean): void {
|
setHD(hd: boolean): void {
|
||||||
super.setHD(hd);
|
super.setHD(hd);
|
||||||
this.sizeGL(this.width, this.height);
|
this.sizeGL(this.width, this.height);
|
||||||
@ -196,7 +201,7 @@ export abstract class GL2<E extends EGL2Event = EGL2Event> extends RenderItem<
|
|||||||
|
|
||||||
private sizeGL(width: number, height: number) {
|
private sizeGL(width: number, height: number) {
|
||||||
const ratio = this.highResolution ? devicePixelRatio : 1;
|
const ratio = this.highResolution ? devicePixelRatio : 1;
|
||||||
const scale = ratio * core.domStyle.scale;
|
const scale = ratio * this.cache.scale;
|
||||||
this.canvas.width = width * scale;
|
this.canvas.width = width * scale;
|
||||||
this.canvas.height = height * scale;
|
this.canvas.height = height * scale;
|
||||||
}
|
}
|
||||||
|
@ -132,6 +132,14 @@ export interface IRenderTickerSupport {
|
|||||||
hasTicker(id: number): boolean;
|
hasTicker(id: number): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IRenderEvent {
|
||||||
|
/**
|
||||||
|
* 当触发缩放事件时,此函数执行的内容
|
||||||
|
* @param scale 缩放至的缩放比
|
||||||
|
*/
|
||||||
|
onResize(scale: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IRenderVueSupport {
|
export interface IRenderVueSupport {
|
||||||
/**
|
/**
|
||||||
* 在 jsx, vue 中当属性改变后触发此函数,用于处理响应式等情况
|
* 在 jsx, vue 中当属性改变后触发此函数,用于处理响应式等情况
|
||||||
@ -185,6 +193,10 @@ export interface IRenderTreeRoot {
|
|||||||
hoverElement(element: RenderItem): void;
|
hoverElement(element: RenderItem): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface RenderItemCanvasData {
|
||||||
|
autoScale: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ERenderItemEvent extends ERenderItemActionEvent {
|
export interface ERenderItemEvent extends ERenderItemActionEvent {
|
||||||
beforeRender: [transform: Transform];
|
beforeRender: [transform: Transform];
|
||||||
afterRender: [transform: Transform];
|
afterRender: [transform: Transform];
|
||||||
@ -213,7 +225,8 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
|||||||
IRenderTickerSupport,
|
IRenderTickerSupport,
|
||||||
IRenderChildable,
|
IRenderChildable,
|
||||||
IRenderVueSupport,
|
IRenderVueSupport,
|
||||||
ITransformUpdatable
|
ITransformUpdatable,
|
||||||
|
IRenderEvent
|
||||||
{
|
{
|
||||||
/** 渲染的全局ticker */
|
/** 渲染的全局ticker */
|
||||||
static ticker: Ticker = new Ticker();
|
static ticker: Ticker = new Ticker();
|
||||||
@ -332,6 +345,11 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
|||||||
readonly transformFallThrough: boolean = false;
|
readonly transformFallThrough: boolean = false;
|
||||||
/** 这个渲染元素使用到的所有画布 */
|
/** 这个渲染元素使用到的所有画布 */
|
||||||
protected readonly canvases: Set<MotaOffscreenCanvas2D> = new Set();
|
protected readonly canvases: Set<MotaOffscreenCanvas2D> = new Set();
|
||||||
|
/** 这个渲染元素每个画布的配置信息 */
|
||||||
|
private readonly canvasMap: Map<
|
||||||
|
MotaOffscreenCanvas2D,
|
||||||
|
RenderItemCanvasData
|
||||||
|
> = new Map();
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 交互事件
|
//#region 交互事件
|
||||||
@ -371,11 +389,8 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
|||||||
|
|
||||||
this._transform.bind(this);
|
this._transform.bind(this);
|
||||||
this.cache = this.requireCanvas();
|
this.cache = this.requireCanvas();
|
||||||
this.cache.withGameScale(true);
|
|
||||||
if (!enableCache) {
|
if (!enableCache) {
|
||||||
this.cache.withGameScale(false);
|
|
||||||
this.cache.size(1, 1);
|
this.cache.size(1, 1);
|
||||||
this.cache.freeze();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,10 +454,12 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
|||||||
/**
|
/**
|
||||||
* 申请一个 `MotaOffscreenCanvas2D`,即申请一个画布
|
* 申请一个 `MotaOffscreenCanvas2D`,即申请一个画布
|
||||||
* @param alpha 是否启用画布的 alpha 通道
|
* @param alpha 是否启用画布的 alpha 通道
|
||||||
|
* @param autoScale 是否自动跟随缩放
|
||||||
*/
|
*/
|
||||||
protected requireCanvas(alpha: boolean = true) {
|
requireCanvas(alpha: boolean = true, autoScale: boolean = false) {
|
||||||
const canvas = new MotaOffscreenCanvas2D(alpha);
|
const canvas = new MotaOffscreenCanvas2D(alpha);
|
||||||
this.canvases.add(canvas);
|
this.canvases.add(canvas);
|
||||||
|
this.canvasMap.set(canvas, { autoScale });
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,9 +467,20 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
|||||||
* 删除由 `requireCanvas` 申请的画布,当画布不再使用时,可以用该方法删除画布
|
* 删除由 `requireCanvas` 申请的画布,当画布不再使用时,可以用该方法删除画布
|
||||||
* @param canvas 要删除的画布
|
* @param canvas 要删除的画布
|
||||||
*/
|
*/
|
||||||
protected deleteCanvas(canvas: MotaOffscreenCanvas2D) {
|
deleteCanvas(canvas: MotaOffscreenCanvas2D) {
|
||||||
if (!this.canvases.delete(canvas)) return;
|
this.canvases.delete(canvas);
|
||||||
canvas.delete();
|
this.canvasMap.delete(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region 事件处理
|
||||||
|
|
||||||
|
onResize(scale: number): void {
|
||||||
|
this.cache.setScale(scale);
|
||||||
|
this.canvases.forEach(v => {
|
||||||
|
if (this.canvasMap.get(v)?.autoScale) {
|
||||||
|
v.setScale(scale);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region 修改元素属性
|
//#region 修改元素属性
|
||||||
@ -736,7 +764,6 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
|||||||
this.update();
|
this.update();
|
||||||
this.checkRoot();
|
this.checkRoot();
|
||||||
this._root?.connect(this);
|
this._root?.connect(this);
|
||||||
this.canvases.forEach(v => v.activate());
|
|
||||||
this._transform.bind(this);
|
this._transform.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -751,7 +778,6 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
|||||||
this._parent = void 0;
|
this._parent = void 0;
|
||||||
parent.requestSort();
|
parent.requestSort();
|
||||||
parent.update();
|
parent.update();
|
||||||
this.canvases.forEach(v => v.deactivate());
|
|
||||||
this._transform.bind();
|
this._transform.bind();
|
||||||
if (!success) return false;
|
if (!success) return false;
|
||||||
this._root?.disconnect(this);
|
this._root?.disconnect(this);
|
||||||
@ -1257,8 +1283,6 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
|||||||
this.remove();
|
this.remove();
|
||||||
this.emit('destroy');
|
this.emit('destroy');
|
||||||
this.removeAllListeners();
|
this.removeAllListeners();
|
||||||
this.cache.delete();
|
|
||||||
this.canvases.forEach(v => v.delete());
|
|
||||||
this.canvases.clear();
|
this.canvases.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,23 @@ interface MouseInfo {
|
|||||||
identifier: number;
|
identifier: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MotaRendererConfig {
|
||||||
|
/** 要挂载到哪个画布上,可以填 css 选择器或画布元素本身 */
|
||||||
|
canvas: string | HTMLCanvasElement;
|
||||||
|
/** 画布的宽度,所有渲染操作会自行适配缩放 */
|
||||||
|
width: number;
|
||||||
|
/** 画布的高度,所有渲染操作会自行适配缩放 */
|
||||||
|
height: number;
|
||||||
|
/** 是否启用不透明度通道,默认启用 */
|
||||||
|
alpha?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export class MotaRenderer extends Container implements IRenderTreeRoot {
|
export class MotaRenderer extends Container implements IRenderTreeRoot {
|
||||||
static list: Map<string, MotaRenderer> = new Map();
|
static list: Map<string, MotaRenderer> = new Map();
|
||||||
|
|
||||||
|
/** 缩放比 */
|
||||||
|
private scale: number = 1;
|
||||||
|
|
||||||
/** 所有连接到此根元素的渲染元素的 id 到元素自身的映射 */
|
/** 所有连接到此根元素的渲染元素的 id 到元素自身的映射 */
|
||||||
protected idMap: Map<string, RenderItem> = new Map();
|
protected idMap: Map<string, RenderItem> = new Map();
|
||||||
|
|
||||||
@ -58,23 +72,22 @@ export class MotaRenderer extends Container implements IRenderTreeRoot {
|
|||||||
|
|
||||||
readonly isRoot = true;
|
readonly isRoot = true;
|
||||||
|
|
||||||
constructor(id: string = 'render-main') {
|
constructor(config: MotaRendererConfig) {
|
||||||
super('static', false);
|
super('static', false);
|
||||||
|
|
||||||
const canvas = document.getElementById(id) as HTMLCanvasElement;
|
const canvas = this.getMountCanvas(config.canvas);
|
||||||
if (!canvas) {
|
if (!canvas) {
|
||||||
logger.error(19);
|
logger.error(19);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.target = new MotaOffscreenCanvas2D(true, canvas);
|
this.target = new MotaOffscreenCanvas2D(config.alpha ?? true, canvas);
|
||||||
this.size(core._PX_, core._PY_);
|
this.size(config.width, config.height);
|
||||||
this.target.withGameScale(true);
|
|
||||||
this.target.setAntiAliasing(false);
|
this.target.setAntiAliasing(false);
|
||||||
|
|
||||||
this.setAnchor(0.5, 0.5);
|
this.setAnchor(0.5, 0.5);
|
||||||
this.transform.translate(240, 240);
|
this.transform.translate(240, 240);
|
||||||
|
|
||||||
MotaRenderer.list.set(id, this);
|
MotaRenderer.list.set(canvas.id, this);
|
||||||
|
|
||||||
const update = () => {
|
const update = () => {
|
||||||
this.requestRenderFrame(() => {
|
this.requestRenderFrame(() => {
|
||||||
@ -87,6 +100,39 @@ export class MotaRenderer extends Container implements IRenderTreeRoot {
|
|||||||
this.listen();
|
this.listen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置这个渲染器的缩放比
|
||||||
|
* @param scale 缩放比
|
||||||
|
*/
|
||||||
|
setScale(scale: number) {
|
||||||
|
this.scale = scale;
|
||||||
|
this.onResize(scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取这个渲染器的缩放比
|
||||||
|
*/
|
||||||
|
getScale() {
|
||||||
|
return this.scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
onResize(scale: number): void {
|
||||||
|
this.target.setScale(scale);
|
||||||
|
const width = this.target.width * scale;
|
||||||
|
const height = this.target.height * scale;
|
||||||
|
this.target.canvas.style.width = `${width}px`;
|
||||||
|
this.target.canvas.style.height = `${height}px`;
|
||||||
|
super.onResize(scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getMountCanvas(canvas: string | HTMLCanvasElement) {
|
||||||
|
if (typeof canvas === 'string') {
|
||||||
|
return document.querySelector(canvas) as HTMLCanvasElement;
|
||||||
|
} else {
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size(width: number, height: number): void {
|
size(width: number, height: number): void {
|
||||||
super.size(width, height);
|
super.size(width, height);
|
||||||
this.target.size(width, height);
|
this.target.size(width, height);
|
||||||
@ -557,7 +603,6 @@ export class MotaRenderer extends Container implements IRenderTreeRoot {
|
|||||||
destroy() {
|
destroy() {
|
||||||
super.destroy();
|
super.destroy();
|
||||||
MotaRenderer.list.delete(this.id);
|
MotaRenderer.list.delete(this.id);
|
||||||
this.target.delete();
|
|
||||||
this.abort?.abort();
|
this.abort?.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,10 +610,14 @@ export class MotaRenderer extends Container implements IRenderTreeRoot {
|
|||||||
if (item.isComment) return '';
|
if (item.isComment) return '';
|
||||||
const name = item.constructor.name;
|
const name = item.constructor.name;
|
||||||
if (item.children.size === 0) {
|
if (item.children.size === 0) {
|
||||||
return `${' '.repeat(deep * space)}<${name} ${item.id ? `id="${item.id}" ` : ''}uid="${item.uid}"${item.hidden ? ' hidden' : ''} />\n`;
|
return `${' '.repeat(deep * space)}<${name} ${
|
||||||
|
item.id ? `id="${item.id}" ` : ''
|
||||||
|
}uid="${item.uid}"${item.hidden ? ' hidden' : ''} />\n`;
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
`${' '.repeat(deep * space)}<${name} ${item.id ? `${item.id} ` : ''}uid="${item.uid}" ${item.hidden ? 'hidden' : ''}>\n` +
|
`${' '.repeat(deep * space)}<${name} ${
|
||||||
|
item.id ? `${item.id} ` : ''
|
||||||
|
}uid="${item.uid}" ${item.hidden ? 'hidden' : ''}>\n` +
|
||||||
`${[...item.children]
|
`${[...item.children]
|
||||||
.filter(v => !v.isComment)
|
.filter(v => !v.isComment)
|
||||||
.map(v => this.toTagString(v, space, deep + 1))
|
.map(v => this.toTagString(v, space, deep + 1))
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { TimingFn } from 'mutate-animate';
|
import { TimingFn } from 'mutate-animate';
|
||||||
// import { RenderAdapter } from './adapter';
|
|
||||||
// import { FloorViewport } from './preset/viewport';
|
|
||||||
import { JSX } from 'vue/jsx-runtime';
|
import { JSX } from 'vue/jsx-runtime';
|
||||||
import { DefineComponent, DefineSetupFnComponent } from 'vue';
|
import { DefineComponent, DefineSetupFnComponent } from 'vue';
|
||||||
import { MotaOffscreenCanvas2D } from './canvas2d';
|
import { MotaOffscreenCanvas2D } from './canvas2d';
|
||||||
@ -14,10 +12,10 @@ export type Props<
|
|||||||
> = T extends keyof JSX.IntrinsicElements
|
> = T extends keyof JSX.IntrinsicElements
|
||||||
? JSX.IntrinsicElements[T]
|
? JSX.IntrinsicElements[T]
|
||||||
: T extends DefineSetupFnComponent<any>
|
: T extends DefineSetupFnComponent<any>
|
||||||
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
||||||
: T extends DefineComponent
|
: T extends DefineComponent
|
||||||
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
? InstanceType<T>['$props'] & InstanceType<T>['$emits']
|
||||||
: unknown;
|
: unknown;
|
||||||
|
|
||||||
export type ElementLocator = [
|
export type ElementLocator = [
|
||||||
x?: number,
|
x?: number,
|
||||||
|
@ -1,24 +1,3 @@
|
|||||||
import { createCache } from './cache';
|
|
||||||
import { createFrame } from './frame';
|
|
||||||
import { createLayer } from './layer';
|
|
||||||
import { createViewport } from './viewport';
|
|
||||||
|
|
||||||
export function create() {
|
|
||||||
createCache();
|
|
||||||
createFrame();
|
|
||||||
createLayer();
|
|
||||||
createViewport();
|
|
||||||
}
|
|
||||||
|
|
||||||
export * from './animate';
|
|
||||||
export * from './block';
|
|
||||||
export * from './cache';
|
|
||||||
export * from './camera';
|
|
||||||
export * from './frame';
|
|
||||||
export * from './graphics';
|
export * from './graphics';
|
||||||
export * from './hero';
|
|
||||||
export * from './layer';
|
|
||||||
export * from './misc';
|
export * from './misc';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
export * from './utils';
|
|
||||||
export * from './viewport';
|
|
||||||
|
@ -6,11 +6,6 @@ import {
|
|||||||
MotaOffscreenCanvas2D
|
MotaOffscreenCanvas2D
|
||||||
} from '@motajs/render-core';
|
} from '@motajs/render-core';
|
||||||
import { Font } from '@motajs/render-style';
|
import { Font } from '@motajs/render-style';
|
||||||
import { logger } from '@motajs/common';
|
|
||||||
import { isNil } from 'lodash-es';
|
|
||||||
import { IAnimateFrame, renderEmits } from './frame';
|
|
||||||
import { AutotileRenderable, RenderableData, texture } from './cache';
|
|
||||||
import { SizedCanvasImageSource } from './types';
|
|
||||||
|
|
||||||
/** 文字的安全填充,会填充在文字的上侧和下侧,防止削顶和削底 */
|
/** 文字的安全填充,会填充在文字的上侧和下侧,防止削顶和削底 */
|
||||||
const SAFE_PAD = 1;
|
const SAFE_PAD = 1;
|
||||||
@ -229,322 +224,3 @@ export class Comment extends RenderItem {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EIconEvent extends ERenderItemEvent {}
|
|
||||||
|
|
||||||
export class Icon extends RenderItem<EIconEvent> implements IAnimateFrame {
|
|
||||||
/** 图标id */
|
|
||||||
icon: AllNumbers = 0;
|
|
||||||
/** 帧数 */
|
|
||||||
frame: number = 0;
|
|
||||||
/** 是否启用动画 */
|
|
||||||
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
|
|
||||||
): void {
|
|
||||||
const ctx = canvas.ctx;
|
|
||||||
const renderable = this.renderable;
|
|
||||||
if (!renderable) return;
|
|
||||||
const [x, y, w, h] = renderable.render[0];
|
|
||||||
const cw = this.width;
|
|
||||||
const ch = this.height;
|
|
||||||
const frame = this.animate
|
|
||||||
? RenderItem.animatedFrame % renderable.frame
|
|
||||||
: this.frame;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置图标
|
|
||||||
* @param id 图标id
|
|
||||||
*/
|
|
||||||
setIcon(id: AllIds | AllNumbers) {
|
|
||||||
if (id === 0) {
|
|
||||||
this.renderable = void 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const num = typeof id === 'number' ? id : texture.idNumberMap[id];
|
|
||||||
|
|
||||||
const { loading } = Mota.require('@user/data-base');
|
|
||||||
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) {
|
|
||||||
logger.warn(43, num.toString());
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
this.icon = num;
|
|
||||||
this.renderable = renderable;
|
|
||||||
this.frame = renderable.frame;
|
|
||||||
}
|
|
||||||
this.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新动画帧
|
|
||||||
*/
|
|
||||||
updateFrameAnimate(): void {
|
|
||||||
if (this.animate) this.update(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy(): void {
|
|
||||||
renderEmits.removeFramer(this);
|
|
||||||
super.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected handleProps(
|
|
||||||
key: string,
|
|
||||||
_prevValue: any,
|
|
||||||
nextValue: any
|
|
||||||
): boolean {
|
|
||||||
switch (key) {
|
|
||||||
case 'icon':
|
|
||||||
this.setIcon(nextValue);
|
|
||||||
return true;
|
|
||||||
case 'animate':
|
|
||||||
if (!this.assertType(nextValue, 'boolean', key)) return false;
|
|
||||||
this.animate = nextValue;
|
|
||||||
if (nextValue) renderEmits.addFramer(this);
|
|
||||||
else renderEmits.removeFramer(this);
|
|
||||||
this.update();
|
|
||||||
return true;
|
|
||||||
case 'frame':
|
|
||||||
if (!this.assertType(nextValue, 'number', key)) return false;
|
|
||||||
this.frame = nextValue;
|
|
||||||
this.update();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface WinskinPatterns {
|
|
||||||
top: CanvasPattern;
|
|
||||||
left: CanvasPattern;
|
|
||||||
bottom: CanvasPattern;
|
|
||||||
right: CanvasPattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EWinskinEvent extends ERenderItemEvent {}
|
|
||||||
|
|
||||||
export class Winskin extends RenderItem<EWinskinEvent> {
|
|
||||||
image: SizedCanvasImageSource;
|
|
||||||
/** 边框宽度,32表示原始宽度 */
|
|
||||||
borderSize: number = 32;
|
|
||||||
/** 图片名称 */
|
|
||||||
imageName?: string;
|
|
||||||
|
|
||||||
private pendingImage?: ImageIds;
|
|
||||||
private patternCache?: WinskinPatterns;
|
|
||||||
private patternTransform: DOMMatrix;
|
|
||||||
|
|
||||||
private static patternMap: Map<string, WinskinPatterns> = new Map();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
image: SizedCanvasImageSource,
|
|
||||||
type: RenderItemPosition = 'static'
|
|
||||||
) {
|
|
||||||
super(type, false, false);
|
|
||||||
this.image = image;
|
|
||||||
this.setAntiAliasing(false);
|
|
||||||
|
|
||||||
if (window.DOMMatrix) {
|
|
||||||
this.patternTransform = new DOMMatrix();
|
|
||||||
} else if (window.WebKitCSSMatrix) {
|
|
||||||
this.patternTransform = new WebKitCSSMatrix();
|
|
||||||
} else {
|
|
||||||
this.patternTransform = new SVGMatrix();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private generatePattern() {
|
|
||||||
const pattern = this.requireCanvas();
|
|
||||||
const img = this.image;
|
|
||||||
pattern.size(32, 16);
|
|
||||||
pattern.withGameScale(false);
|
|
||||||
pattern.setHD(false);
|
|
||||||
pattern.setAntiAliasing(false);
|
|
||||||
const ctx = pattern.ctx;
|
|
||||||
ctx.drawImage(img, 144, 0, 32, 16, 0, 0, 32, 16);
|
|
||||||
const topPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
|
||||||
ctx.clearRect(0, 0, 32, 16);
|
|
||||||
ctx.drawImage(img, 144, 48, 32, 16, 0, 0, 32, 16);
|
|
||||||
const bottomPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
|
||||||
ctx.clearRect(0, 0, 32, 16);
|
|
||||||
pattern.size(16, 32);
|
|
||||||
ctx.drawImage(img, 128, 16, 16, 32, 0, 0, 16, 32);
|
|
||||||
const leftPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
|
||||||
ctx.clearRect(0, 0, 16, 32);
|
|
||||||
ctx.drawImage(img, 176, 16, 16, 32, 0, 0, 16, 32);
|
|
||||||
const rightPattern = ctx.createPattern(pattern.canvas, 'repeat');
|
|
||||||
if (!topPattern || !bottomPattern || !leftPattern || !rightPattern) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const winskinPattern: WinskinPatterns = {
|
|
||||||
top: topPattern,
|
|
||||||
bottom: bottomPattern,
|
|
||||||
left: leftPattern,
|
|
||||||
right: rightPattern
|
|
||||||
};
|
|
||||||
if (this.imageName) {
|
|
||||||
Winskin.patternMap.set(this.imageName, winskinPattern);
|
|
||||||
}
|
|
||||||
this.patternCache = winskinPattern;
|
|
||||||
this.deleteCanvas(pattern);
|
|
||||||
return winskinPattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getPattern() {
|
|
||||||
if (!this.imageName) {
|
|
||||||
if (this.patternCache) return this.patternCache;
|
|
||||||
return this.generatePattern();
|
|
||||||
} else {
|
|
||||||
const pattern = Winskin.patternMap.get(this.imageName);
|
|
||||||
if (pattern) return pattern;
|
|
||||||
return this.generatePattern();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(
|
|
||||||
canvas: MotaOffscreenCanvas2D,
|
|
||||||
_transform: Transform
|
|
||||||
): void {
|
|
||||||
const ctx = canvas.ctx;
|
|
||||||
const img = this.image;
|
|
||||||
const w = this.width;
|
|
||||||
const h = this.height;
|
|
||||||
const pad = this.borderSize / 2;
|
|
||||||
// 背景
|
|
||||||
ctx.drawImage(img, 0, 0, 128, 128, 2, 2, w - 4, h - 4);
|
|
||||||
const pattern = this.getPattern();
|
|
||||||
if (!pattern) return;
|
|
||||||
const { top, left, right, bottom } = pattern;
|
|
||||||
top.setTransform(this.patternTransform);
|
|
||||||
left.setTransform(this.patternTransform);
|
|
||||||
right.setTransform(this.patternTransform);
|
|
||||||
bottom.setTransform(this.patternTransform);
|
|
||||||
// 上下左右边框
|
|
||||||
ctx.save();
|
|
||||||
ctx.fillStyle = top;
|
|
||||||
ctx.translate(pad, 0);
|
|
||||||
ctx.fillRect(0, 0, w - pad * 2, pad);
|
|
||||||
ctx.fillStyle = bottom;
|
|
||||||
ctx.translate(0, h - pad);
|
|
||||||
ctx.fillRect(0, 0, w - pad * 2, pad);
|
|
||||||
ctx.fillStyle = left;
|
|
||||||
ctx.translate(-pad, pad * 2 - h);
|
|
||||||
ctx.fillRect(0, 0, pad, h - pad * 2);
|
|
||||||
ctx.fillStyle = right;
|
|
||||||
ctx.translate(w - pad, 0);
|
|
||||||
ctx.fillRect(0, 0, pad, h - pad * 2);
|
|
||||||
ctx.restore();
|
|
||||||
// 四个角的边框
|
|
||||||
ctx.drawImage(img, 128, 0, 16, 16, 0, 0, pad, pad);
|
|
||||||
ctx.drawImage(img, 176, 0, 16, 16, w - pad, 0, pad, pad);
|
|
||||||
ctx.drawImage(img, 128, 48, 16, 16, 0, h - pad, pad, pad);
|
|
||||||
ctx.drawImage(img, 176, 48, 16, 16, w - pad, h - pad, pad, pad);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置winskin图片
|
|
||||||
* @param image winskin图片
|
|
||||||
*/
|
|
||||||
setImage(image: SizedCanvasImageSource) {
|
|
||||||
this.image = image;
|
|
||||||
this.patternCache = void 0;
|
|
||||||
this.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过图片名称设置winskin
|
|
||||||
* @param name 图片名称
|
|
||||||
*/
|
|
||||||
setImageByName(name: ImageIds) {
|
|
||||||
const { loading } = Mota.require('@user/data-base');
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
this.imageName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置边框大小
|
|
||||||
* @param size 边框大小
|
|
||||||
*/
|
|
||||||
setBorderSize(size: number) {
|
|
||||||
this.borderSize = size;
|
|
||||||
this.patternTransform.a = size / 32;
|
|
||||||
this.patternTransform.d = size / 32;
|
|
||||||
this.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected handleProps(
|
|
||||||
key: string,
|
|
||||||
_prevValue: any,
|
|
||||||
nextValue: any
|
|
||||||
): boolean {
|
|
||||||
switch (key) {
|
|
||||||
case 'image':
|
|
||||||
if (!this.assertType(nextValue, 'string', key)) return false;
|
|
||||||
this.setImageByName(nextValue);
|
|
||||||
return true;
|
|
||||||
case 'borderSize':
|
|
||||||
if (!this.assertType(nextValue, 'number', key)) return false;
|
|
||||||
this.setBorderSize(nextValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -8,7 +8,6 @@ import {
|
|||||||
} from 'vue';
|
} from 'vue';
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
import {
|
import {
|
||||||
AnimateProps,
|
|
||||||
BaseProps,
|
BaseProps,
|
||||||
BezierProps,
|
BezierProps,
|
||||||
CirclesProps,
|
CirclesProps,
|
||||||
@ -18,10 +17,7 @@ import {
|
|||||||
CustomProps,
|
CustomProps,
|
||||||
DamageProps,
|
DamageProps,
|
||||||
EllipseProps,
|
EllipseProps,
|
||||||
IconProps,
|
|
||||||
ImageProps,
|
ImageProps,
|
||||||
LayerGroupProps,
|
|
||||||
LayerProps,
|
|
||||||
LineProps,
|
LineProps,
|
||||||
PathProps,
|
PathProps,
|
||||||
QuadraticProps,
|
QuadraticProps,
|
||||||
@ -29,8 +25,7 @@ import {
|
|||||||
RectRProps,
|
RectRProps,
|
||||||
ShaderProps,
|
ShaderProps,
|
||||||
SpriteProps,
|
SpriteProps,
|
||||||
TextProps,
|
TextProps
|
||||||
WinskinProps
|
|
||||||
} from './props';
|
} from './props';
|
||||||
import {
|
import {
|
||||||
ERenderItemEvent,
|
ERenderItemEvent,
|
||||||
@ -40,13 +35,8 @@ import {
|
|||||||
EShaderEvent
|
EShaderEvent
|
||||||
} from '@motajs/render-core';
|
} from '@motajs/render-core';
|
||||||
import {
|
import {
|
||||||
EIconEvent,
|
|
||||||
EImageEvent,
|
EImageEvent,
|
||||||
ETextEvent,
|
ETextEvent,
|
||||||
EWinskinEvent,
|
|
||||||
ELayerEvent,
|
|
||||||
ELayerGroupEvent,
|
|
||||||
EAnimateEvent,
|
|
||||||
EGraphicItemEvent
|
EGraphicItemEvent
|
||||||
} from '@motajs/render-elements';
|
} from '@motajs/render-elements';
|
||||||
|
|
||||||
@ -97,10 +87,7 @@ declare module 'vue/jsx-runtime' {
|
|||||||
image: TagDefine<ImageProps, EImageEvent>;
|
image: TagDefine<ImageProps, EImageEvent>;
|
||||||
comment: TagDefine<CommentProps, ERenderItemEvent>;
|
comment: TagDefine<CommentProps, ERenderItemEvent>;
|
||||||
custom: TagDefine<CustomProps, ERenderItemEvent>;
|
custom: TagDefine<CustomProps, ERenderItemEvent>;
|
||||||
layer: TagDefine<LayerProps, ELayerEvent>;
|
|
||||||
'layer-group': TagDefine<LayerGroupProps, ELayerGroupEvent>;
|
|
||||||
damage: TagDefine<DamageProps, ERenderItemEvent>;
|
damage: TagDefine<DamageProps, ERenderItemEvent>;
|
||||||
animation: TagDefine<AnimateProps, EAnimateEvent>;
|
|
||||||
'g-rect': TagDefine<RectProps, EGraphicItemEvent>;
|
'g-rect': TagDefine<RectProps, EGraphicItemEvent>;
|
||||||
'g-circle': TagDefine<CirclesProps, EGraphicItemEvent>;
|
'g-circle': TagDefine<CirclesProps, EGraphicItemEvent>;
|
||||||
'g-ellipse': TagDefine<EllipseProps, EGraphicItemEvent>;
|
'g-ellipse': TagDefine<EllipseProps, EGraphicItemEvent>;
|
||||||
@ -109,8 +96,6 @@ declare module 'vue/jsx-runtime' {
|
|||||||
'g-quad': TagDefine<QuadraticProps, EGraphicItemEvent>;
|
'g-quad': TagDefine<QuadraticProps, EGraphicItemEvent>;
|
||||||
'g-path': TagDefine<PathProps, EGraphicItemEvent>;
|
'g-path': TagDefine<PathProps, EGraphicItemEvent>;
|
||||||
'g-rectr': TagDefine<RectRProps, EGraphicItemEvent>;
|
'g-rectr': TagDefine<RectRProps, EGraphicItemEvent>;
|
||||||
icon: TagDefine<IconProps, EIconEvent>;
|
|
||||||
winskin: TagDefine<WinskinProps, EWinskinEvent>;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,8 @@ import {
|
|||||||
import {
|
import {
|
||||||
Comment,
|
Comment,
|
||||||
ETextEvent,
|
ETextEvent,
|
||||||
Icon,
|
|
||||||
Image,
|
Image,
|
||||||
Text,
|
Text,
|
||||||
Winskin,
|
|
||||||
Animate,
|
|
||||||
Layer,
|
|
||||||
LayerGroup,
|
|
||||||
BezierCurve,
|
BezierCurve,
|
||||||
Circle,
|
Circle,
|
||||||
Ellipse,
|
Ellipse,
|
||||||
@ -70,7 +65,7 @@ class RenderTagMap {
|
|||||||
|
|
||||||
export const tagMap = new RenderTagMap();
|
export const tagMap = new RenderTagMap();
|
||||||
|
|
||||||
const standardElement = (
|
export const standardElement = (
|
||||||
Item: new (
|
Item: new (
|
||||||
type: RenderItemPosition,
|
type: RenderItemPosition,
|
||||||
cache?: boolean,
|
cache?: boolean,
|
||||||
@ -91,7 +86,7 @@ const standardElement = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const standardElementNoCache = (
|
export const standardElementNoCache = (
|
||||||
Item: new (
|
Item: new (
|
||||||
type: RenderItemPosition,
|
type: RenderItemPosition,
|
||||||
cache?: boolean,
|
cache?: boolean,
|
||||||
@ -162,13 +157,13 @@ tagMap.register<ETextEvent, Text>('text', (_0, _1, props) => {
|
|||||||
return new Text(text, type);
|
return new Text(text, type);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const emptyImage = document.createElement('canvas');
|
||||||
|
emptyImage.width = 1;
|
||||||
|
emptyImage.height = 1;
|
||||||
tagMap.register('image', (_0, _1, props) => {
|
tagMap.register('image', (_0, _1, props) => {
|
||||||
if (!props) return new Image(core.material.images.images['bg.webp']);
|
if (!props) return new Image(emptyImage);
|
||||||
else {
|
else {
|
||||||
const {
|
const { image = emptyImage, type = 'static' } = props;
|
||||||
image = core.material.images.images['bg.webp'],
|
|
||||||
type = 'static'
|
|
||||||
} = props;
|
|
||||||
return new Image(image, type);
|
return new Image(image, type);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -199,44 +194,6 @@ tagMap.register('custom', (_0, _1, props) => {
|
|||||||
return item(props);
|
return item(props);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
tagMap.register('layer', (_0, _1, props) => {
|
|
||||||
if (!props) return new Layer();
|
|
||||||
else {
|
|
||||||
const { ex } = props;
|
|
||||||
const l = new Layer();
|
|
||||||
|
|
||||||
if (ex) {
|
|
||||||
(ex as any[]).forEach(v => {
|
|
||||||
l.extends(v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tagMap.register('layer-group', (_0, _1, props) => {
|
|
||||||
if (!props) return new LayerGroup();
|
|
||||||
else {
|
|
||||||
const { ex, layers } = props;
|
|
||||||
const l = new LayerGroup();
|
|
||||||
|
|
||||||
if (ex) {
|
|
||||||
(ex as any[]).forEach(v => {
|
|
||||||
l.extends(v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (layers) {
|
|
||||||
(layers as any[]).forEach(v => {
|
|
||||||
l.addLayer(v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tagMap.register('animation', (_0, _1, _props) => {
|
|
||||||
return new Animate();
|
|
||||||
});
|
|
||||||
tagMap.register('g-rect', standardElementNoCache(Rect));
|
tagMap.register('g-rect', standardElementNoCache(Rect));
|
||||||
tagMap.register('g-circle', standardElementNoCache(Circle));
|
tagMap.register('g-circle', standardElementNoCache(Circle));
|
||||||
tagMap.register('g-ellipse', standardElementNoCache(Ellipse));
|
tagMap.register('g-ellipse', standardElementNoCache(Ellipse));
|
||||||
@ -245,14 +202,3 @@ tagMap.register('g-bezier', standardElementNoCache(BezierCurve));
|
|||||||
tagMap.register('g-quad', standardElementNoCache(QuadraticCurve));
|
tagMap.register('g-quad', standardElementNoCache(QuadraticCurve));
|
||||||
tagMap.register('g-path', standardElementNoCache(Path));
|
tagMap.register('g-path', standardElementNoCache(Path));
|
||||||
tagMap.register('g-rectr', standardElementNoCache(RectR));
|
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']);
|
|
||||||
else {
|
|
||||||
const {
|
|
||||||
image = core.material.images.images['winskin.png'],
|
|
||||||
type = 'static'
|
|
||||||
} = props;
|
|
||||||
return new Winskin(image, type);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
@ -9,9 +9,6 @@ import {
|
|||||||
CustomContainerRenderFn
|
CustomContainerRenderFn
|
||||||
} from '@motajs/render-core';
|
} from '@motajs/render-core';
|
||||||
import {
|
import {
|
||||||
FloorLayer,
|
|
||||||
ILayerGroupRenderExtends,
|
|
||||||
ILayerRenderExtends,
|
|
||||||
BezierParams,
|
BezierParams,
|
||||||
CircleParams,
|
CircleParams,
|
||||||
EllipseParams,
|
EllipseParams,
|
||||||
@ -125,28 +122,6 @@ export interface CommentProps extends BaseProps {
|
|||||||
text?: string;
|
text?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LayerGroupProps extends BaseProps {
|
|
||||||
cellSize?: number;
|
|
||||||
blockSize?: number;
|
|
||||||
floorId?: FloorIds;
|
|
||||||
bindThisFloor?: boolean;
|
|
||||||
camera?: Transform;
|
|
||||||
ex?: readonly ILayerGroupRenderExtends[];
|
|
||||||
layers?: readonly FloorLayer[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LayerProps extends BaseProps {
|
|
||||||
layer?: FloorLayer;
|
|
||||||
mapWidth?: number;
|
|
||||||
mapHeight?: number;
|
|
||||||
cellSize?: number;
|
|
||||||
background?: AllNumbers;
|
|
||||||
floorImage?: FloorAnimate[];
|
|
||||||
ex?: readonly ILayerRenderExtends[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AnimateProps extends BaseProps {}
|
|
||||||
|
|
||||||
export interface DamageProps extends BaseProps {
|
export interface DamageProps extends BaseProps {
|
||||||
mapWidth?: number;
|
mapWidth?: number;
|
||||||
mapHeight?: number;
|
mapHeight?: number;
|
||||||
@ -255,19 +230,3 @@ export interface RectRProps extends GraphicPropsBase {
|
|||||||
*/
|
*/
|
||||||
ellipse?: RectREllipseParams;
|
ellipse?: RectREllipseParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IconProps extends BaseProps {
|
|
||||||
/** 图标 id 或数字 */
|
|
||||||
icon: AllNumbers | AllIds;
|
|
||||||
/** 显示图标的第几帧 */
|
|
||||||
frame?: number;
|
|
||||||
/** 是否开启动画,开启后 frame 参数无效 */
|
|
||||||
animate?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WinskinProps extends BaseProps {
|
|
||||||
/** winskin 的图片 id */
|
|
||||||
image: ImageIds;
|
|
||||||
/** 边框大小 */
|
|
||||||
borderSize?: number;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user