Skip to content

Commit

Permalink
feat: 新增菜单选项menus
Browse files Browse the repository at this point in the history
  • Loading branch information
hacxy committed Mar 15, 2024
1 parent f12edaa commit a8170b3
Show file tree
Hide file tree
Showing 16 changed files with 809 additions and 487 deletions.
13 changes: 13 additions & 0 deletions packages/oh-my-live2d/src/config/config.ts
Expand Up @@ -109,6 +109,19 @@ export const DEFAULT_OPTIONS: DefaultOptions = {
priority: 3,
message: ['你复制了什么内容呢?记得注明出处哦~']
}
},
menus: {
style: {
transition: 'all 500ms',
visibility: 'hidden',
opacity: 0,
position: 'absolute',
right: 0,
bottom: '10%',
zIndex: '9999',
fontSize: '26px'
},
itemStyle: {}
}
};

Expand Down
4 changes: 2 additions & 2 deletions packages/oh-my-live2d/src/index.ts
@@ -1,10 +1,10 @@
import './library/iconfont.js';
import { setup } from './modules/index.js';
import { bootstrap } from './modules/index.js';
import { loadScript } from './utils/index.js';

export * from './types/options.js';
// @ts-ignore
export const loadOml2d = setup(async () => {
export const loadOml2d = bootstrap(async () => {
// await loadUmdLibrary(importType, urls);
await loadScript({ url: 'https://lib.oml2d.com/complete.js', id: 'test' });
window.PIXI.utils.skipHello();
Expand Down
49 changes: 49 additions & 0 deletions packages/oh-my-live2d/src/modules/application.ts
@@ -0,0 +1,49 @@
import type { InternalModel, Live2DModel } from 'pixi-live2d-display';
import type { Application as ApplicationType } from 'pixi.js';

import type { PixiModule } from '../types/index.js';

export class Application {
app?: ApplicationType;
constructor(
// private options: DefaultOptions,
private PIXI: PixiModule
) {}

mount(canvasElement: HTMLCanvasElement, stageElement: HTMLElement, model?: Live2DModel<InternalModel>): void {
if (!this.app) {
this.app = new this.PIXI.Application({
view: canvasElement,
resolution: 2,
autoStart: true,
autoDensity: true,
backgroundAlpha: 0,
resizeTo: stageElement
});
}

if (model) {
this.clearAppStage();
this.app.stage.addChild(model);
} else {
console.error('挂载模型失败');
}
}

unMount(): void {
this.clearAppStage();
}

// 清除舞台中所有模型
clearAppStage(): void {
const childLen = this.app?.stage.children.length || 0;

if (childLen > 0) {
this.app!.stage.removeChildren(0, childLen - 1);
}
}

resize(): void {
this.app?.resize();
}
}
31 changes: 24 additions & 7 deletions packages/oh-my-live2d/src/modules/globalStyle.ts
Expand Up @@ -7,25 +7,42 @@ import { createElement } from '../utils/index.js';

// 全局样式
export class GlobalStyle {
styleSheet: HTMLElement;
styleSheet?: HTMLElement;
// options: DefaultOptions;
constructor(private options: DefaultOptions) {
// this.options = options;
// destroyElement(ELEMENT_ID.globalStyle);
}

// 创建
create(): void {
this.styleSheet = createElement({
tagName: 'style',
id: ELEMENT_ID.globalStyle,
innerHtml: generateGlobalStyle(this.options.primaryColor)
});
document.head.append(this.styleSheet);
}

reloadStyleSheet(): void {
this.styleSheet.innerHTML = generateGlobalStyle(this.options.primaryColor);
//挂载
mount(): void {
if (this.styleSheet) {
document.head.append(this.styleSheet);
}
}

initialize(options: DefaultOptions): void {
this.options = options;
// // 初始化
// update(options: DefaultOptions): void {
// this.options = options;
// this.reloadStyleSheet();
// }

initializeStyle(): void {
this.reloadStyleSheet();
}

// 重载样式表
reloadStyleSheet(): void {
if (this.styleSheet) {
this.styleSheet.innerHTML = generateGlobalStyle(this.options.primaryColor);
}
}
}
165 changes: 8 additions & 157 deletions packages/oh-my-live2d/src/modules/index.ts
@@ -1,171 +1,22 @@
// import { HitAreaFrames } from 'pixi-live2d-display/extra';
import type { Application } from 'pixi.js';
// import { isNumber, mergeDeep } from 'tianjie';

import { GlobalStyle } from './globalStyle.js';
import { Menus } from './menus.js';
import { Models } from './models.js';
import { Stage } from './stage.js';
import { StatusBar } from './status-bar.js';
import { Tips } from './tips.js';
import { OhMyLive2D } from './oml2d.js';
import { DEFAULT_OPTIONS } from '../config/index.js';
import type { DefaultOptions, LoadMethod, Options, PixiLive2dDisplayModule } from '../types/index.js';
import { checkVersion, mergeOptions, printProjectInfo } from '../utils/index.js';

export class OhMyLive2D {
// private stage: Stage;
// private statusBar: StatusBar;
// private tips: Tips;
// private menus: Menus;
private models: Models;
// private model: Models; // 当前模型的实例
// private modelIndex = 0; // 当前模型索引
// private windowSizeType: WindowSizeType = WindowSizeType.pc; // 当前窗口大小
// private mediaQuery = window.matchMedia('screen and (max-width: 768px)'); // 窗口大小的媒体查询

constructor(
private options: DefaultOptions,
private pixiLive2dDisplayModule: PixiLive2dDisplayModule,
private application: Application,
private stage: Stage,
private statusBar: StatusBar,
private tips: Tips,
private menus: Menus,
private globalStyle: GlobalStyle
// private Application: ApplicationType,
) {
this.initialize();
this.models = new Models(
this.application,
this.pixiLive2dDisplayModule.Live2DModel,
this.options,
this.stage,
this.statusBar,
this.tips,
this.menus
);

// this.destroy();
// import('../library/iconfont.js');
// new GlobalStyle({ primaryColor: this.options.primaryColor }); // 加载全局样式
// const defaultStatusBarColorInfo = {
// info: this.options.primaryColor,
// error: ''
// };
// this.stage = new Stage(this.options.parentElement, this.options.transitionTime); // 实例化舞台
// this.statusBar = new StatusBar(this.options.parentElement, defaultStatusBarColorInfo, this.options.primaryColor);
// this.tips = new Tips(this.stage.element, this.options.tips, this.options.primaryColor); // 提示框
// this.menus = new Menus(this.stage.element); // 菜单
// this.models = new Models(
// this.Application,
// this.pixiLive2dDisplayModule.Live2DModel,
// this.options,
// this.HitAreaFrames,
// this.stage,
// this.statusBar,
// this.tips,
// this.menus
// );
// this.initialize();
}

// 初始化
initialize(): void {
// 检查版本
void checkVersion();

// 打印信息
if (this.options.sayHello) {
printProjectInfo();
}

this.initializeModules();
// 注册事件
this.registerEvents();
}

// 初始化所有模块
initializeModules(): void {
this.stage.initialize(this.options);
this.statusBar.initialize(this.options);
this.globalStyle.initialize(this.options);
this.tips.initialize(this.options);
this.menus.initialize();
}

updateOptions(options: Options = {}): void {
this.options = mergeOptions(this.options, options);
this.initializeModules();
// void this.models.loadModel();
this.models.initialize();
}
import type { LoadMethod, Options } from '../types/index.js';
import { mergeOptions } from '../utils/index.js';

registerEvents(): void {
// 点击菜单按钮
this.menus.onClickItem((name) => {
switch (name) {
case 'Rest':
this.models.switchStatus();

return;
// 切换模型
case 'SwitchModel':
void this.models.loadNextModel();

return;

case 'About':
window.open('https://oml2d.com');

return;
}
});

// copy 事件
window.addEventListener('copy', () => {
this.tips.copy();
});

// 出场入场动画执行结束之后的事件回调
this.stage.onChangeSlideEnd((status) => {
if (status) {
this.tips.welcome();
}
});
}
}

export const setup = (loadMethod: LoadMethod): ((options: Options) => Promise<OhMyLive2D>) => {
let application: Application;
export const bootstrap = (loadMethod: LoadMethod): ((options: Options) => Promise<OhMyLive2D>) => {
let oml2d: OhMyLive2D;
const globalStyle = new GlobalStyle(DEFAULT_OPTIONS);
const stage = new Stage(DEFAULT_OPTIONS); // 实例化舞台
const statusBar = new StatusBar(DEFAULT_OPTIONS);
const tips = new Tips(stage.element, DEFAULT_OPTIONS); // 提示框
const menus = new Menus(stage.element); // 菜单

const loadOml2d = async (options: Options): Promise<OhMyLive2D> => {
const finalOptions = mergeOptions(DEFAULT_OPTIONS, options);
const { PixiLive2dDisplay, PIXI } = await loadMethod(finalOptions.importType, finalOptions.libraryUrls);
const { PixiLive2dDisplay, PIXI, HitAreaFrames } = await loadMethod(finalOptions.importType, finalOptions.libraryUrls);

if (!application) {
application = new PIXI.Application({
view: stage.canvasElement,
resolution: 2,
autoStart: true,
autoDensity: true,
backgroundAlpha: 0,
resizeTo: stage.element
});
}
if (oml2d) {
// oml2d.destroy();
oml2d.updateOptions();
// oml2d.updateOptions();
} else {
oml2d = new OhMyLive2D(finalOptions, PixiLive2dDisplay, application, stage, statusBar, tips, menus, globalStyle);
oml2d = new OhMyLive2D(finalOptions, PIXI, PixiLive2dDisplay, HitAreaFrames);
void oml2d.initialize();
}

// console.log(oml2d);
return oml2d;
};

Expand Down
79 changes: 79 additions & 0 deletions packages/oh-my-live2d/src/modules/live2d.ts
@@ -0,0 +1,79 @@
import type { InternalModel, Live2DModel } from 'pixi-live2d-display';
// import { MotionPreloadStrategy } from 'pixi-live2d-display';

import { MotionPreloadStrategy, WindowSizeType } from '../constants/index.js';
import type { DefaultOptions, Live2DModelType, ModelOptions } from '../types/index.js';
import { getWindowSizeType } from '../utils/index.js';

export class Models {
model?: Live2DModel<InternalModel>; // 当前模型实例
private currentModelIndex = 0;
constructor(private options: DefaultOptions) {}

get modelIndex(): number {
return this.currentModelIndex;
}
set modelIndex(index: number) {
this.currentModelIndex = index;
}

get currentModelOptions(): ModelOptions {
return this.options.models[this.modelIndex];
}

create(Live2dModel: Live2DModelType): Promise<void> {
return new Promise((resolve, reject) => {
this.model = Live2dModel.fromSync(this.currentModelOptions.path, {
motionPreload: (this.currentModelOptions.motionPreloadStrategy as MotionPreloadStrategy) || MotionPreloadStrategy.IDLE,
onError: reject
});

this.model.once('load', resolve);
});
}

// 设置模型
settingModel(): void {
switch (getWindowSizeType()) {
case WindowSizeType.mobile:
this.setPosition(...(this.currentModelOptions.mobilePosition || []));
this.setScale(this.currentModelOptions.mobileScale);
break;
case WindowSizeType.pc:
this.setPosition(...(this.currentModelOptions.position || []));
this.setScale(this.currentModelOptions.scale);
break;
}
}
// initializeStyle(): void {
// this.setScale();
// this.setPosition();
// }

// 模型尺寸
get modelSize(): { width: number; height: number } {
return {
width: this.model?.width || 0,
height: this.model?.height || 0
};
}

/**
* 设置缩放比例
* @param x
* @param y
*/
setScale(value: number = 0.1): void {
this.model?.scale.set(value, value);
}

/**
* 设置位置
* @param x
* @param y
*/
setPosition(x = 0, y = 0): void {
this.model!.x = x;
this.model!.y = y;
}
}

0 comments on commit a8170b3

Please sign in to comment.