feat: graphics框架 & patchProp

This commit is contained in:
unanmed 2024-11-27 21:19:46 +08:00
parent ac68d64f5f
commit 4a55255b74
7 changed files with 333 additions and 150 deletions

View File

@ -2,7 +2,6 @@ import { FloorItemDetail } from '@/plugin/fx/itemDetail';
import { FloorDamageExtends } from './preset/damage';
import { LayerDoorAnimate } from './preset/floor';
import { HeroRenderer } from './preset/hero';
import { LayerGroup, FloorLayer } from './preset/layer';
import { MotaRenderer } from './render';
import { LayerShadowExtends } from '../fx/shadow';
import { LayerGroupFilter } from '@/plugin/fx/gameCanvas';
@ -10,15 +9,10 @@ import { LayerGroupAnimate } from './preset/animate';
import { LayerGroupPortal } from '@/plugin/fx/portal';
import { LayerGroupHalo } from '@/plugin/fx/halo';
import { FloorViewport } from './preset/viewport';
import { Container } from './container';
import { PopText } from '@/plugin/fx/pop';
import { FloorChange } from '@/plugin/fallback';
import { onTick, render } from './renderer';
import { MotaOffscreenCanvas2D } from '../fx/canvas2d';
import { SpriteComponent } from './renderer/elements';
import { defineComponent, onActivated, onMounted, ref } from 'vue';
import { Ticker } from 'mutate-animate';
import { Sprite } from './sprite';
import { render } from './renderer';
import { defineComponent, ref } from 'vue';
let main: MotaRenderer;
@ -26,8 +20,6 @@ Mota.require('var', 'loading').once('coreInit', () => {
main = new MotaRenderer();
const Com = defineComponent(props => {
const group = ref<LayerGroup>();
return () => (
<container
id="map-draw"
@ -38,7 +30,6 @@ Mota.require('var', 'loading').once('coreInit', () => {
>
<layer-group
id="layer-main"
ref={group}
ex={[
new FloorDamageExtends(),
new FloorItemDetail(),
@ -72,53 +63,6 @@ Mota.require('var', 'loading').once('coreInit', () => {
main.hide();
render(<Com></Com>, main);
// const mapDraw = new Container();
// const layer = new LayerGroup();
// const pop = new PopText('static');
// const floorChange = new FloorChange('static');
// mapDraw.id = 'map-draw';
// layer.id = 'layer-main';
// pop.id = 'pop-main';
// floorChange.id = 'floor-change';
// mapDraw.setHD(true);
// mapDraw.setAntiAliasing(false);
// mapDraw.size(core._PX_, core._PY_);
// floorChange.size(480, 480);
// floorChange.setHD(true);
// floorChange.setZIndex(50);
// floorChange.setTips(tips);
// pop.setZIndex(80);
// ['bg', 'bg2', 'event', 'fg', 'fg2'].forEach(v => {
// layer.addLayer(v as FloorLayer);
// });
// const damage = new FloorDamageExtends();
// const hero = new HeroRenderer();
// const detail = new FloorItemDetail();
// const door = new LayerDoorAnimate();
// const shadow = new LayerShadowExtends();
// const filter = new LayerGroupFilter();
// const animate = new LayerGroupAnimate();
// const portal = new LayerGroupPortal();
// const halo = new LayerGroupHalo();
// const viewport = new FloorViewport();
// layer.extends(damage);
// layer.extends(detail);
// layer.extends(filter);
// layer.extends(portal);
// layer.extends(halo);
// layer.getLayer('event')?.extends(hero);
// layer.getLayer('event')?.extends(door);
// layer.getLayer('event')?.extends(shadow);
// layer.extends(animate);
// layer.extends(viewport);
// main.appendChild(mapDraw);
// mapDraw.appendChild(layer);
// layer.appendChild(pop);
// mapDraw.appendChild(floorChange);
console.log(main);
});

View File

@ -1,82 +1,267 @@
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
import { RenderItem } from '../item';
import { Transform } from '../transform';
import { ElementNamespace, ComponentInternalInstance } from 'vue';
type DrawType = 'fill' | 'stroke';
interface ILineProperty {
/** 线宽 */
lineWidth: number;
/** 线的虚线设置 */
lineDash?: number[];
/** 虚线偏移量 */
lineDashOffset?: number;
/** 线的连接样式 */
lineJoin: CanvasLineJoin;
/** 线的顶端样式 */
lineCap: CanvasLineCap;
/** 线的斜接限制当连接为miter类型时可填默认为10 */
miterLimit: number;
}
interface IGraphicProperty {
/** 渲染方式,是描边还是填充 */
mode: DrawType;
interface IGraphicProperty extends ILineProperty {
/** 渲染模式,可选 {@link GraphicMode.Fill}, {@link GraphicMode.Stroke}, {@link GraphicMode.All} */
mode: GraphicMode;
/** 填充样式 */
fill: CanvasStyle;
/** 描边样式 */
stroke: CanvasStyle;
}
export const enum GraphicMode {
/** 仅填充 */
Fill = 1,
/** 仅描边 */
Stroke = 2,
/** 填充+描边 */
All = 3
}
export class Graphics extends RenderItem {
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {}
}
/** 排序后的子元素 */
sortedChildren: RenderItem[] = [];
export class Rect extends RenderItem implements IGraphicProperty {
mode: DrawType = 'fill';
rectX: number = 0;
rectY: number = 0;
rectWidth: number = 100;
rectHeight: number = 100;
/** 是否需要重排 */
private needSort: boolean = false;
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {
const ctx = canvas.ctx;
ctx.rect(this.rectX, this.rectY, this.rectWidth, this.rectHeight);
this.sortedChildren.forEach(v => {
ctx.save();
v.renderContent(canvas, transform);
ctx.restore();
});
}
setPos(x: number, y: number) {
this.rectX = x;
this.rectY = y;
this.update();
/**
* Graphics元素添加子元素Graphics元素或基于GraphicItemBase的元素
* @param child
*/
appendChild(...child: RenderItem<any>[]): void {
child.forEach(v => {
// 如果是Graphics或GraphicItemBase实例则加入子元素列表否则抛出警告并忽略本次添加
if (v instanceof Graphics || v instanceof GraphicItemBase) {
} else {
}
});
}
setSize(w: number, h: number) {
this.rectWidth = w;
this.rectHeight = h;
this.update();
/**
*
*/
removeChild(...child: RenderItem<any>[]): void {}
/**
* zIndex进行重排
*/
requestSort(): void {
// 在下一帧渲染前进行排序
if (!this.needSort) {
this.needSort = true;
this.requestBeforeFrame(() => {});
}
}
}
export class Circle extends RenderItem implements IGraphicProperty {
mode: DrawType = 'fill';
export abstract class GraphicItemBase
extends RenderItem
implements IGraphicProperty
{
mode: number = GraphicMode.Fill;
fill: CanvasStyle = '#fff';
stroke: CanvasStyle = '#fff';
lineWidth: number = 2;
lineDash?: number[] | undefined;
lineDashOffset?: number | undefined;
lineJoin: CanvasLineJoin = 'bevel';
lineCap: CanvasLineCap = 'butt';
miterLimit: number = 10;
/**
*
* @param options 线
*/
setLineOption(options: Partial<ILineProperty>) {}
/**
*
* @param style
*/
setStyle(style: CanvasStyle) {}
/**
*
* @param mode
*/
setMode(mode: GraphicMode) {}
patchProp(
key: string,
prevValue: any,
nextValue: any,
namespace?: ElementNamespace,
parentComponent?: ComponentInternalInstance | null
): void {
switch (key) {
}
super.patchProp(key, prevValue, nextValue, namespace, parentComponent);
}
}
export class Rect extends GraphicItemBase {
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {}
patchProp(
key: string,
prevValue: any,
nextValue: any,
namespace?: ElementNamespace,
parentComponent?: ComponentInternalInstance | null
): void {
switch (key) {
}
super.patchProp(key, prevValue, nextValue, namespace, parentComponent);
}
}
export class Circle extends GraphicItemBase {
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {}
patchProp(
key: string,
prevValue: any,
nextValue: any,
namespace?: ElementNamespace,
parentComponent?: ComponentInternalInstance | null
): void {
switch (key) {
}
super.patchProp(key, prevValue, nextValue, namespace, parentComponent);
}
}
export class Ellipse extends GraphicItemBase {
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {}
patchProp(
key: string,
prevValue: any,
nextValue: any,
namespace?: ElementNamespace,
parentComponent?: ComponentInternalInstance | null
): void {
switch (key) {
}
super.patchProp(key, prevValue, nextValue, namespace, parentComponent);
}
}
export class Line extends GraphicItemBase {
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {}
patchProp(
key: string,
prevValue: any,
nextValue: any,
namespace?: ElementNamespace,
parentComponent?: ComponentInternalInstance | null
): void {
switch (key) {
}
super.patchProp(key, prevValue, nextValue, namespace, parentComponent);
}
}
export class BezierCurve extends GraphicItemBase {
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {}
patchProp(
key: string,
prevValue: any,
nextValue: any,
namespace?: ElementNamespace,
parentComponent?: ComponentInternalInstance | null
): void {
switch (key) {
}
super.patchProp(key, prevValue, nextValue, namespace, parentComponent);
}
}
export class QuadraticCurve extends GraphicItemBase {
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {}
patchProp(
key: string,
prevValue: any,
nextValue: any,
namespace?: ElementNamespace,
parentComponent?: ComponentInternalInstance | null
): void {
switch (key) {
}
super.patchProp(key, prevValue, nextValue, namespace, parentComponent);
}
}
export class Path extends GraphicItemBase {
/** 路径 */
path: Path2D = new Path2D();
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {}
patchProp(
key: string,
prevValue: any,
nextValue: any,
namespace?: ElementNamespace,
parentComponent?: ComponentInternalInstance | null
): void {
switch (key) {
}
export class Ellipse extends RenderItem implements IGraphicProperty {
mode: DrawType = 'fill';
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {}
super.patchProp(key, prevValue, nextValue, namespace, parentComponent);
}
export class Line extends RenderItem implements IGraphicProperty {
mode: DrawType = 'fill';
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {}
}
export class Path extends RenderItem implements IGraphicProperty {
mode: DrawType = 'fill';
protected render(
canvas: MotaOffscreenCanvas2D,
transform: Transform
): void {}
}

View File

@ -159,6 +159,20 @@ export class Image extends RenderItem<EImageEvent> {
this.image = image;
this.update();
}
patchProp(
key: string,
prevValue: any,
nextValue: any,
namespace?: ElementNamespace,
parentComponent?: ComponentInternalInstance | null
): void {
switch (key) {
case 'image':
this.setImage(nextValue);
return;
}
}
}
export class Comment extends RenderItem {

View File

@ -10,14 +10,22 @@ import EventEmitter from 'eventemitter3';
import {
AnimateProps,
BaseProps,
BezierProps,
CirclesProps,
CommentProps,
ContainerProps,
CustomProps,
DamageProps,
EllipseProps,
GL2Props,
GraphicsProps,
ImageProps,
LayerGroupProps,
LayerProps,
LineProps,
PathProps,
QuadraticProps,
RectProps,
ShaderProps,
SpriteProps,
TextProps
@ -65,19 +73,6 @@ type TagDefine<T extends object, E extends ERenderItemEvent> = T &
MappingEvent<E> &
ReservedProps;
export type RenderItemComponent = _Define<BaseProps, ERenderItemEvent>;
export type SpriteComponent = _Define<SpriteProps, ESpriteEvent>;
export type ContainerComponent = _Define<ContainerProps, EContainerEvent>;
export type GL2Component = _Define<GL2Props, EGL2Event>;
export type ShaderComponent = _Define<ShaderProps, EShaderEvent>;
export type TextComponent = _Define<TextProps, ETextEvent>;
export type ImageComponent = _Define<ImageProps, EImageEvent>;
export type CommentComponent = _Define<CommentProps, ERenderItemEvent>;
export type LayerGroupComponent = _Define<LayerGroupProps, ELayerGroupEvent>;
export type LayerComponent = _Define<LayerProps, ELayerEvent>;
export type AnimateComponent = _Define<AnimateProps, EAnimateEvent>;
export type DamageComponent = _Define<DamageProps, EDamageEvent>;
declare module 'vue/jsx-runtime' {
namespace JSX {
export interface IntrinsicElements {
@ -92,6 +87,14 @@ declare module 'vue/jsx-runtime' {
'layer-group': TagDefine<LayerGroupProps, ELayerGroupEvent>;
damage: TagDefine<DamageProps, EDamageEvent>;
animate: TagDefine<AnimateProps, EAnimateEvent>;
graphics: TagDefine<GraphicsProps, ERenderItemEvent>;
'g-rect': TagDefine<RectProps, ERenderItemEvent>;
'g-circle': TagDefine<CirclesProps, ERenderItemEvent>;
'g-ellipse': TagDefine<EllipseProps, ERenderItemEvent>;
'g-line': TagDefine<LineProps, ERenderItemEvent>;
'g-bezier': TagDefine<BezierProps, ERenderItemEvent>;
'g-quad': TagDefine<QuadraticProps, ERenderItemEvent>;
'g-path': TagDefine<PathProps, ERenderItemEvent>;
}
}
}

View File

@ -1,5 +1,5 @@
import { logger } from '@/core/common/logger';
import { ERenderItemEvent, RenderItem } from '../item';
import { ERenderItemEvent, RenderItem, RenderItemPosition } from '../item';
import { ElementNamespace, VNodeProps } from 'vue';
import { Container } from '../container';
import { MotaRenderer } from '../render';
@ -7,6 +7,17 @@ import { Sprite } from '../sprite';
import { Comment, Image, Text } from '../preset/misc';
import { Shader } from '../shader';
import { Animate, Damage, EDamageEvent, Layer, LayerGroup } from '../preset';
import {
BezierCurve,
Circle,
Ellipse,
Graphics,
Line,
Path,
QuadraticCurve,
Rect
} from '../preset/graphics';
import { BaseProps } from './props';
type OnItemCreate<
E extends ERenderItemEvent = ERenderItemEvent,
@ -48,32 +59,32 @@ class RenderTagMap {
export const tagMap = new RenderTagMap();
// Default elements
tagMap.register('container', (_0, _1, props) => {
if (!props) return new Container();
const standardElement = (
Item: new (
type: RenderItemPosition,
cache?: boolean,
fall?: boolean
) => RenderItem
) => {
return (_0: any, _1: any, props?: any) => {
if (!props) return new Item('static');
else {
const {
type = 'static',
enableCache = true,
fallthrough = false
} = props;
return new Container(type, enableCache, fallthrough);
return new Item(type, enableCache, fallthrough);
}
});
};
};
// Default elements
tagMap.register('container', standardElement(Container));
tagMap.register('mota-renderer', (_0, _1, props) => {
return new MotaRenderer(props?.id);
});
tagMap.register('sprite', (_0, _1, props) => {
if (!props) return new Sprite();
else {
const {
type = 'static',
enableCache = true,
fallthrough = false
} = props;
return new Sprite(type, enableCache, fallthrough);
}
});
tagMap.register('sprite', standardElement(Sprite));
tagMap.register('text', (_0, _1, props) => {
if (!props) return new Text();
else {
@ -159,3 +170,11 @@ tagMap.register<EDamageEvent, Damage>('damage', (_0, _1, props) => {
tagMap.register('animate', (_0, _1, props) => {
return new Animate();
});
tagMap.register('graphics', standardElement(Graphics));
tagMap.register('g-rect', standardElement(Rect));
tagMap.register('g-circle', standardElement(Circle));
tagMap.register('g-ellipse', standardElement(Ellipse));
tagMap.register('g-line', standardElement(Line));
tagMap.register('g-bezier', standardElement(BezierCurve));
tagMap.register('g-quad', standardElement(QuadraticCurve));
tagMap.register('g-path', standardElement(Path));

View File

@ -25,6 +25,8 @@ export interface BaseProps {
hidden?: boolean;
transform?: Transform;
type?: RenderItemPosition;
enableCache?: boolean;
fallthrough?: boolean;
id?: string;
alpha?: number;
composite?: GlobalCompositeOperation;
@ -87,3 +89,19 @@ export interface DamageProps extends BaseProps {
strokeStyle?: string;
strokeWidth?: number;
}
export interface GraphicsProps extends BaseProps {}
export interface RectProps extends BaseProps {}
export interface CirclesProps extends BaseProps {}
export interface EllipseProps extends BaseProps {}
export interface LineProps extends BaseProps {}
export interface BezierProps extends BaseProps {}
export interface QuadraticProps extends BaseProps {}
export interface PathProps extends BaseProps {}

View File

@ -11,7 +11,7 @@ const FSHOST = 'http://127.0.0.1:3000/';
const custom = [
'container', 'image', 'sprite', 'shader', 'text', 'comment', 'custom',
'layer', 'layer-group', 'animate', 'damage'
'layer', 'layer-group', 'animate', 'damage', 'graphics'
]
// https://vitejs.dev/config/
@ -22,7 +22,7 @@ export default defineConfig({
}),
vuejsx({
isCustomElement: (tag) => {
return custom.includes(tag)
return custom.includes(tag) || tag.startsWith('g-');
}
}),
legacy({