Compare commits

..

5 Commits

3 changed files with 424 additions and 637 deletions

View File

@ -1,6 +1,14 @@
import { DefaultProps, ElementLocator, GraphicPropsBase } from '@motajs/render'; import { DefaultProps, ElementLocator, GraphicPropsBase } from '@motajs/render';
import { SetupComponentOptions } from '@motajs/system-ui'; import { SetupComponentOptions } from '@motajs/system-ui';
import { computed, defineComponent, onMounted, Ref, ref, watch } from 'vue'; import {
computed,
defineComponent,
DefineSetupFnComponent,
onMounted,
Ref,
shallowRef,
watch
} from 'vue';
export interface IconsProps extends DefaultProps<GraphicPropsBase> { export interface IconsProps extends DefaultProps<GraphicPropsBase> {
loc: ElementLocator; loc: ElementLocator;
@ -11,14 +19,53 @@ const iconsProps = {
} satisfies SetupComponentOptions<IconsProps>; } satisfies SetupComponentOptions<IconsProps>;
type PathGenerator = (width: number, height: number) => Path2D; type PathGenerator = (width: number, height: number) => Path2D;
/** type PadFn = (
* @param ox divisor: number
* @param oy ) => [left: number, right: number, top: number, bottom: number];
* @param width type IconLoc = [
* @param height x: number,
*/ y: number,
type PathFn = (ox: number, oy: number, width: number, height: number) => Path2D; w: number,
h: number,
cx: number,
cy: number
];
/**
* @param loc
* @param pad
*/
type PathFn = (loc: IconLoc, pad: PadFn) => Path2D;
/**
*
* @param x
* @param y
* @param width
* @param height
* @param divisor `x + width / divisor`
*/
function pad(
x: number,
y: number,
width: number,
height: number,
divisor: number
): [left: number, right: number, top: number, bottom: number] {
return [
x + width / divisor, // left
x + width - width / divisor, // right
y + height / divisor, // top
y + height - height / divisor // bottom
];
}
/**
*
* @param aspect
* @param ref
* @param fn
*/
function adjustPath( function adjustPath(
aspect: number, aspect: number,
ref: Ref<Path2D | undefined>, ref: Ref<Path2D | undefined>,
@ -49,19 +96,57 @@ function adjustPath(
dw = height * aspect; dw = height * aspect;
ox = (width - dw) / 2; ox = (width - dw) / 2;
} }
path = fn(ox, oy, dw, dh); const cx = ox + dw / 2;
const cy = oy + dh / 2;
path = fn([ox, oy, dw, dh, cx, cy], divisor =>
pad(ox, oy, dw, dh, divisor)
);
ref.value = path; ref.value = path;
return path; return path;
}; };
} }
export const RollbackIcon = defineComponent<IconsProps>(props => { /**
const path = ref<Path2D>(); *
* @param aspect
* @param pathDef
* @param props
*/
export function defineIcon<T extends IconsProps>(
aspect: number,
pathDef: PathFn,
props: SetupComponentOptions<T> = iconsProps
): DefineSetupFnComponent<T> {
return defineComponent<T>(props => {
const path = shallowRef<Path2D>();
const width = computed(() => props.loc[2] ?? 200); const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200); const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => { const generatePath = adjustPath(aspect, path, pathDef);
watch(props, () => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => (
<g-path
loc={props.loc}
path={path.value}
stroke
lineJoin="round"
lineCap="round"
></g-path>
);
}, props);
}
export const RollbackIcon = defineIcon(1, loc => {
const path = new Path2D(); const path = new Path2D();
const [ox, oy, width, height] = loc;
const arc = width / 10; const arc = width / 10;
const arrow = width / 10; const arrow = width / 10;
const left = ox + width / 10; const left = ox + width / 10;
@ -82,34 +167,9 @@ export const RollbackIcon = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const RetweetIcon = defineIcon(1, loc => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
stroke
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const RetweetIcon = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const [ox, oy, width, height] = loc;
const arc = width / 10; const arc = width / 10;
const arrow = width / 10; const arrow = width / 10;
const left = ox + width / 10; const left = ox + width / 10;
@ -130,81 +190,22 @@ export const RetweetIcon = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const ViewMapIcon = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
stroke
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const ViewMapIcon = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const left = ox + width / 5; const [, , , , cx, cy] = loc;
const top = oy + height / 5; const [left, right, top, bottom] = pad(5);
const right = ox + width - width / 5;
const bottom = oy + height - height / 5;
const cx = ox + width / 2;
const cy = oy + height / 2;
path.rect(left, top, right - left, bottom - top); path.rect(left, top, right - left, bottom - top);
path.moveTo(cx, top); path.moveTo(cx, top);
path.lineTo(cx, bottom); path.lineTo(cx, bottom);
path.moveTo(left, cy); path.moveTo(left, cy);
path.lineTo(right, cy); path.lineTo(right, cy);
return path; return path;
}); });
watch(props, () => { export const DanmakuIcon = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
stroke
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const DanmakuIcon = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const left = ox + width / 5; const [, , width, height, cx, cy] = loc;
const bottom = oy + height - height / 5; const [left, , , bottom] = pad(5);
const cx = ox + width / 2;
const cy = oy + height / 2;
const rx = width / 3; const rx = width / 3;
const ry = height / 4; const ry = height / 4;
const start = (Math.PI * 16) / 18; const start = (Math.PI * 16) / 18;
@ -215,40 +216,11 @@ export const DanmakuIcon = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const ReplayIcon = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
stroke
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const ReplayIcon = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const [, , width, height, , cy] = loc;
const [left, right, top, bottom] = pad(5);
const arc = width / 10; const arc = width / 10;
const left = ox + width / 5;
const top = oy + height / 5;
const right = ox + width - width / 5;
const bottom = oy + height - height / 5;
const cy = oy + height / 2;
path.moveTo(right, cy - height / 8); path.moveTo(right, cy - height / 8);
path.lineTo(right, top + arc); path.lineTo(right, top + arc);
path.arcTo(right, top, right - arc, top, arc); path.arcTo(right, top, right - arc, top, arc);
@ -270,40 +242,10 @@ export const ReplayIcon = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const NumpadIcon = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
stroke
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const NumpadIcon = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const left = ox + width / 5; const [, , width, height, cx, cy] = loc;
const top = oy + height / 5; const [left, right, top, bottom] = pad(5);
const right = ox + width - width / 5;
const bottom = oy + height - height / 5;
const cx = ox + width / 2;
const cy = oy + height / 2;
path.rect(left, top, right - left, bottom - top); path.rect(left, top, right - left, bottom - top);
const path2 = new Path2D(); const path2 = new Path2D();
path2.ellipse(cx, cy, width / 9, height / 6, 0, 0, Math.PI * 2); path2.ellipse(cx, cy, width / 9, height / 6, 0, 0, Math.PI * 2);
@ -311,38 +253,10 @@ export const NumpadIcon = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const PlayIcon = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
stroke
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const PlayIcon = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const left = ox + width / 5; const [, oy, , height] = loc;
const top = oy + height / 5; const [left, right, top, bottom] = pad(5);
const right = ox + width - width / 5;
const bottom = oy + height - height / 5;
path.moveTo(left, top); path.moveTo(left, top);
path.lineTo(right, oy + height / 2); path.lineTo(right, oy + height / 2);
path.lineTo(left, bottom); path.lineTo(left, bottom);
@ -350,38 +264,10 @@ export const PlayIcon = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const PauseIcon = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
fill
stroke
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const PauseIcon = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const cx = ox + width / 2; const [, , width, , cx] = loc;
const top = oy + height / 5; const [, , top, bottom] = pad(5);
const bottom = oy + height - height / 5;
path.moveTo(cx - width / 5, top); path.moveTo(cx - width / 5, top);
path.lineTo(cx - width / 5, bottom); path.lineTo(cx - width / 5, bottom);
path.moveTo(cx + width / 5, top); path.moveTo(cx + width / 5, top);
@ -389,41 +275,11 @@ export const PauseIcon = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const DoubleArrow = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
stroke
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const DoubleArrow = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const path2 = new Path2D(); const path2 = new Path2D();
const left = ox + width / 5; const [, , width, height, cx, cy] = loc;
const top = oy + height / 5; const [left, right, top, bottom] = pad(5);
const right = ox + width - width / 5;
const bottom = oy + height - height / 5;
const cx = ox + width / 2;
const cy = oy + height / 2;
path.moveTo(left, top + height / 12); path.moveTo(left, top + height / 12);
path.lineTo(cx + width / 8, cy); path.lineTo(cx + width / 8, cy);
path.lineTo(left, bottom - height / 12); path.lineTo(left, bottom - height / 12);
@ -436,40 +292,11 @@ export const DoubleArrow = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const StepForward = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
stroke
fill
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const StepForward = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const path2 = new Path2D(); const path2 = new Path2D();
const left = ox + width / 5; const [, oy, , height] = loc;
const top = oy + height / 5; const [left, right, top, bottom] = pad(5);
const right = ox + width - width / 5;
const bottom = oy + height - height / 5;
path.moveTo(left, top); path.moveTo(left, top);
path.lineTo(right, oy + height / 2); path.lineTo(right, oy + height / 2);
path.lineTo(left, bottom); path.lineTo(left, bottom);
@ -480,35 +307,9 @@ export const StepForward = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const SoundVolume = defineIcon(1, loc => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
stroke
fill
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const SoundVolume = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const [ox, oy, width, height, cx, cy] = loc;
const left = ox + width / 8; const left = ox + width / 8;
const top = oy + height / 5; const top = oy + height / 5;
const bottom = oy + height - height / 5; const bottom = oy + height - height / 5;
@ -519,8 +320,6 @@ export const SoundVolume = defineComponent<IconsProps>(props => {
path.lineTo(width / 2, top); path.lineTo(width / 2, top);
path.lineTo(left + width / 6, height / 2 - height / 10); path.lineTo(left + width / 6, height / 2 - height / 10);
path.closePath(); path.closePath();
const cx = width / 2;
const cy = height / 2;
const start = -Math.PI / 4; const start = -Math.PI / 4;
const end = Math.PI / 4; const end = Math.PI / 4;
path.moveTo( path.moveTo(
@ -536,38 +335,10 @@ export const SoundVolume = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const Fullscreen = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
stroke
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const Fullscreen = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const left = ox + width / 4; const [, , width, height] = loc;
const right = ox + width - width / 4; const [left, right, top, bottom] = pad(4);
const top = oy + height / 4;
const bottom = oy + height - height / 4;
// 左上 // 左上
path.moveTo(left + width / 6, top + height / 6); path.moveTo(left + width / 6, top + height / 6);
@ -599,38 +370,10 @@ export const Fullscreen = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const ExitFullscreen = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value);
});
onMounted(() => {
generatePath(width.value, height.value);
});
return () => {
return (
<g-path
loc={props.loc}
path={path.value}
stroke
lineJoin="round"
lineCap="round"
></g-path>
);
};
}, iconsProps);
export const ExitFullscreen = defineComponent<IconsProps>(props => {
const path = ref<Path2D>();
const width = computed(() => props.loc[2] ?? 200);
const height = computed(() => props.loc[3] ?? 200);
const generatePath = adjustPath(1, path, (ox, oy, width, height) => {
const path = new Path2D(); const path = new Path2D();
const left = ox + width / 4; const [, , width, height] = loc;
const right = ox + width - width / 4; const [left, right, top, bottom] = pad(4);
const top = oy + height / 4;
const bottom = oy + height - height / 4;
// 左上 // 左上
path.moveTo(left + width / 6, top + height / 6); path.moveTo(left + width / 6, top + height / 6);
@ -662,23 +405,46 @@ export const ExitFullscreen = defineComponent<IconsProps>(props => {
return path; return path;
}); });
watch(props, () => { export const ArrowLeftTailless = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value); const path = new Path2D();
const [, , width] = loc;
const [left, right, top, bottom] = pad(4);
path.moveTo(right, top);
path.lineTo(left + width / 4, (top + right) / 2);
path.lineTo(right, bottom);
return path;
}); });
onMounted(() => { export const ArrowRightTailless = defineIcon(1, (loc, pad) => {
generatePath(width.value, height.value); const path = new Path2D();
const [, , width] = loc;
const [left, right, top, bottom] = pad(4);
path.moveTo(left, top);
path.lineTo(right - width / 4, (top + right) / 2);
path.lineTo(left, bottom);
return path;
}); });
return () => { export const ArrowUpTailless = defineIcon(1, (loc, pad) => {
return ( const path = new Path2D();
<g-path const [, , , height] = loc;
loc={props.loc} const [left, right, top, bottom] = pad(4);
path={path.value}
stroke path.moveTo(left, bottom);
lineJoin="round" path.lineTo((left + right) / 2, top + height / 4);
lineCap="round" path.lineTo(right, bottom);
></g-path> return path;
); });
};
}, iconsProps); export const ArrowDownTailless = defineIcon(1, (loc, pad) => {
const path = new Path2D();
const [, , , height] = loc;
const [left, right, top, bottom] = pad(4);
path.moveTo(left, top);
path.lineTo((left + right) / 2, bottom - height / 4);
path.lineTo(right, top);
return path;
});

View File

@ -26,6 +26,7 @@ import { ExitFullscreen, Fullscreen, SoundVolume } from '../components';
import { mainSetting, triggerFullscreen } from '@motajs/legacy-ui'; import { mainSetting, triggerFullscreen } from '@motajs/legacy-ui';
import { saveLoad } from './save'; import { saveLoad } from './save';
import { MainSceneUI } from './main'; import { MainSceneUI } from './main';
import { adjustCover } from '../utils';
const enum TitleButton { const enum TitleButton {
StartGame, StartGame,
@ -59,19 +60,12 @@ export const GameTitle = defineComponent<GameTitleProps>(props => {
const bg = core.material.images.images['bg.webp']; const bg = core.material.images.images['bg.webp'];
//#region 计算背景图 //#region 计算背景图
const aspect = bg.width / bg.height; const [width, height] = adjustCover(
const canvasAspect = MAIN_WIDTH / MAIN_HEIGHT; bg.width,
const [width, height] = (() => { bg.height,
if (canvasAspect > aspect) { MAIN_WIDTH,
const width = MAIN_WIDTH; MAIN_HEIGHT
const height = width / aspect; );
return [width, height];
} else {
const height = MAIN_HEIGHT;
const width = height * aspect;
return [width, height];
}
})();
//#region 标题设置 //#region 标题设置

View File

@ -57,3 +57,30 @@ export function adjustGrid(
locs locs
}; };
} }
/**
* `object-fit: cover`
* @param itemWidth
* @param itemHeight
* @param targetWidth
* @param targetHeight
* @returns
*/
export function adjustCover(
itemWidth: number,
itemHeight: number,
targetWidth: number,
targetHeight: number
): Readonly<LocArr> {
const aspect = itemWidth / itemHeight;
const canvasAspect = targetWidth / targetHeight;
if (canvasAspect > aspect) {
const width = targetWidth;
const height = width / aspect;
return [width, height];
} else {
const height = targetHeight;
const width = height * aspect;
return [width, height];
}
}