diff --git a/.github/workflows/page.yml b/.github/workflows/page.yml index a8e4950..e5aa123 100644 --- a/.github/workflows/page.yml +++ b/.github/workflows/page.yml @@ -27,7 +27,7 @@ jobs: run: | npm i -g pnpm@7.27.0 pnpm i - pnpm build-gh + pnpm build # 执行部署 - name: 部署 diff --git a/.gitignore b/.gitignore index 833f8af..dcbb758 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,20 @@ index.cjs !public/swap/*.h5save _bundle out -dist-resource \ No newline at end of file +dist-resource +_temp +dam1.png +dam2.png +dam3.png +dam4.png +meeting.md + +*.csv +script/special.ts +script/people.ts +user.ts +.antlr +graph.svg +docs/.vitepress/cache +docs/.vitepress/dist +docs/.vitepress/apiSidebar.ts diff --git a/.madgerc b/.madgerc new file mode 100644 index 0000000..edc2560 --- /dev/null +++ b/.madgerc @@ -0,0 +1,12 @@ +{ + "fileExtensions": [ + "ts", + "tsx" + ], + "tsConfig": "./tsconfig.json", + "detectiveOptions": { + "ts": { + "skipTypeImports": true + } + } +} \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index 264740c..3e797de 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,4 +5,12 @@ public/project/floors/*.js public/project/items.js public/project/floors/*.js public/project/maps.js -script/**/*.js \ No newline at end of file +public/project/icons.js +public/project/enemys.js +public/_server/**/*.js +script/**/*.js +public/editor.html +keyCodes.ts +src/core/main/setting.ts +src/core/fx/shadow.ts +dist/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..6ff0062 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,13 @@ +{ + "printWidth": 80, + "tabWidth": 4, + "useTabs": false, + "semi": true, + "singleQuote": true, + "quoteProps": "as-needed", + "bracketSpacing": true, + "vueIndentScriptAndStyle": false, + "arrowParens": "avoid", + "trailingComma": "none", + "endOfLine": "auto" +} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json index a7cea0b..4c8f1f8 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,9 @@ { - "recommendations": ["Vue.volar"] + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "vue.volar", + "slevesque.shader", + "tobermory.es6-string-html" + ] } diff --git a/LICENSE b/LICENSE index c6e2e54..0a04128 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,165 @@ -MIT License + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 -Copyright (c) 2023 unanmed + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/components.d.ts b/components.d.ts index 46765fe..49dd79b 100644 --- a/components.d.ts +++ b/components.d.ts @@ -7,7 +7,9 @@ export {} declare module '@vue/runtime-core' { export interface GlobalComponents { + AButton: typeof import('ant-design-vue/es')['Button'] ADivider: typeof import('ant-design-vue/es')['Divider'] + AInput: typeof import('ant-design-vue/es')['Input'] AProgress: typeof import('ant-design-vue/es')['Progress'] ASelect: typeof import('ant-design-vue/es')['Select'] ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] @@ -17,6 +19,7 @@ declare module '@vue/runtime-core' { BoxAnimate: typeof import('./src/components/boxAnimate.vue')['default'] Colomn: typeof import('./src/components/colomn.vue')['default'] EnemyOne: typeof import('./src/components/enemyOne.vue')['default'] + Minimap: typeof import('./src/components/minimap.vue')['default'] Scroll: typeof import('./src/components/scroll.vue')['default'] } } diff --git a/docs/.vitepress/api.ts b/docs/.vitepress/api.ts new file mode 100644 index 0000000..287f72d --- /dev/null +++ b/docs/.vitepress/api.ts @@ -0,0 +1,97 @@ +import fs from 'fs-extra'; +import path from 'path'; +import chokidar from 'chokidar'; +import { DefaultTheme } from 'vitepress'; + +const apiDir = path.resolve('./docs/api'); +const sidebarConfigPath = path.resolve('./docs/.vitepress/apiSidebar.ts'); + +const weight: Record = { + 主页: 10, + 函数: 5 +}; + +function generateSidebar(): void { + const sidebar: DefaultTheme.SidebarItem[] = [ + { text: '目录', link: '/api/' } + ]; + + // 遍历 api 目录,查找 package 目录 + const packages = fs + .readdirSync(apiDir) + .filter(pkg => fs.statSync(path.join(apiDir, pkg)).isDirectory()); + + packages.forEach(pkg => { + const pkgPath = path.join(apiDir, pkg); + const files = fs + .readdirSync(pkgPath) + .filter(file => file.endsWith('.md')); + + const items: DefaultTheme.SidebarItem[] = files.map(file => { + const filePath = `api/${pkg}/${file}`; + const fileName = path.basename(file, '.md'); + + return { + text: + fileName === 'index' + ? '主页' + : fileName === 'functions' + ? '函数' + : fileName, + link: `/${filePath.replace(/\\/g, '/')}` // 兼容 Windows 路径 + }; + }); + + items.sort((a, b) => { + const titleA = a.text ?? ''; + const titleB = b.text ?? ''; + return (weight[titleB] ?? 0) - (weight[titleA] ?? 0); + }); + + sidebar.push({ + text: pkg, + collapsed: true, + items + }); + }); + + // 生成 sidebar.ts + const sidebarContent = `import { DefaultTheme } from 'vitepress'; + +export default ${JSON.stringify( + sidebar, + null, + 4 + )} as DefaultTheme.SidebarItem[];`; + fs.writeFileSync(sidebarConfigPath, sidebarContent); + console.log('✅ Sidebar 配置已更新'); +} + +// 初次运行 +generateSidebar(); + +// 监听文件变动 +chokidar + .watch(apiDir, { ignoreInitial: true }) + .on('add', filePath => { + console.log(`📄 文件新增: ${filePath}`); + generateSidebar(); + }) + .on('unlink', filePath => { + console.log(`❌ 文件删除: ${filePath}`); + generateSidebar(); + }) + .on('addDir', dirPath => { + console.log(`📁 目录新增: ${dirPath}`); + generateSidebar(); + }) + .on('unlinkDir', dirPath => { + console.log(`📁 目录删除: ${dirPath}`); + generateSidebar(); + }) + .on('raw', (event, path, details) => { + if (event === 'rename') { + console.log(`🔄 文件或文件夹重命名: ${path}`); + generateSidebar(); + } + }); diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 0000000..bccf639 --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,119 @@ +import { defineConfig } from 'vitepress'; +import { MermaidMarkdown, MermaidPlugin } from 'vitepress-plugin-mermaid'; +import api from './apiSidebar'; + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + title: 'HTML5 魔塔样板 V2.B', + description: 'HTML5 魔塔样板 V2.B 帮助文档', + base: '/_docs/', + markdown: { + math: true, + config(md) { + md.use(MermaidMarkdown); + } + }, + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + outline: [2, 3], + nav: [ + { text: '主页', link: '/' }, + { text: '指南', link: '/guide/diff' }, + { text: 'API', link: '/api/' }, + { text: '错误代码', link: '/logger/' } + ], + sidebar: { + '/guide/': [ + { + text: '深度指南', + items: [ + { text: '差异说明', link: '/guide/diff' }, + { text: '系统说明', link: '/guide/system' }, + { text: '代码编写', link: '/guide/coding' }, + { + text: 'UI 系统', + collapsed: false, + items: [ + { text: 'UI 编写', link: '/guide/ui' }, + { text: 'UI 优化', link: '/guide/ui-perf' }, + { text: 'UI 系统', link: '/guide/ui-system' }, + { text: 'UI 元素', link: '/guide/ui-elements' }, + { text: 'UI 常见问题', link: '/guide/ui-faq' } + ] + }, + { text: '音频系统', link: '/guide/audio' } + ] + } + ], + '/logger/': [ + { + text: '错误代码一览', + items: [ + { + text: '错误代码', + collapsed: false, + items: [ + { text: '1-50', link: '/logger/error/error1' } + ] + }, + { + text: '警告代码', + collapsed: false, + items: [ + { text: '1-50', link: '/logger/warn/warn1' }, + { text: '51-100', link: '/logger/warn/warn2' } + ] + } + ] + } + ], + '/api/': [ + { + text: 'API 列表', + items: api + } + ] + }, + socialLinks: [ + { icon: 'github', link: 'https://github.com/unanmed/HumanBreak' } + ], + search: { + provider: 'local', + options: { + locales: { + zh: { + translations: { + button: { + buttonText: '搜索文档', + buttonAriaLabel: '搜索文档' + }, + modal: { + noResultsText: '无法找到相关结果', + resetButtonTitle: '清除查询条件', + footer: { + selectText: '选择', + navigateText: '切换' + } + } + } + } + } + } + } + }, + locales: { + root: { + lang: 'zh', + label: '中文' + } + }, + vite: { + plugins: [MermaidPlugin()], + optimizeDeps: { + include: ['mermaid'] + }, + ssr: { + noExternal: ['mermaid'] + } + } +}); diff --git a/docs/.vitepress/theme.css b/docs/.vitepress/theme.css new file mode 100644 index 0000000..4d1d650 --- /dev/null +++ b/docs/.vitepress/theme.css @@ -0,0 +1,7 @@ +.mermaid { + max-width: 600px; /* 限制最大宽度 */ + max-height: 400px; /* 限制最大高度 */ + overflow: auto; /* 允许滚动以防止超出 */ + display: block; + margin: 0 auto; +} diff --git a/docs/api/index.md b/docs/api/index.md new file mode 100644 index 0000000..d4948fa --- /dev/null +++ b/docs/api/index.md @@ -0,0 +1,32 @@ +--- +lang: zh-CN +--- + +# API 列表 + +- [@motajs/client](./motajs-client) 渲染层代码 +- [@motajs/client-base](./motajs-client-base) 渲染层底层代码 +- [@motajs/common](./motajs-common) 渲染层和数据层通用代码 +- [@motajs/legacy-client](./motajs-legacy-client) 遗留渲染层代码 +- [@motajs/legacy-common](./motajs-legacy-common) 遗留通用代码 +- [@motajs/legacy-data](./motajs-legacy-data) 遗留数据层代码 +- [@motajs/legacy-system](./motajs-legacy-system) 遗留渲染层系统代码 +- [@motajs/legacy-ui](./motajs-legacy-ui) 遗留 UI 相关代码 +- [@motajs/render](./motajs-render) 渲染系统代码 +- [@motajs/render-core](./motajs-render-core) 渲染系统核心代码 +- [@motajs/render-elements](./motajs-render-elements) 渲染系统内置元素代码 +- [@motajs/render-style](./motajs-render-style) 渲染系统样式代码 +- [@motajs/render-vue](./motajs-render-vue) 渲染系统 vue 支持代码 +- [@motajs/system](./motajs-system) 渲染层系统代码 +- [@motajs/system-action](./motajs-system-action) 渲染层交互系统代码 +- [@motajs/system-ui](./motajs-system-ui) 渲染层 UI 系统代码 +- [@motajs/types](./motajs-types) 渲染层类型代码 +- [@user/client-modules](./user-client-modules) 用户渲染层主要代码 +- [@user/data-base](./user-data-base) 用户数据层底层代码 +- [@user/data-fallback](./user-data-fallback) 用户数据层向后兼容代码 +- [@user/data-state](./user-data-state) 用户数据层状态代码 +- [@user/data-utils](./user-data-utils) 用户数据层工具代码 +- [@user/entry-client](./user-entry-client) 用户渲染层入口 +- [@user/entry-data](./user-entry-data) 用户数据层入口 +- [@user/legacy-plugin-client](./user-legacy-plugin-client) 用户遗留渲染层代码 +- [@user/legacy-plugin-data](./user-legacy-plugin-data) 用户遗留数据层代码 diff --git a/docs/api/motajs-client-base/KeyCode.md b/docs/api/motajs-client-base/KeyCode.md new file mode 100644 index 0000000..b73bbd2 --- /dev/null +++ b/docs/api/motajs-client-base/KeyCode.md @@ -0,0 +1,3 @@ +# KeyCode + +参考 `monaco-editor` 文档 [KeyCode](https://microsoft.github.io/monaco-editor/docs.html#enums/KeyCode.html) diff --git a/docs/api/motajs-client-base/index.md b/docs/api/motajs-client-base/index.md new file mode 100644 index 0000000..163dbb2 --- /dev/null +++ b/docs/api/motajs-client-base/index.md @@ -0,0 +1,5 @@ +# @motajs/client-base + +目录: + +- [KeyCode](./KeyCode.md) diff --git a/docs/api/motajs-client/index.md b/docs/api/motajs-client/index.md new file mode 100644 index 0000000..5c5b673 --- /dev/null +++ b/docs/api/motajs-client/index.md @@ -0,0 +1,13 @@ +# @motajs/client + +`@motajs/client` 包含多个模块: + +- [`@motajs/client-base`](../motajs-client-base/) + +示例: + +```ts +import { KeyCode } from '@motajs/client'; + +const { KeyCOde } = Mota.require('@motajs/client'); +``` diff --git a/docs/api/motajs-common/Logger.md b/docs/api/motajs-common/Logger.md new file mode 100644 index 0000000..4d5bc70 --- /dev/null +++ b/docs/api/motajs-common/Logger.md @@ -0,0 +1,212 @@ +# Logger + +本文档由 `DeepSeek R1` 模型生成并微调。 + +## 属性说明 + +| 属性名 | 类型 | 默认值 | 说明 | +| --------- | ------------- | ------ | ---------------------------------------------------------------- | +| `enabled` | `boolean` | `true` | 控制日志输出是否启用。设为 `false` 可临时关闭日志输出。 | +| `level` | `LogLevel` | - | 日志级别,决定输出的最低日志等级(通过构造函数传入,不可修改)。 | +| `info` | `ILoggerInfo` | - | 包含错误和警告信息的配置对象(通过构造函数传入,不可修改)。 | + +## 方法说明 + +### `constructor` + +```ts +function constructor(level: LogLevel, info: ILoggerInfo): Logger; +``` + +#### 描述 + +构造一个 `Logger` 实例。 + +#### 参数 + +- `level`: 日志对象输出等级。 +- `info`: 日志内容。 + +### `error` + +```ts +function error(code: number, ...params: string[]): void; +``` + +#### 描述 + +记录一个错误信息。 + +#### 参数 + +- `code`: 错误代码,对应 `info.error` 中的键值。 +- `...params`: 替换错误信息中的占位符(如 $1, $2)的参数。 + +#### 行为 + +- 如果未找到对应 `code` 的错误信息,会触发 `error(16)` 表示代码未定义。 +- 根据日志级别 `level` 决定是否输出到控制台 + +### `warn` + +```ts +function warn(code: number, ...params: string[]): void; +``` + +#### 描述 + +记录一个警告信息。 + +#### 参数 + +- `code`: 警告代码,对应 `info.warn` 中的键值。 +- `...params`: 替换警告信息中的占位符的参数。 + +#### 行为 + +- 如果未找到对应 `code` 的警告信息,会触发 `error(16)`。 +- 仅在 `level <= LogLevel.WARNING` 时输出。 + +### `log` + +```ts +function log(text: string): void; +``` + +#### 描述 + +记录一条普通日志。 + +#### 参数 + +`text`: 日志文本内容。 + +#### 行为 + +- 仅在 `level <= LogLevel.LOG` 时输出到控制台。 + +### `catch` + +```ts +function catch(fn: () => T): LoggerCatchReturns; +``` + +#### 描述 + +捕获函数执行期间产生的日志信息,并抑制日志输出。 + +#### 参数 + +- `fn`: 需要执行的函数。 + +#### 返回值 + +- `ret`: 函数 `fn` 的返回值。 +- `info`: 捕获的日志信息数组。 + +#### 行为 + +- 执行期间会临时禁用日志输出,执行完成后恢复原有状态。 + +### `disable` + +```ts +function disable(): void; +``` + +#### 描述 + +禁用日志输出(设置 `enabled = false`)。 + +### `enable` + +```ts +function enable(): void; +``` + +#### 描述 + +启用日志输出(设置 `enabled = true`)。 + +## 接口说明 + +### `LoggerCatchInfo` + +#### 结构 + +```ts +interface LoggerCatchInfo { + /** 错误/警告代码(仅 error/warn 方法存在) */ + code?: number; + /** 日志等级 */ + level: LogLevel; + /** 解析后的完整信息 */ + message: string; +} +``` + +### `LoggerCatchReturns` + +#### 结构 + +```ts +interface LoggerCatchReturns { + /** 被捕获函数的返回值 */ + ret: T; + /** 捕获的日志信息列表 */ + info: LoggerCatchInfo[]; +} +``` + +## 使用示例 + +- 初始化 Logger + +```ts +import { LogLevel, Logger } from './logger'; + +const logInfo = { + error: { + 404: 'Page $1 not found.', + 500: 'Internal server error: $1' + }, + warn: { + 101: 'Deprecated API: $1' + } +}; + +const logger = new Logger(LogLevel.WARNING, logInfo); +``` + +- 记录错误 + +```ts +logger.error(404, 'home'); +// 控制台输出: [ERROR Code 404] Page home not found. +``` + +- 记录警告 + +```ts +logger.warn(101, '/old-api'); +// 控制台输出: [WARNING Code 101] Deprecated API: /old-api +``` + +- 捕获日志 + +```ts +const result = logger.catch(() => { + logger.error(500, 'database timeout'); + return { success: false }; +}); + +console.log(result.info[0].message); // "Internal server error: database timeout" +``` + +- 禁用日志 + +```ts +logger.disable(); +logger.log('This will not be printed'); // 无输出 +logger.enable(); +``` diff --git a/docs/api/motajs-common/functions.md b/docs/api/motajs-common/functions.md new file mode 100644 index 0000000..f34cf50 --- /dev/null +++ b/docs/api/motajs-common/functions.md @@ -0,0 +1,24 @@ +# @motajs/common 函数 + +## `sleep` + +```ts +function sleep(time: number): Promise; +``` + +#### 描述 + +创建一个等待指定时长的异步。 + +#### 参数 + +- `time`: 等待时长 + +#### 使用示例 + +```ts +async function myFunc() { + await sleep(1000); + // 这后面的内容会在 1 秒之后执行 +} +``` diff --git a/docs/api/motajs-common/index.md b/docs/api/motajs-common/index.md new file mode 100644 index 0000000..dd45248 --- /dev/null +++ b/docs/api/motajs-common/index.md @@ -0,0 +1,11 @@ +# @motajs/common + +目录: + +- [函数](./functions.md) + +--- + +类目录: + +- [Logger](./Logger.md) diff --git a/docs/api/motajs-legacy-client/index.md b/docs/api/motajs-legacy-client/index.md new file mode 100644 index 0000000..aa9f43e --- /dev/null +++ b/docs/api/motajs-legacy-client/index.md @@ -0,0 +1,3 @@ +# @motajs/legacy-client + +目录: diff --git a/docs/api/motajs-legacy-common/Patch.md b/docs/api/motajs-legacy-common/Patch.md new file mode 100644 index 0000000..214153d --- /dev/null +++ b/docs/api/motajs-legacy-common/Patch.md @@ -0,0 +1,120 @@ +# Patch API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +## 类描述 + +`Patch` 类用于对旧版接口的函数实现进行动态重写,支持按模块类别批量修改目标类的原型方法。需配合 `PatchClass` 枚举指定要修改的模块类型。 + +--- + +## 泛型说明 + +- `T extends PatchClass`: 表示要修改的模块类别(如 `PatchClass.Actions` 对应动作模块) + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| ------------ | ---- | ---------------------------- | +| `patchClass` | `T` | 只读,当前补丁关联的模块类别 | + +--- + +## 构造方法 + +```typescript +function constructor(patchClass: T): Patch; +``` + +- **参数** + - `patchClass`: 指定要修改的模块类别(从 `PatchClass` 枚举中选择) + +**示例** + +```typescript +// 创建针对控制模块的补丁 +const patch = new Patch(PatchClass.Control); +``` + +--- + +## 方法说明 + +### `add` + +```typescript +function add( + key: K, + patch: PatchList[T][K] +): void; +``` + +为目标模块添加函数补丁。 + +- **参数** + - `key`: 要修改的函数名(需为目标模块原型存在的函数) + - `patch`: 新的函数实现 + +**示例** + +```typescript +// 重写控制模块的 setFlag 方法 +control.add('setFlag', function (this: Control, key, value) { + console.log('执行重写后的 setFlag 代码'); + if (typeof value === 'number') { + // 数字额外增加 100 点 + core.status.hero.flags[key] = value + 100; + } else { + core.status.hero.flags[key] = value; + } +}); +``` + +--- + +### `Patch.patchAll` + +```typescript +function patchAll(): void; +``` + +**静态方法**:应用所有未执行的补丁修改。一般不需要自己调用,游戏启动阶段已经包含了此方法的调用。 + +--- + +### `Patch.patch` + +```typescript +function patch(patch: Patch): void; +``` + +**静态方法**:立即应用指定补丁实例的修改。一般不需要自己调用,游戏启动阶段已经包含了此方法的调用。 + +- **参数** + - `patch`: 要应用的补丁实例 + +--- + +## 总使用示例 + +```typescript +import { Patch, PatchClass } from '@motajs/legacy-common'; + +// 新建函数,这个操作是必要的,我们不能直接在顶层使用这个接口 +export function patchMyFunctions() { + // 创建 Patch 实例,参数表示这个 Patch 示例要重写哪个文件中的函数 + // 如果需要复写两个文件,那么就需要创建两个实例 + const patch = new Patch(PatchClass.Control); + + // 使用 add 函数来重写,第一个参数会有自动补全 + // 如果要重写的函数以下划线开头,可能会有报错 + // 这时候需要去 types/declaration 中对应的文件中添加声明 + patch.add('getFlag', (name, defaultValue) => { + // 重写 getFlag,如果变量是数字,那么 +100 后返回 + const value = core.status?.hero?.flags[name] ?? defaultValue; + return typeof value === 'number' ? value + 100 : value; + }); +} +``` diff --git a/docs/api/motajs-legacy-common/index.md b/docs/api/motajs-legacy-common/index.md new file mode 100644 index 0000000..2b112e3 --- /dev/null +++ b/docs/api/motajs-legacy-common/index.md @@ -0,0 +1,3 @@ +# @motajs/legacy-common + +目录: diff --git a/docs/api/motajs-legacy-system/index.md b/docs/api/motajs-legacy-system/index.md new file mode 100644 index 0000000..914499d --- /dev/null +++ b/docs/api/motajs-legacy-system/index.md @@ -0,0 +1,3 @@ +# @motajs/legacy-system + +目录: diff --git a/docs/api/motajs-legacy-ui/index.md b/docs/api/motajs-legacy-ui/index.md new file mode 100644 index 0000000..e1375f5 --- /dev/null +++ b/docs/api/motajs-legacy-ui/index.md @@ -0,0 +1,3 @@ +# @motajs/legacy-ui + +目录: diff --git a/docs/api/motajs-render-core/Container.md b/docs/api/motajs-render-core/Container.md new file mode 100644 index 0000000..25bed56 --- /dev/null +++ b/docs/api/motajs-render-core/Container.md @@ -0,0 +1,121 @@ +# Container 类 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 继承关系 + +```mermaid +graph LR + Container --> RenderItem --> EventEmitter + + click RenderItem "./RenderItem" + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +## 属性说明 + +| 属性名 | 类型 | 默认值 | 说明 | +| ---------------- | -------------- | ------ | ------------------------------ | +| `sortedChildren` | `RenderItem[]` | `[]` | 按 `zIndex` 排序后的子元素列表 | + +--- + +## 构造方法 + +### `constructor` + +**参数** + +- `type`: 渲染模式(`absolute` 绝对定位 / `static` 跟随摄像机) +- `cache`: 是否启用渲染缓存 +- `fall`: 是否启用变换矩阵下穿机制 + +**示例** + +```typescript +const container = new Container('static'); +``` + +--- + +## 方法说明 + +### `appendChild` + +```typescript +function appendChild(...children: RenderItem[]): void; +``` + +**描述** +添加子元素并触发重新排序。 +**示例** + +```typescript +const child = new RenderItem('static'); +container.appendChild(child); // 添加子元素 +``` + +--- + +### `removeChild` + +```typescript +function removeChild(...child: RenderItem[]): void; +``` + +**描述** +移除指定子元素并触发重新排序。 +**示例** + +```typescript +container.removeChild(child); // 移除子元素 +``` + +--- + +### `requestSort` + +```typescript +function requestSort(): void; +``` + +**描述** +标记需要重新排序子元素(在下一帧前自动执行)。 + +--- + +### `forEachChild` + +```typescript +function forEachChild(fn: (ele: RenderItem) => void): void; +``` + +**描述** +遍历元素的每一个子元素(DFS 遍历),并对每一个元素执行函数。 + +--- + +## 总使用示例 + +```typescript +// 创建基础容器 +const baseContainer = new Container('absolute'); +baseContainer.size(800, 600); + +// 添加子元素 +const sprite1 = new Sprite('static'); +sprite1.pos(100, 100).setZIndex(2); +baseContainer.appendChild(sprite1); + +const sprite2 = new Sprite('static'); +sprite2.pos(200, 200).setZIndex(1); +baseContainer.appendChild(sprite2); + +// 将容器添加到根元素 +rootElement.appendChild(baseContainer); + +// 动态修改子元素层级 +sprite1.setZIndex(0); // 自动触发重新排序 +``` diff --git a/docs/api/motajs-render-core/ContainerCustom.md b/docs/api/motajs-render-core/ContainerCustom.md new file mode 100644 index 0000000..f269f73 --- /dev/null +++ b/docs/api/motajs-render-core/ContainerCustom.md @@ -0,0 +1,71 @@ +# ContainerCustom 类 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 继承关系 + +```mermaid +graph LR + ContainerCustom --> Container --> RenderItem --> EventEmitter + + click Container "./Container" + click RenderItem "./RenderItem" + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 属性说明 + +| 属性名 | 类型 | 默认值 | 说明 | +| ---------- | ------------------------- | ----------- | ---------------------- | +| `renderFn` | `CustomContainerRenderFn` | `undefined` | 自定义渲染函数(可选) | + +--- + +## 构造方法 + +继承自 `Container`,参数与父类一致。 + +--- + +## 方法说明 + +### `setRenderFn` + +```typescript +function setRenderFn(render?: CustomContainerRenderFn): void; +``` + +**描述** +设置自定义渲染函数,覆盖默认的子元素渲染逻辑。 +**参数** + +- `render`: 接收画布、子元素列表和变换矩阵的回调函数 + +**示例** + +```typescript +customContainer.setRenderFn((canvas, children, transform) => { + children.forEach(child => { + child.renderContent(canvas, transform); + }); +}); +``` + +--- + +## 总使用示例 + +```ts +// 创建自定义容器 +const customContainer = new ContainerCustom('static'); +customContainer.setRenderFn((canvas, children) => { + // 倒序渲染子元素 + children.reverse().forEach(child => { + child.renderContent(canvas, Transform.identity); + }); +}); +``` diff --git a/docs/api/motajs-render-core/Event.md b/docs/api/motajs-render-core/Event.md new file mode 100644 index 0000000..bfe4894 --- /dev/null +++ b/docs/api/motajs-render-core/Event.md @@ -0,0 +1,201 @@ +# Event 模块 API 文档 + +以下内容由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 枚举说明 + +### MouseType + +| 值 | 说明 | +| --------- | ---------------- | +| `None` | 没有按键按下 | +| `Left` | 左键 | +| `Middle` | 中键(按下滚轮) | +| `Right` | 右键 | +| `Back` | 侧键后退 | +| `Forward` | 侧键前进 | + +### WheelType + +| 值 | 说明 | +| ------- | -------------------------- | +| `None` | 无单位 | +| `Pixel` | 以像素为单位 | +| `Line` | 以行为单位(约 1rem) | +| `Page` | 以页为单位(一个屏幕高度) | + +### ActionType + +| 值 | 说明 | +| ------- | -------------------------------- | +| `Click` | 点击事件(按下与抬起在同一元素) | +| `Down` | 鼠标或手指按下事件 | +| `Move` | 鼠标或手指移动事件 | +| `Up` | 鼠标或手指抬起事件 | +| `Enter` | 进入元素时触发 | +| `Leave` | 离开元素时触发 | +| `Wheel` | 滚轮事件 | + +### EventProgress + +| 值 | 说明 | +| --------- | -------- | +| `Capture` | 捕获阶段 | +| `Bubble` | 冒泡阶段 | + +--- + +## 接口说明 + +### IActionEventBase + +| 属性名 | 类型 | 说明 | +| ---------- | ------------ | ----------------------------------------------------------------- | +| `target` | `RenderItem` | 触发事件的元素 | +| `touch` | `boolean` | 是否为触摸操作(`true` 表示触摸,`false` 表示鼠标) | +| `type` | `MouseType` | 触发事件的按键类型(参考 `MouseType`) | +| `buttons` | `number` | 当前按下的按键(通过位运算判断,例如 `buttons & MouseType.Left`) | +| `altKey` | `boolean` | 是否按下 `Alt` 键 | +| `shiftKey` | `boolean` | 是否按下 `Shift` 键 | +| `ctrlKey` | `boolean` | 是否按下 `Ctrl` 键 | +| `metaKey` | `boolean` | 是否按下 `Windows/Command` 键 | + +--- + +### IActionEvent + +#### 继承关系 + +```mermaid +graph LR + IActionEvent --> IActionEventBase +``` + +| 属性名 | 类型 | 说明 | +| ------------ | -------- | -------------------------------------------- | +| `identifier` | `number` | 操作的唯一标识符(在按下、移动、抬起中一致) | +| `offsetX` | `number` | 相对于元素左上角的横坐标 | +| `offsetY` | `number` | 相对于元素左上角的纵坐标 | +| `absoluteX` | `number` | 相对于整个画布左上角的横坐标 | +| `absoluteY` | `number` | 相对于整个画布左上角的纵坐标 | + +#### 方法说明 + +##### `stopPropagation` + +```typescript +function stopPropagation(): void; +``` + +**描述** +停止事件的传播(捕获或冒泡阶段)。 + +**示例** + +```typescript +item.on('click', ev => { + ev.stopPropagation(); // 阻止事件继续传播 +}); +``` + +--- + +### IWheelEvent + +```mermaid +graph LR + IWheelEvent --> IActionEvent --> IActionEventBase +``` + +| 属性名 | 类型 | 说明 | +| ----------- | ----------- | -------------------- | +| `wheelX` | `number` | 横向滚动量 | +| `wheelY` | `number` | 纵向滚动量 | +| `wheelZ` | `number` | 垂直屏幕方向的滚动量 | +| `wheelType` | `WheelType` | 滚动量的单位类型 | + +--- + +### ERenderItemActionEvent + +描述了所有的交互事件类型。 + +| 事件名 | 参数类型 | 说明 | +| -------------- | ---------------------------- | ------------------ | +| `clickCapture` | `Readonly` | 点击事件的捕获阶段 | +| `click` | `Readonly` | 点击事件的冒泡阶段 | +| `downCapture` | `Readonly` | 按下事件的捕获阶段 | +| `down` | `Readonly` | 按下事件的冒泡阶段 | +| `moveCapture` | `Readonly` | 移动事件的捕获阶段 | +| `move` | `Readonly` | 移动事件的冒泡阶段 | +| `upCapture` | `Readonly` | 抬起事件的捕获阶段 | +| `up` | `Readonly` | 抬起事件的冒泡阶段 | +| `enter` | `Readonly` | 进入元素事件 | +| `leave` | `Readonly` | 离开元素事件 | +| `wheelCapture` | `Readonly` | 滚轮事件的捕获阶段 | +| `wheel` | `Readonly` | 滚轮事件的冒泡阶段 | + +--- + +### ActionEventMap + +| 键(ActionType) | 值类型 | 说明 | +| ---------------- | -------------- | ------------ | +| `Click` | `IActionEvent` | 点击事件 | +| `Down` | `IActionEvent` | 按下事件 | +| `Enter` | `IActionEvent` | 进入元素事件 | +| `Leave` | `IActionEvent` | 离开元素事件 | +| `Move` | `IActionEvent` | 移动事件 | +| `Up` | `IActionEvent` | 抬起事件 | +| `Wheel` | `IWheelEvent` | 滚轮事件 | + +--- + +## 总使用示例 + +::: code-group + +```typescript +// 创建渲染元素(以 Sprite 为例) +const item = new Sprite(); + +// 监听点击事件(冒泡阶段) +item.on('click', ev => { + console.log('点击坐标:', ev.offsetX, ev.offsetY); + ev.stopPropagation(); // 阻止冒泡 +}); + +// 监听滚轮事件(捕获阶段) +item.on('wheelCapture', ev => { + console.log('滚轮滚动量:', ev.wheelY, '单位:', WheelType[ev.wheelType]); +}); + +// 监听进入元素事件 +item.on('enter', ev => { + console.log('进入元素,触发按键:', MouseType[ev.type]); +}); +``` + +```tsx +// 监听点击事件(冒泡阶段) +const click = (ev: IActionEvent) => { + console.log('点击坐标:', ev.offsetX, ev.offsetY); + ev.stopPropagation(); // 阻止冒泡 +}; + +// 监听滚轮事件(捕获阶段) +const wheel = (ev: IWheelEvent) => { + console.log('滚轮滚动量:', ev.wheelY, '单位:', WheelType[ev.wheelType]); +}; + +// 监听进入元素事件 +const enter = (ev: IActionEventBase) => { + console.log('进入元素,触发按键:', MouseType[ev.type]); +}; + +; +``` + +::: diff --git a/docs/api/motajs-render-core/GL2.md b/docs/api/motajs-render-core/GL2.md new file mode 100644 index 0000000..a8964a3 --- /dev/null +++ b/docs/api/motajs-render-core/GL2.md @@ -0,0 +1,151 @@ +# GL2 类 API 文档 + +**需丰富** + +本文档由 `DeepSeek R1` 模型生成并微调。 + +## 继承关系 + +```mermaid +graph LR + GL2 --> RenderItem --> EventEmitter + + click RenderItem "./RenderItem" + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 属性说明 + +| 属性名 | 类型 | 默认值 | 说明 | +| ------------------------------- | ------------------------ | ------------------ | --------------------------------------------- | +| `support` | `boolean`(静态) | 检测 WebGL2 支持性 | 标识当前环境是否支持 WebGL2 | +| `canvas` | `HTMLCanvasElement` | - | 绑定的 WebGL2 画布元素 | +| `gl` | `WebGL2RenderingContext` | - | WebGL2 渲染上下文 | +| `UNIFORM_1f` ~ `UNIFORM_4uiv` | `UniformType` 枚举 | 对应枚举值 | WebGL uniform 类型常量(共 25 种) | +| `U_MATRIX_2x2` ~ `U_MATRIX_4x4` | `UniformMatrix` 枚举 | 对应枚举值 | 矩阵类型 uniform 常量(9 种) | +| `ATTRIB_1f` ~ `ATTRIB_I4uiv` | `AttribType` 枚举 | 对应枚举值 | 顶点属性类型常量(12 种) | +| `MAX_TEXTURE_COUNT` | `number` | `0` | 最大纹理支持数量(实际值由 WebGL 上下文决定) | + +--- + +## 构造方法 + +### `constructor` + +**参数** + +- `type`: 渲染模式(`absolute` 绝对定位 / `static` 跟随摄像机) + +**行为** + +- 初始化 WebGL2 上下文 +- 自动检测 WebGL2 支持性(通过静态属性 `support`) +- 设置默认渲染模式 + +--- + +## 方法说明 + +### `createProgram` + +```typescript +function createProgram( + Program: ProgramConstructor, + vs?: string, + fs?: string +): T; +``` + +**描述** +创建 WebGL 着色器程序 +**参数** + +- `Program`: 着色器程序类(需继承 `GL2Program`) +- `vs`: 自定义顶点着色器代码(可选) +- `fs`: 自定义片元着色器代码(可选) + **示例** + +```typescript +class MyProgram extends GL2Program {} +const program = gl2.createProgram(MyProgram); +``` + +--- + +### `useProgram` + +```typescript +function useProgram(program: GL2Program): void; +``` + +**描述** +切换当前使用的着色器程序 +**示例** + +```typescript +gl2.useProgram(shaderProgram); +``` + +--- + +### `framebuffer` + +```typescript +function framebuffer( + name: string, + texture: IShaderTexture2D, + clear?: boolean +): void; +``` + +**描述** +将渲染结果输出到帧缓冲纹理 +**参数** + +- `name`: 帧缓冲名称 +- `texture`: 目标纹理对象 +- `clear`: 是否清空画布 + +--- + +### `drawScene`(抽象方法) + +```typescript +function drawScene( + canvas: MotaOffscreenCanvas2D, + gl: WebGL2RenderingContext, + program: GL2Program, + transform: Transform +): void; +``` + +**描述** +抽象渲染方法,子类必须实现具体绘制逻辑 + +--- + +## 静态方法说明 + +### `GL2.support` + +```typescript +static readonly support: boolean; +``` + +**描述** +静态只读属性,检测 WebGL2 支持性 +**示例** + +```typescript +if (GL2.support) { + // 初始化 WebGL2 功能 +} +``` + +--- + +## 总使用示例 + +暂时没有。 diff --git a/docs/api/motajs-render-core/GL2Program.md b/docs/api/motajs-render-core/GL2Program.md new file mode 100644 index 0000000..742140d --- /dev/null +++ b/docs/api/motajs-render-core/GL2Program.md @@ -0,0 +1,188 @@ +# GL2Program 类 API 文档 + +**需丰富** + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 继承关系 + +```mermaid +graph LR + GL2Program --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 属性说明 + +| 属性名 | 类型 | 说明 | +| -------------- | ------------------------ | ------------------------------------------ | +| `gl` | `WebGL2RenderingContext` | WebGL2 渲染上下文 | +| `element` | `GL2` | 关联的 GL2 渲染元素 | +| `program` | `WebGLProgram \| null` | WebGL 着色器程序对象 | +| `renderMode` | `RenderMode` | 当前渲染模式(默认 `RenderMode.Elements`) | +| `usingIndices` | `IShaderIndices \| null` | 当前使用的顶点索引数组 | + +--- + +## 方法说明 + +### `defineUniform` + +```typescript +function defineUniform( + uniform: string, + type: T +): IShaderUniform | null; +``` + +**描述** +定义 Uniform 变量 +**参数** + +- `uniform`: Uniform 变量名 +- `type`: Uniform 类型(如 `GL2.UNIFORM_2f`) + **返回值** +- 操作对象(可设置值)或 `null`(定义失败) + +--- + +### `defineTexture` + +```typescript +function defineTexture( + name: string, + index: number, + w?: number, + h?: number +): IShaderTexture2D | null; +``` + +**描述** +定义纹理对象 +**参数** + +- `name`: 纹理名称 +- `index`: 纹理索引(建议不超过 8) +- `w`: 纹理宽度(可选) +- `h`: 纹理高度(可选) + **示例** + +```typescript +const tex = program.defineTexture('diffuse', 0, 512, 512); +``` + +--- + +### `paramElements` + +```typescript +function paramElements( + mode: GLenum, + count: number, + type: GLenum, + offset: number +): void; +``` + +**描述** +设置元素模式渲染参数 +**参数** + +- `mode`: 渲染模式(如 `gl.TRIANGLES`) +- `count`: 元素数量 +- `type`: 数据类型(如 `gl.UNSIGNED_SHORT`) +- `offset`: 数据偏移量 + +--- + +### `requestCompile` + +```typescript +function requestCompile(force?: boolean): boolean; +``` + +**描述** +请求编译着色器 +**参数** + +- `force`: 是否强制重新编译 + **返回值** +- `true` 表示编译成功 + +--- + +### `vs` + +```typescript +function vs(vs: string): void; +``` + +**描述** +设置顶点着色器代码 +**示例** + +```typescript +program.vs(` + ${GL2_PREFIX.VERTEX} + in vec4 aPosition; + void main() { + gl_Position = aPosition; + } +`); +``` + +--- + +## 事件说明 + +| 事件名 | 触发时机 | 参数类型 | +| -------- | ---------------- | -------- | +| `load` | 程序被加载使用时 | `[]` | +| `unload` | 程序被卸载时 | `[]` | + +--- + +## 总使用示例 + +```typescript +// 创建着色器程序 +const program = gl2.createProgram(GL2Program); + +// 定义着色器 +program.vs(` + ${GL2_PREFIX.VERTEX} + uniform mat4 uProjection; + in vec4 aPosition; + void main() { + gl_Position = uProjection * aPosition; + } +`); + +program.fs(` + ${GL2_PREFIX.FRAGMENT} + out vec4 fragColor; + uniform vec3 uColor; + void main() { + fragColor = vec4(uColor, 1.0); + } +`); + +// 定义 Uniform 和纹理 +const colorUniform = program.defineUniform('uColor', UniformType.Uniform3f); +const diffuseTex = program.defineTexture('diffuse', 0, 512, 512); + +// 设置渲染参数 +program.paramElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); + +// 编译并应用 +if (program.requestCompile()) { + gl2.useProgram(program); + colorUniform?.set(1.0, 0.5, 0.2); + diffuseTex?.set(imageElement); +} +``` diff --git a/docs/api/motajs-render-core/MotaOffscreenCanvas2D.md b/docs/api/motajs-render-core/MotaOffscreenCanvas2D.md new file mode 100644 index 0000000..09ea584 --- /dev/null +++ b/docs/api/motajs-render-core/MotaOffscreenCanvas2D.md @@ -0,0 +1,311 @@ +# MotaOffscreenCanvas2D 类 API 文档 + +以下内容由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 继承关系 + +```mermaid +graph LR + MotaOffscreenCanvas2D --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 属性说明 + +| 属性名 | 类型 | 默认值 | 说明 | +| ---------------- | -------------------------- | -------- | ------------------------------------------- | +| `canvas` | `HTMLCanvasElement` | - | 关联的 HTML 画布元素 | +| `ctx` | `CanvasRenderingContext2D` | - | 画布的 2D 渲染上下文 | +| `width` | `number` | 自动计算 | 画布的逻辑宽度(不包含缩放比例) | +| `height` | `number` | 自动计算 | 画布的逻辑高度(不包含缩放比例) | +| `autoScale` | `boolean` | `false` | 是否自动跟随 `core.domStyle.scale` 进行缩放 | +| `highResolution` | `boolean` | `true` | 是否启用高清画布(根据设备像素比例缩放) | +| `antiAliasing` | `boolean` | `true` | 是否启用抗锯齿 | +| `scale` | `number` | `1` | 当前画布的缩放比例 | +| `symbol` | `number` | `0` | 更新标识符,值变化表示画布被被动清空或调整 | +| `freezed` | `boolean`(只读) | `false` | 当前画布是否被冻结(冻结后不可修改属性) | +| `active` | `boolean`(只读) | `true` | 当前画布是否处于激活状态 | + +--- + +## 构造方法 + +### `constructor` + +```ts +function constructor( + alpha: boolean = true, + canvas?: HTMLCanvasElement +): MotaOffscreenCanvas2D; +``` + +**描述** +创建一个新的离屏画布。 +**参数** + +- `alpha`: 是否启用透明度通道(默认为 `true`)。 +- `canvas`: 可指定现有画布,未提供时自动创建新画布。 + **注意** +- 在自定义渲染元素中,建议使用 `RenderItem.requireCanvas` 而非直接调用此构造函数。 + +--- + +## 方法说明 + +### `size` + +```ts +function size(width: number, height: number): void; +``` + +**描述** +设置画布的尺寸。 +**参数** + +- `width`: 逻辑宽度(最小为 1)。 +- `height`: 逻辑高度(最小为 1)。 + **行为** +- 自动计算缩放比例(考虑 `highResolution` 和 `autoScale`)。 +- 调整画布物理尺寸和样式尺寸。 + +**示例** + +```typescript +const canvas = new MotaOffscreenCanvas2D(); +canvas.size(800, 600); // 设置画布尺寸为 800x600(逻辑尺寸) +``` + +--- + +### `withGameScale` + +```ts +function withGameScale(auto: boolean): void; +``` + +**描述** +设置画布是否跟随 `core.domStyle.scale` 自动缩放。 +**参数** + +- `auto`: 是否启用自动缩放。 + +**示例** + +```typescript +canvas.withGameScale(true); // 启用自动缩放 +``` + +--- + +### `setHD` + +```ts +function setHD(hd: boolean): void; +``` + +**描述** +设置是否为高清画布(基于设备像素比例)。 +**参数** + +- `hd`: 是否启用高清模式。 + +**示例** + +```typescript +canvas.setHD(false); // 关闭高清模式 +``` + +--- + +### `setAntiAliasing` + +```ts +function setAntiAliasing(anti: boolean): void; +``` + +**描述** +设置抗锯齿功能。 +**参数** + +- `anti`: 是否启用抗锯齿。 + +**示例** + +```typescript +canvas.setAntiAliasing(false); // 关闭抗锯齿 +``` + +--- + +### `clear` + +```ts +function clear(): void; +``` + +**描述** +清空画布内容。 +**注意** + +- 冻结状态下调用此方法会触发警告。 + +**示例** + +```typescript +canvas.clear(); // 清空画布 +``` + +--- + +### `delete` + +```ts +function delete(): void +``` + +**描述** +删除画布,释放资源并解除 DOM 绑定。 + +**示例** + +```typescript +canvas.delete(); // 删除画布 +``` + +--- + +### `freeze` + +```ts +function freeze(): void; +``` + +**描述** +冻结画布,禁止修改属性,并从全局列表中移除。 + +**示例** + +```typescript +canvas.freeze(); // 冻结画布 +``` + +--- + +### `activate` + +```ts +function activate(): void; +``` + +**描述** +激活画布,使其跟随游戏缩放调整尺寸。 + +**示例** + +```typescript +canvas.activate(); // 激活画布 +``` + +--- + +### `deactivate` + +```ts +function deactivate(): void; +``` + +**描述** +停用画布,不再自动调整尺寸,可能被垃圾回收。 + +**示例** + +```typescript +canvas.deactivate(); // 停用画布 +``` + +--- + +## 静态方法说明 + +### `MotaOffscreenCanvas2D.clone` + +```ts +function clone(canvas: MotaOffscreenCanvas2D): MotaOffscreenCanvas2D; +``` + +**描述** +复制一个画布对象,结果画布将被冻结。 +**返回值** + +- 复制的画布对象(不可修改属性,但可绘制)。 + +**示例** + +```typescript +const cloned = MotaOffscreenCanvas2D.clone(sourceCanvas); // 复制画布 +``` + +--- + +### `MotaOffscreenCanvas2D.refreshAll` + +```ts +function refreshAll(force: boolean = false): void; +``` + +**描述** +刷新所有已注册画布的尺寸(仅在窗口大小变化时自动调用)。 +**参数** + +- `force`: 是否强制刷新所有画布(默认仅刷新启用 `autoScale` 的画布)。 + +--- + +## 事件类型 + +### `resize` + +**触发时机** +当画布被动调整尺寸时触发(例如窗口大小变化或 `core.domStyle.scale` 变化)。 + +**监听示例** + +```typescript +canvas.on('resize', () => { + console.log('画布尺寸已调整'); +}); +``` + +--- + +## 使用示例 + +```typescript +// 创建画布 +const canvas = new MotaOffscreenCanvas2D(); + +// 配置属性 +canvas.size(800, 600); +canvas.withGameScale(true); +canvas.setHD(true); + +// 监听调整事件 +canvas.on('resize', () => { + console.log('画布尺寸已更新'); +}); + +// 绘制内容 +canvas.ctx.fillStyle = 'red'; +canvas.ctx.fillRect(0, 0, canvas.width, canvas.height); + +// 冻结画布 +canvas.freeze(); + +// 复制画布 +const cloned = MotaOffscreenCanvas2D.clone(canvas); +``` diff --git a/docs/api/motajs-render-core/MotaRenderer.md b/docs/api/motajs-render-core/MotaRenderer.md new file mode 100644 index 0000000..aa0940f --- /dev/null +++ b/docs/api/motajs-render-core/MotaRenderer.md @@ -0,0 +1,174 @@ +# MotaRenderer 类 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 继承关系 + +```mermaid +graph LR + MotaRenderer --> Container --> RenderItem --> EventEmitter + + click Container "./Container" + click RenderItem "./RenderItem" + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 属性说明 + +| 属性名 | 类型 | 默认值 | 说明 | +| -------- | ------------------------- | ----------- | ------------------------------- | +| `isRoot` | `boolean` | `true` | 标识为渲染树根节点 | +| `target` | `MotaOffscreenCanvas2D` | - | 绑定的目标画布 | +| `idMap` | `Map` | `new Map()` | ID 到渲染元素的映射表(受保护) | + +--- + +## 构造方法 + +### `constructor` + +**参数** + +- `id`: 目标 canvas 元素的 DOM ID(默认为 `render-main`) + +**行为** + +- 自动绑定指定 ID 的 canvas 元素 +- 初始化渲染循环和事件监听 +- 设置默认锚点为中心点(0.5, 0.5) + +**示例** + +```typescript +// 创建主渲染器 +const renderer = new MotaRenderer(); + +// 创建带自定义 ID 的渲染器 +const customRenderer = new MotaRenderer('game-canvas'); +``` + +--- + +## 方法说明 + +### `getElementById` + +```typescript +function getElementById(id: string): RenderItem | null; +``` + +**描述** +通过 ID 获取渲染树中的元素。 +**示例** + +```typescript +const hero = renderer.getElementById('player'); +``` + +--- + +### `refresh` + +```typescript +function refresh(): void; +``` + +**描述** +强制刷新渲染内容(清空画布并重新渲染所有元素)。 + +--- + +### `toTagTree` + +```typescript +function toTagTree(space?: number): string; +``` + +**描述** +(调试用)将渲染树输出为 XML 格式字符串。 +**参数** + +- `space`: 缩进空格数 + **示例** + +```typescript +console.log(renderer.toTagTree()); +/* 输出示例: + + + + + +*/ +``` + +--- + +### `destroy` + +```typescript +function destroy(): void; +``` + +**描述** +销毁渲染器,释放所有资源并解除事件监听。 + +--- + +## 静态方法说明 + +### `MotaRenderer.get` + +```typescript +function get(id: string): MotaRenderer | undefined; +``` + +**描述** +通过 ID 获取已注册的渲染器实例。 +**示例** + +```typescript +const mainRenderer = MotaRenderer.get('render-main'); +``` + +--- + +## 总使用示例 + +```typescript +// 初始化渲染器 +const renderer = new MotaRenderer(); + +// 创建游戏元素 +const player = new Sprite(); +player.size(32, 32); +player.setRenderFn(canvas => { + canvas.ctx.fillStyle = 'blue'; + canvas.ctx.fillRect(0, 0, 32, 32); +}); + +// 添加交互逻辑 +player.on('click', ev => { + console.log('玩家被点击', ev.offsetX, ev.offsetY); +}); + +// 构建场景 +const scene = new Container('absolute'); +scene.appendChild(player); +renderer.appendChild(scene); + +// 动态查找元素 +setTimeout(() => { + const found = renderer.getElementById('player'); + found?.pos(100, 100); +}, 1000); + +// 销毁渲染器(退出时调用) +window.addEventListener('beforeunload', () => { + renderer.destroy(); +}); +``` diff --git a/docs/api/motajs-render-core/RenderAdapter.md b/docs/api/motajs-render-core/RenderAdapter.md new file mode 100644 index 0000000..d9146f2 --- /dev/null +++ b/docs/api/motajs-render-core/RenderAdapter.md @@ -0,0 +1,230 @@ +# RenderAdapter API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + RenderAdapter --> 无继承关系 +``` + +_RenderAdapter 为独立类,无父类或子类。_ + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| ------------------ | --------------------------------- | ------------------------------ | +| `items` | `Set` | 所有元素的集合 | +| `id` | `string` | 适配器的唯一标识符 | +| `adapters`(静态) | `Map>` | 全局存储所有已创建的适配器实例 | + +--- + +## 构造方法 + +### `constructor` + +```typescript +function constructor(id: string): RenderAdapter; +``` + +创建一个适配器实例并自动注册到全局 `adapters` 集合中。 +**示例:** + +```typescript +const adapter = new RenderAdapter('ui-elements'); +``` + +--- + +## 方法说明 + +### `add` + +```typescript +function add(item: T): void; +``` + +向集合中添加一个元素。 +**示例:** + +```typescript +adapter.add(document.getElementById('box')); +``` + +### `remove` + +```typescript +function remove(item: T): void; +``` + +从集合中移除一个元素。 +**示例:** + +```typescript +adapter.remove(document.getElementById('box')); +``` + +### `receiveGlobal` + +```typescript +function receiveGlobal( + id: string, + fn: (...params: any[]) => Promise +): void; +``` + +注册全局异步函数(不与具体元素绑定)。 +**示例:** + +```typescript +adapter.receiveGlobal('refresh', async () => { + await fetchData(); +}); +``` + +### `receive` + +```typescript +function receive( + id: string, + fn: (item: T, ...params: any[]) => Promise +): void; +``` + +注册元素的异步执行函数。 +**示例:** + +```typescript +adapter.receive('fadeOut', async (element: HTMLElement) => { + element.style.opacity = '0'; + await new Promise(resolve => setTimeout(resolve, 1000)); +}); +``` + +### `receiveSync` + +```typescript +function receiveSync(id: string, fn: (item: T, ...params: any[]) => any): void; +``` + +注册元素的同步执行函数。 +**示例:** + +```typescript +adapter.receiveSync('highlight', (element: HTMLElement) => { + element.style.backgroundColor = 'yellow'; +}); +``` + +### `all` + +```typescript +function all(fn: string, ...params: any[]): Promise; +``` + +对所有元素执行异步函数,返回 `Promise.all` 结果。 +**示例:** + +```typescript +await adapter.all('fadeOut'); // 所有元素淡出 +``` + +### `any` + +```typescript +function any(fn: string, ...params: any[]): Promise; +``` + +对所有元素执行异步函数,返回 `Promise.any` 结果。 +**示例:** + +```typescript +await adapter.any('loadImage'); // 任一图片加载完成即继续 +``` + +### `sync` + +```typescript +function sync(fn: string, ...params: any[]): R[]; +``` + +对所有元素执行同步函数。 +**示例:** + +```typescript +adapter.sync('highlight'); // 所有元素高亮 +``` + +### `global` + +```typescript +function global(id: string, ...params: any[]): Promise; +``` + +调用全局异步函数。 +**示例:** + +```typescript +await adapter.global('refresh'); // 触发全局刷新 +``` + +### `destroy` + +```typescript +function destroy(): void; +``` + +销毁适配器实例并从全局 `adapters` 中移除。 +**示例:** + +```typescript +adapter.destroy(); +``` + +--- + +## 静态方法说明 + +### `RenderAdapter.get` + +```typescript +function get(id: string): RenderAdapter | undefined; +``` + +通过 ID 获取已注册的适配器实例。 +**示例:** + +```typescript +const adapter = RenderAdapter.get('ui-elements'); +``` + +--- + +## 总使用示例 + +```typescript +// 创建适配器 +const animationAdapter = new RenderAdapter('animations'); + +// 注册动画函数 +animationAdapter.receive('slideLeft', async (element: HTMLElement) => { + element.style.transform = 'translateX(-100px)'; + await new Promise(resolve => setTimeout(resolve, 500)); +}); + +// 添加元素 +const box = document.getElementById('box'); +animationAdapter.add(box); + +// 执行动画 +animationAdapter.all('slideLeft').then(() => { + console.log('所有元素滑动完成'); +}); + +// 销毁适配器 +animationAdapter.destroy(); +``` diff --git a/docs/api/motajs-render-core/RenderItem.md b/docs/api/motajs-render-core/RenderItem.md new file mode 100644 index 0000000..40ca605 --- /dev/null +++ b/docs/api/motajs-render-core/RenderItem.md @@ -0,0 +1,477 @@ +# RenderItem 类 API 文档 + +**需丰富** + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 继承关系 + +```mermaid +graph LR + RenderItem --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 接口说明 + +### IRenderUpdater + +```typescript +interface IRenderUpdater { + update(item?: RenderItem): void; +} +``` + +**描述** +定义元素更新能力的接口。`RenderItem` 通过 `update` 方法通知父元素需要重新渲染。 + +--- + +### IRenderAnchor + +```typescript +interface IRenderAnchor { + anchorX: number; + anchorY: number; + setAnchor(x: number, y: number): void; +} +``` + +**描述** +管理元素锚点的接口。锚点用于定位元素的渲染基准点(如中心点、左上角等)。 + +--- + +### IRenderConfig + +```typescript +interface IRenderConfig { + highResolution: boolean; + antiAliasing: boolean; + setHD(hd: boolean): void; + setAntiAliasing(anti: boolean): void; +} +``` + +**描述** +管理画布渲染配置的接口,控制高清模式和抗锯齿的开关。 + +--- + +### IRenderChildable + +```typescript +interface IRenderChildable { + children: Set; + appendChild(...child: RenderItem[]): void; + removeChild(...child: RenderItem[]): void; + requestSort(): void; +} +``` + +**描述** +管理子元素的接口。需在子类中实现具体逻辑(如 `Container` 元素)。 + +## 属性说明 + +| 属性名 | 类型 | 默认值 | 说明 | +| ---------------- | -------------------------- | --------------- | ---------------------------------------------------- | +| `uid` | `number` | 自动递增 | 元素的唯一标识符 | +| `id` | `string` | `''` | 元素 ID(原则不可重复) | +| `zIndex` | `number` | `0` | 元素的纵深层级(决定遮挡关系) | +| `width` | `number` | `200` | 元素的逻辑宽度 | +| `height` | `number` | `200` | 元素的逻辑高度 | +| `anchorX` | `number` | `0` | 锚点横坐标(`0` 左端,`1` 右端) | +| `anchorY` | `number` | `0` | 锚点纵坐标(`0` 上端,`1` 下端) | +| `type` | `RenderItemPosition` | `'static'` | 渲染模式(`absolute` 绝对定位,`static` 跟随摄像机) | +| `highResolution` | `boolean` | `true` | 是否启用高清画布 | +| `antiAliasing` | `boolean` | `true` | 是否启用抗锯齿 | +| `hidden` | `boolean` | `false` | 元素是否隐藏 | +| `filter` | `string` | `'none'` | 元素的滤镜效果 | +| `composite` | `GlobalCompositeOperation` | `'source-over'` | 渲染混合模式 | +| `alpha` | `number` | `1` | 元素的不透明度(`0` 透明,`1` 不透明) | +| `cursor` | `string` | `'inherit'` | 鼠标悬停时的光标样式 | +| `noEvent` | `boolean` | `false` | 是否忽略交互事件 | +| `isRoot` | `boolean` | `false` | 是否为根元素(需实现 `IRenderTreeRoot` 接口) | +| `connected` | `boolean` | 自动计算 | 元素是否已连接到根元素 | + +**特殊属性说明** + +- `transform`: 元素的变换矩阵(`Transform` 实例),修改时会自动触发 `updateTransform`。 + +--- + +## 构造方法 + +### `constructor(type: RenderItemPosition, enableCache: boolean = true, transformFallThrough: boolean = false)` + +**参数** + +- `type`: 渲染模式(`absolute` 或 `static`) +- `enableCache`: 是否启用渲染缓存(默认启用) +- `transformFallThrough`: 是否启用变换矩阵下穿机制(默认关闭) + +**示例** + +```typescript +const item = new RenderItem('absolute'); +``` + +--- + +## 方法说明 + +### `size` + +```typescript +function size(width: number, height: number): void; +``` + +**描述** +设置元素的尺寸。 +**示例** + +```typescript +item.size(300, 200); // 设置宽度 300,高度 200 +``` + +--- + +### `pos` + +```typescript +function pos(x: number, y: number): void; +``` + +**描述** +设置元素的坐标(等效于修改 `transform` 的平移量)。 +**示例** + +```typescript +item.pos(100, 50); // 设置坐标为 (100, 50) +``` + +--- + +### `append` + +```typescript +function append(parent: RenderItem): void; +``` + +**描述** +将元素添加到指定父元素下。 +**示例** + +```typescript +const parent = new RenderItem('static'); +item.append(parent); // 将 item 添加为 parent 的子元素 +``` + +--- + +### `remove` + +```typescript +function remove(): boolean; +``` + +**描述** +从父元素中移除当前元素。 +**返回值** + +- `true` 表示移除成功,`false` 表示失败。 + **示例** + +```typescript +item.remove(); // 从父元素中移除 +``` + +--- + +### `hide` + +```typescript +function hide(): void; +``` + +**描述** +隐藏元素。 +**示例** + +```typescript +item.hide(); // 隐藏元素 +``` + +--- + +### `show` + +```typescript +function show(): void; +``` + +**描述** +显示元素。 +**示例** + +```typescript +item.show(); // 显示元素 +``` + +--- + +### `delegateTicker` + +```typescript +function delegateTicker(fn: TickerFn, time?: number, end?: () => void): number; +``` + +**描述** +委托动画帧函数,持续执行指定时间。 +**返回值** + +- 委托 ID,可用于移除。 + **示例** + +```typescript +const id = item.delegateTicker(() => { + console.log('每帧执行'); +}, 1000); // 持续 1 秒 +``` + +--- + +### `destroy` + +```typescript +function destroy(): void; +``` + +**描述** +销毁元素,释放资源。 +**示例** + +```typescript +item.destroy(); // 销毁元素 +``` + +### `getAbsolutePosition` + +```typescript +function getAbsolutePosition(x?: number, y?: number): [number, number]; +``` + +**描述** +获取元素在全局坐标系中的绝对坐标。 +**示例** + +```typescript +const [absX, absY] = item.getAbsolutePosition(); // 获取元素原点绝对坐标 +``` + +--- + +### `getBoundingRect` + +```typescript +function getBoundingRect(): DOMRectReadOnly; +``` + +**描述** +获取元素的包围矩形(相对于父元素坐标系)。 +**示例** + +```typescript +const rect = item.getBoundingRect(); +console.log(rect.width, rect.height); +``` + +--- + +### `setZIndex` + +```typescript +function setZIndex(zIndex: number): void; +``` + +**描述** +设置元素的纵深层级(`zIndex` 越大越靠前)。 +**示例** + +```typescript +item.setZIndex(5); // 置顶显示 +``` + +--- + +### `requestRenderFrame` + +```typescript +function requestRenderFrame(fn: () => void): void; +``` + +**描述** +在下一帧渲染时执行函数(适用于需要在渲染流程中更新的操作)。 +**示例** + +```typescript +item.requestRenderFrame(() => { + item.pos(item.x + 1, item.y); // 每帧右移 1 单位 +}); +``` + +--- + +### `setFilter` + +```typescript +function setFilter(filter: string): void; +``` + +**描述** +设置元素的 CSS 滤镜效果(如模糊、灰度等)。 +**示例** + +```typescript +item.setFilter('blur(5px)'); // 添加模糊效果 +``` + +--- + +## 受保护方法说明 + +### `render` + +```typescript +protected abstract render(canvas: MotaOffscreenCanvas2D, transform: Transform): void; +``` + +**描述** +抽象渲染方法,子类必须实现此方法以定义具体渲染逻辑。 +**示例** + +```typescript +class CustomItem extends RenderItem { + protected render(canvas: MotaOffscreenCanvas2D) { + canvas.ctx.fillStyle = 'red'; + canvas.ctx.fillRect(0, 0, this.width, this.height); + } +} +``` + +--- + +### `isActionInElement` + +```typescript +protected isActionInElement(x: number, y: number): boolean; +``` + +**描述** +判断坐标点是否在元素范围内(可覆盖实现自定义碰撞检测)。 +**默认行为** +检测坐标是否在 `[0, width] x [0, height]` 矩形内。 + +--- + +## 静态方法说明 + +### `RenderItem.ticker` + +**类型** + +```typescript +const ticker: Ticker; +``` + +**描述** +全局动画帧管理器,用于处理所有委托的动画帧函数。 + +--- + +## 事件说明 + +事件继承自 [ERenderItemActionEvent](./Event.md#erenderitemactionevent) + +| 事件名 | 参数类型 | 说明 | +| -------------- | ------------------------- | ------------------ | +| `beforeRender` | `Transform` | 渲染前触发 | +| `afterRender` | `Transform` | 渲染后触发 | +| `destroy` | `[]` | 元素销毁时触发 | +| `transform` | `[RenderItem, Transform]` | 变换矩阵更新时触发 | + +--- + +## 总使用示例 + +::: code-group + +```typescript [基础操作] +// 创建元素(以 Sprite 为例) +const item = new Sprite('static'); + +// 设置属性 +item.size(400, 300); +item.pos(100, 50); +item.setAnchor(0.5, 0.5); // 设置中心锚点 +item.setZIndex(2); + +// 监听渲染事件 +item.on('beforeRender', transform => { + console.log('即将渲染,变换矩阵:', transform); +}); + +// 添加动画效果 +const tickerId = item.delegateTicker(time => { + item.pos(Math.sin(time / 1000) * 100, 50); +}); + +// 销毁元素 +setTimeout(() => { + item.destroy(); +}, 5000); +``` + +```typescript [创建自定义元素] +// 创建自定义可交互元素 +class Button extends RenderItem { + constructor() { + super('static'); + this.size(100, 40); + this.on('click', ev => { + console.log('按钮被点击!坐标:', ev.offsetX, ev.offsetY); + }); + } + + protected render(canvas: MotaOffscreenCanvas2D) { + // 绘制圆角矩形按钮 + const ctx = canvas.ctx; + ctx.fillStyle = '#4CAF50'; + ctx.roundRect(0, 0, this.width, this.height, 8); + ctx.fill(); + } +} + +// 使用按钮 +const button = new Button(); +button.pos(200, 150); +button.append(parentElement); + +// 添加鼠标悬停效果 +button.on('enter', () => button.setFilter('brightness(1.2)')); +button.on('leave', () => button.setFilter('none')); +``` + +::: + +# RenderItem 类 API 文档(补充部分) + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- diff --git a/docs/api/motajs-render-core/Shader.md b/docs/api/motajs-render-core/Shader.md new file mode 100644 index 0000000..b213a8b --- /dev/null +++ b/docs/api/motajs-render-core/Shader.md @@ -0,0 +1,12 @@ +# Shader 类 API 文档 + +```mermaid +graph LR + Shader --> GL2 --> RenderItem --> EventEmitter + + click GL2 "./GL2" + click RenderItem "./RenderItem" + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +用法同 [GL2](./GL2.md) diff --git a/docs/api/motajs-render-core/ShaderProgram.md b/docs/api/motajs-render-core/ShaderProgram.md new file mode 100644 index 0000000..30395a9 --- /dev/null +++ b/docs/api/motajs-render-core/ShaderProgram.md @@ -0,0 +1,11 @@ +# Shader 类 API 文档 + +```mermaid +graph LR + ShaderProgram --> GL2Program --> EventEmitter + + click GL2Program "./GL2Program" + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +用法同 [GL2Program](./GL2Program.md) diff --git a/docs/api/motajs-render-core/Sprite.md b/docs/api/motajs-render-core/Sprite.md new file mode 100644 index 0000000..40f07b1 --- /dev/null +++ b/docs/api/motajs-render-core/Sprite.md @@ -0,0 +1,121 @@ +# Sprite 类 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 继承关系 + +```mermaid +graph LR + Sprite --> RenderItem --> EventEmitter + + click RenderItem "./RenderItem" + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 属性说明 + +| 属性名 | 类型 | 默认值 | 说明 | +| ---------- | ---------------- | ---------- | -------------------------------------- | +| `renderFn` | `RenderFunction` | `() => {}` | 自定义渲染函数,用于定义精灵的绘制逻辑 | + +--- + +## 构造方法 + +### `constructor` + +**参数** + +- `type`: 渲染模式(`absolute` 绝对定位 / `static` 跟随摄像机) +- `cache`: 是否启用渲染缓存(默认启用) +- `fall`: 是否启用变换矩阵下穿机制(默认关闭) + +**示例** + +```typescript +const sprite = new Sprite('static'); +``` + +--- + +## 方法说明 + +### `setRenderFn` + +```typescript +function setRenderFn(fn: RenderFunction): void; +``` + +**描述** +设置自定义渲染函数,用于定义精灵的具体绘制逻辑。 +**参数** + +- `fn`: 接收画布和变换矩阵的回调函数,格式为 `(canvas, transform) => void` + +**示例** + +```typescript +sprite.setRenderFn((canvas, transform) => { + // 绘制一个红色矩形 + canvas.ctx.fillStyle = 'red'; + canvas.ctx.fillRect(0, 0, sprite.width, sprite.height); +}); +``` + +--- + +## 总使用示例 + +```typescript +// 创建精灵实例 +const sprite = new Sprite('absolute'); +sprite.size(100, 100); // 设置尺寸 +sprite.pos(200, 150); // 设置坐标 + +// 定义渲染逻辑 +sprite.setRenderFn(canvas => { + const ctx = canvas.ctx; + // 绘制渐变圆形 + const gradient = ctx.createRadialGradient(50, 50, 0, 50, 50, 50); + gradient.addColorStop(0, 'yellow'); + gradient.addColorStop(1, 'orange'); + ctx.fillStyle = gradient; + ctx.beginPath(); + ctx.arc(50, 50, 50, 0, Math.PI * 2); + ctx.fill(); +}); + +// 添加到父容器 +container.appendChild(sprite); + +// 监听变换事件 +sprite.on('transform', (item, transform) => { + console.log('精灵变换矩阵更新:', transform); +}); +``` + +--- + +## 高级用法示例 + +```typescript +// 创建动态旋转精灵 +const rotatingSprite = new Sprite('static'); +rotatingSprite.size(80, 80); +rotatingSprite.setRenderFn((canvas, transform) => { + canvas.ctx.fillStyle = 'blue'; + canvas.ctx.fillRect(0, 0, 80, 80); +}); + +// 每帧旋转 +rotatingSprite.delegateTicker(time => { + rotatingSprite.transform.setRotate(time / 1000); +}); + +// 添加到场景 +rootContainer.appendChild(rotatingSprite); +``` diff --git a/docs/api/motajs-render-core/Transform.md b/docs/api/motajs-render-core/Transform.md new file mode 100644 index 0000000..a9ff837 --- /dev/null +++ b/docs/api/motajs-render-core/Transform.md @@ -0,0 +1,332 @@ +# Transform 类 API 文档 + +以下内容由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 继承关系 + +```mermaid +graph LR + Transform --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 属性说明 + +| 属性名 | 类型 | 默认值 | 说明 | +| -------------- | --------------------- | ----------- | ----------------------------------------------------------- | +| `mat` | `mat3` | 单位矩阵 | 存储当前变换的 3x3 矩阵 | +| `x` | `number` | `0` | 水平平移量 | +| `y` | `number` | `0` | 垂直平移量 | +| `scaleX` | `number` | `1` | 水平缩放比例 | +| `scaleY` | `number` | `1` | 垂直缩放比例 | +| `rad` | `number` | `0` | 旋转弧度值(范围:`[0, 2π)`) | +| `modified` | `boolean`(私有) | `false` | 标识变换是否被修改过 | +| `bindedObject` | `ITransformUpdatable` | `undefined` | 绑定的对象(当变换更新时自动调用其 `updateTransform` 方法) | + +--- + +## 构造方法 + +### `constructor` + +创建一个新的变换实例,初始化为单位矩阵。 + +```typescript +const transform = new Transform(); +``` + +--- + +## 方法说明 + +### `bind` + +```typescript +function bind(obj?: ITransformUpdatable): void; +``` + +**描述** +绑定一个对象,当变换更新时自动调用其 `updateTransform` 方法(若存在)。 + +**示例** + +```typescript +const obj = { updateTransform: () => console.log('Transform updated!') }; +transform.bind(obj); +``` + +--- + +### `reset` + +```typescript +function reset(): void; +``` + +**描述** +重置所有参数到初始状态(单位矩阵)。 + +**示例** + +```typescript +transform.reset(); // 重置为 x=0, y=0, scaleX=1, scaleY=1, rad=0 +``` + +--- + +### `scale` + +```typescript +function scale(x: number, y: number = x): this; +``` + +**描述** +叠加缩放变换(相对于当前状态)。 + +**参数** + +- `x`: 水平缩放比例 +- `y`: 垂直缩放比例(默认同 `x`) + +**示例** + +```typescript +transform.scale(2); // 水平和垂直均放大2倍 +transform.scale(1.5, 0.5); // 水平放大1.5倍,垂直缩小到0.5倍 +``` + +--- + +### `translate` + +```typescript +function translate(x: number, y: number): this; +``` + +**描述** +叠加平移变换(相对于当前状态)。 + +**参数** + +- `x`: 水平平移量 +- `y`: 垂直平移量 + +**示例** + +```typescript +transform.translate(100, 50); // 向右平移100单位,向下平移50单位 +``` + +--- + +### `rotate` + +```typescript +function rotate(rad: number): this; +``` + +**描述** +叠加旋转变换(相对于当前状态)。 + +**参数** + +- `rad`: 旋转弧度值 + +**示例** + +```typescript +transform.rotate(Math.PI / 2); // 顺时针旋转90度 +``` + +--- + +### `setScale` + +```typescript +function setScale(x: number, y: number = x): this; +``` + +**描述** +直接设置缩放比例(非叠加,覆盖当前状态)。 + +**示例** + +```typescript +transform.setScale(3, 2); // 设置水平缩放3倍,垂直缩放2倍 +``` + +--- + +### `setTranslate` + +```typescript +function setTranslate(x: number, y: number): this; +``` + +**描述** +直接设置平移量(非叠加,覆盖当前状态)。 + +**示例** + +```typescript +transform.setTranslate(200, 100); // 直接定位到(200, 100) +``` + +--- + +### `setRotate` + +```typescript +function setRotate(rad: number): this; +``` + +**描述** +直接设置旋转角度(非叠加,覆盖当前状态)。 + +**示例** + +```typescript +transform.setRotate(Math.PI); // 设置旋转180度 +``` + +--- + +### `transformed` + +```typescript +function transformed(x: number, y: number): vec3; +``` + +**描述** +将坐标点 `(x, y)` 应用当前变换矩阵,返回变换后的坐标。 + +**返回值** + +- `vec3`: 变换后的三维坐标(`[x, y, 1]`) + +**示例** + +```typescript +const point = transform.transformed(10, 20); // 应用变换后的坐标 +``` + +--- + +### `untransformed` + +```typescript +function untransformed(x: number, y: number): vec3; +``` + +**描述** +将坐标点 `(x, y)` 逆向应用当前变换矩阵,返回原坐标。 + +**示例** + +```typescript +const origin = transform.untransformed(50, 30); // 逆向变换后的坐标 +``` + +--- + +### `clone` + +```typescript +function clone(): Transform; +``` + +**描述** +复制当前变换实例。 + +**示例** + +```typescript +const cloned = transform.clone(); // 生成一个完全相同的副本 +``` + +--- + +## 静态方法说明 + +### `Transform.transformed` + +```typescript +function transformed(transform: Transform, x: number, y: number): vec3; +``` + +**描述** +静态方法,直接通过变换矩阵计算坐标点 `(x, y)` 的变换结果。 + +**示例** + +```typescript +const result = Transform.transformed(transform, 5, 5); +``` + +--- + +### `Transform.untransformed` + +```typescript +function untransformed(transform: Transform, x: number, y: number): vec3; +``` + +**描述** +静态方法,直接通过变换矩阵逆向计算坐标点 `(x, y)` 的原位置。 + +**示例** + +```typescript +const origin = Transform.untransformed(transform, 100, 50); +``` + +--- + +## 接口说明 + +### `ITransformUpdatable` + +```typescript +interface ITransformUpdatable { + updateTransform?(): void; +} +``` + +**描述** +可绑定对象的接口,当变换更新时触发 `updateTransform` 方法(可选)。 + +--- + +## 总使用示例 + +```typescript +// 创建变换实例 +const transform = new Transform(); + +// 应用变换 +transform + .translate(50, 30) + .scale(2) + .rotate(Math.PI / 4); + +// 绑定对象 +const obj = { + updateTransform: () => console.log('Transform updated!') +}; +transform.bind(obj); + +// 坐标转换 +const transformedPoint = transform.transformed(10, 10); +console.log('Transformed point:', transformedPoint); + +// 复制变换 +const cloned = transform.clone(); + +// 静态方法使用 +const staticResult = Transform.transformed(cloned, 5, 5); +``` diff --git a/docs/api/motajs-render-core/functions.md b/docs/api/motajs-render-core/functions.md new file mode 100644 index 0000000..a428eaf --- /dev/null +++ b/docs/api/motajs-render-core/functions.md @@ -0,0 +1,119 @@ +# 函数 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 函数说明 + +### `isWebGLSupported` + +**功能** +检测浏览器是否支持 WebGL 1.0 +**返回值** + +- `true`: 支持 +- `false`: 不支持 + +**示例** + +```typescript +if (isWebGLSupported()) { + // 初始化 WebGL 1.0 功能 +} +``` + +--- + +### `isWebGL2Supported` + +**功能** +检测浏览器是否支持 WebGL 2.0 +**返回值** + +- `true`: 支持 +- `false`: 不支持 + +--- + +### `addTiming` + +**功能** +组合两个缓动函数为加法函数 +**数学表达** +`newTiming(p) = timing1(p) + timing2(p)` + +**参数** + +- `timing1`: 第一个缓动函数 +- `timing2`: 第二个缓动函数 + +**示例** + +```typescript +const linear = (p: number) => p; +const bounce = (p: number) => p * p; +const combined = addTiming(linear, bounce); // p + p² +``` + +--- + +### `multiplyTiming` + +**功能** +组合两个缓动函数为乘法函数 +**数学表达** +`newTiming(p) = timing1(p) * timing2(p)` + +--- + +### `isSetEqual` + +**功能** +判断两个集合是否相等(元素完全相同) +**实现逻辑** + +1. 直接引用相同 → `true` +2. 大小不同 → `false` +3. 检查 set1 是否是 set2 的子集 + +--- + +### `transformCanvas` + +**功能** +将变换矩阵应用到画布上下文 +**实现逻辑** + +```typescript +const mat = transform.mat; // 获取 3x3 矩阵 +const [a, b, , c, d, , e, f] = mat; // 分解为 2D 变换参数 +ctx.transform(a, b, c, d, e, f); // 应用变换 +``` + +**参数** + +- `canvas`: 目标画布对象 +- `transform`: 变换矩阵 + +**示例** + +```typescript +const transform = new Transform(); +transform.translate(100, 50); +transformCanvas(myCanvas, transform); // 应用平移变换 +``` + +--- + +## 工具函数关系图 + +```mermaid +graph LR + checkSupport --> isWebGLSupported + checkSupport --> isWebGL2Supported + addTiming --> 组合缓动函数 + multiplyTiming --> 组合缓动函数 + isSetEqual --> 集合操作 + transformCanvas --> 矩阵变换 +``` diff --git a/docs/api/motajs-render-core/index.md b/docs/api/motajs-render-core/index.md new file mode 100644 index 0000000..9ddbb44 --- /dev/null +++ b/docs/api/motajs-render-core/index.md @@ -0,0 +1 @@ +# @motajs/render-core diff --git a/docs/api/motajs-render-elements/BlockCacher.md b/docs/api/motajs-render-elements/BlockCacher.md new file mode 100644 index 0000000..1a05397 --- /dev/null +++ b/docs/api/motajs-render-elements/BlockCacher.md @@ -0,0 +1,369 @@ +# BlockCacher API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + BlockCacher --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +_继承自 `EventEmitter`,支持事件监听。_ + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| ------------ | ---------------- | ------------------------------------------------------------------- | +| `width` | `number` | 区域总宽度(元素单位) | +| `height` | `number` | 区域总高度(元素单位) | +| `blockSize` | `number` | 单个分块的大小(元素单位) | +| `blockData` | `BlockData` | 分块计算结果(包含分块数量、最后一个块的尺寸等信息) | +| `cacheDepth` | `number` | 缓存深度(每个分块可存储多个缓存层) | +| `cache` | `Map` | 缓存存储结构,键为精确索引(`(x + y * blockWidth) * depth + deep`) | + +--- + +## 构造方法 + +### `constructor` + +```typescript +function constructor( + width: number, + height: number, + size: number, + depth?: number +): BlockCacher; +``` + +创建分块缓存管理器并自动计算初始分块。 +**示例:** + +```typescript +const cacher = new BlockCacher(800, 600, 64); // 800x600区域,64为分块大小 +``` + +--- + +## 方法说明 + +### `size` + +```typescript +function size(width: number, height: number): void; +``` + +重置区域尺寸并重新分块(触发 `split` 事件)。 +**示例:** + +```typescript +cacher.size(1024, 768); // 重置为1024x768区域 +``` + +### `setBlockSize` + +```typescript +function setBlockSize(size: number): void; +``` + +修改分块尺寸并重新分块(触发 `split` 事件)。 +**示例:** + +```typescript +cacher.setBlockSize(128); // 分块大小改为128 +``` + +### `setCacheDepth` + +```typescript +function setCacheDepth(depth: number): void; +``` + +调整缓存深度(最大 31),自动迁移旧缓存。 +**示例:** + +```typescript +cacher.setCacheDepth(3); // 每个分块支持3层缓存 +``` + +### `split` + +```typescript +function split(): void; +``` + +重新计算分块数据并触发 `'split'` 事件。 +**示例:** + +```typescript +cacher.split(); // 手动触发分块计算(一般无需调用) +``` + +### `clearCache` + +```typescript +function clearCache(index: number, deep: number): void; +``` + +清除指定分块索引的缓存(按二进制掩码清除深度)。 +**示例:** + +```typescript +cacher.clearCache(5, 0b101); // 清除分块5的第0层和第2层缓存 +``` + +### `clearCacheByIndex` + +```typescript +function clearCacheByIndex(index: number): void; +``` + +直接按精确索引清除单个缓存。 +**示例:** + +```typescript +cacher.clearCacheByIndex(42); // 清除精确索引42对应的缓存 +``` + +### `clearAllCache` + +```typescript +function clearAllCache(): void; +``` + +清空所有缓存并销毁关联资源。 +**示例:** + +```typescript +cacher.clearAllCache(); // 完全重置缓存 +``` + +### `getIndex` + +```typescript +function getIndex(x: number, y: number): number; +``` + +根据分块坐标获取分块索引(分块坐标 -> 分块索引)。 +**示例:** + +```typescript +const index = cacher.getIndex(2, 3); // 获取(2,3)分块的索引 +``` + +### `getIndexByLoc` + +```typescript +function getIndexByLoc(x: number, y: number): number; +``` + +根据元素坐标获取所属分块索引(元素坐标 -> 分块索引)。 +**示例:** + +```typescript +const index = cacher.getIndexByLoc(150, 200); // 元素坐标(150,200)所在分块索引 +``` + +### `getBlockXYByIndex` + +```typescript +function getBlockXYByIndex(index: number): [number, number]; +``` + +根据分块索引获取分块坐标(分块索引 -> 分块坐标)。 +**示例:** + +```typescript +const [x, y] = cacher.getBlockXYByIndex(5); // 分块5的坐标 +``` + +### `getBlockXY` + +```typescript +function getBlockXY(x: number, y: number): [number, number]; +``` + +获取一个元素位置所在的分块位置(即使它不在任何分块内)(元素索引 -> 分块坐标)。 +**示例:** + +```typescript +const [x, y] = cacher.getBlockXY(11, 24); // 指定位置所在分块位置 +``` + +### `getPreciseIndex` + +```typescript +function getPreciseIndex(x: number, y: number, deep: number): number; +``` + +根据分块坐标与 `deep` 获取一个分块的精确索引(分块坐标 -> 分块索引)。 +**示例:** + +```typescript +const index = cacher.getPreciseIndex(2, 1, 3); // 指定分块的索引 +``` + +### `getPreciseIndexByLoc` + +```typescript +function getPreciseIndexByLoc(x: number, y: number, deep: number): number; +``` + +根据元素坐标及 `deep` 获取元素所在块的精确索引(元素坐标 -> 分块索引)。 +**示例:** + +```typescript +const index = cacher.getPreciseIndexByLoc(22, 11, 3); // 指定元素所在分块的索引 +``` + +### `updateElementArea` + +```typescript +function updateElementArea( + x: number, + y: number, + width: number, + height: number, + deep: number = 2 ** 31 - 1 +): Set; +``` + +根据元素区域清除相关分块缓存(返回受影响的分块索引集合)(元素坐标->分块清空)。 +**示例:** + +```typescript +const blocks = cacher.updateElementArea(100, 100, 200, 200); // 清除200x200区域内的缓存 +``` + +### `updateArea` + +```typescript +function updateArea( + x: number, + y: number, + width: number, + height: number, + deep: number = 2 ** 31 - 1 +): Set; +``` + +更新指定分块区域内的缓存(注意坐标是分块坐标,而非元素坐标)(分块坐标->分块清空)。 +**示例:** + +```typescript +const blocks = cacher.updateArea(1, 1, 1, 1); // 清除指定分块区域内的缓存 +``` + +### `getIndexOf` + +```typescript +function getIndexOf( + x: number, + y: number, + width: number, + height: number +): Set; +``` + +传入分块坐标与范围,获取该区域内包含的所有分块索引(分块坐标->分块索引集合)。 +**示例:** + +```typescript +const blocks = cacher.getIndexOf(1, 1, 1, 1); // 清除指定分块区域内的缓存 +``` + +### `getIndexOfElement` + +```typescript +function getIndexOfElement( + x: number, + y: number, + width: number, + height: number +): Set; +``` + +传入元素坐标与范围,获取该区域内包含的所有分块索引(元素坐标->分块索引集合)。 +**示例:** + +```typescript +const blocks = cacher.getIndexOfElement(3, 5, 12, 23); // 清除指定元素区域内的缓存 +``` + +### `getRectOfIndex` + +```typescript +function getRectOfIndex(block: number): [number, number, number, number]; +``` + +获取分块索引对应的元素坐标范围(分块索引 -> 元素矩形坐标)。 +**示例:** + +```typescript +const [x1, y1, x2, y2] = cacher.getRectOfIndex(5); // 分块5的坐标范围 +``` + +### `getRectOfBlockXY` + +```typescript +function getRectOfBlockXY( + x: number, + y: number +): [number, number, number, number]; +``` + +根据分块坐标,获取这个分块所在区域的元素矩形范围(左上角横纵坐标及右下角横纵坐标)(分块坐标 -> 元素矩形坐标)。 +**示例:** + +```typescript +const [x1, y1, x2, y2] = cacher.getRectOfIndex(5); // 分块5的坐标范围 +``` + +### `destroy` + +```typescript +function destroy(): void; +``` + +摧毁这个块缓存。 + +--- + +## 事件说明 + +| 事件名 | 参数 | 描述 | +| ------- | ---- | ------------------ | +| `split` | 无 | 分块参数变更时触发 | + +--- + +## 总使用示例 + +```typescript +// 创建缓存管理器 +const cacheManager = new BlockCacher(1024, 768, 64); + +// 监听分块变化 +cacheManager.on('split', () => { + console.log('分块已重新计算'); +}); + +// 添加测试缓存项 +const blockIndex = cacheManager.getIndex(2, 3); +const preciseIndex = cacheManager.getPreciseIndex(2, 3, 0); +cacheManager.cache.set( + preciseIndex, + new CanvasCacheItem(new MotaOffscreenCanvas2D(), 1) +); + +// 清除特定区域缓存 +cacheManager.updateElementArea(150, 150, 100, 100); + +// 销毁管理器 +cacheManager.destroy(); +``` diff --git a/docs/api/motajs-render-elements/Camera.md b/docs/api/motajs-render-elements/Camera.md new file mode 100644 index 0000000..758d302 --- /dev/null +++ b/docs/api/motajs-render-elements/Camera.md @@ -0,0 +1,386 @@ +# Camera API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + Camera --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +_继承自 `EventEmitter`,支持事件监听。_ + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| --------------------- | ------------------- | ------------------------------------------------ | +| `readonly binded` | `RenderItem` | 当前绑定的渲染元素 | +| `transform` | `Transform` | 目标变换矩阵,默认与 `binded.transform` 共享引用 | +| `protected operation` | `CameraOperation[]` | 当前应用的变换操作列表(平移/旋转/缩放) | + +--- + +## 构造方法 + +### `Camera.for` + +```typescript + function for(item: RenderItem): Camera +``` + +获取或创建与渲染元素关联的摄像机实例。 +**示例:** + +```typescript +const item = new RenderItem(); +const camera = Camera.for(item); // 获取或创建摄像机 +``` + +### `constructor` + +```typescript +function constructor(item: RenderItem): Camera; +``` + +直接创建摄像机实例(不会自动注册到全局映射)。 +**注意:** 推荐优先使用 `Camera.for()` 方法。 + +--- + +## 方法说明 + +### `disable` + +```typescript +function disable(): void; +``` + +禁用摄像机变换效果。 +**示例:** + +```typescript +camera.disable(); // 暂停所有摄像机变换 +``` + +### `enable` + +```typescript +function enable(): void; +``` + +启用摄像机变换效果。 + +### `requestUpdate` + +```typescript +function requestUpdate(): void; +``` + +请求在下一帧强制更新变换矩阵。 + +### `removeOperation` + +```typescript +function removeOperation(operation: CameraOperation): void; +``` + +移除一个变换操作。 +**参数说明** + +- `operation`: 要移除的操作 + +**示例** + +```ts +const operation = camera.addTranslate(); +camera.removeOperation(operation); +``` + +### `clearOperation` + +```ts +function clearOperation(): void; +``` + +清空变换操作列表。 + +### `addTranslate` + +```typescript +function addTranslate(): ICameraTranslate; +``` + +添加平移操作并返回操作对象。 +**示例:** + +```typescript +const translateOp = camera.addTranslate(); +translateOp.x = 100; // 设置横向偏移 +camera.requestUpdate(); +``` + +### `addRotate` + +```typescript +function addRotate(): ICameraRotate; +``` + +添加旋转操作并返回操作对象。 +**示例:** + +```typescript +const rotateOp = camera.addRotate(); +rotateOp.angle = Math.PI / 2; // 设置90度旋转 +camera.requestUpdate(); +``` + +### `addScale` + +```typescript +function addScale(): ICameraScale; +``` + +添加缩放操作并返回操作对象。 +**示例:** + +```typescript +const scaleOp = camera.addScale(); +scaleOp.x = 2; // 横向放大2倍 +camera.requestUpdate(); +``` + +### `applyAnimation` + +```ts +function applyAnimation(time: number, update: () => void): void; +``` + +施加动画。 + +**参数说明** + +- `time`: 动画时长。 +- `update`: 每帧执行的更新函数。 + +### `applyTranslateAnimation` + +```typescript +function applyTranslateAnimation( + operation: ICameraTranslate, + animate: Animation, + time: number +): void; +``` + +为平移操作绑定动画。 +**参数说明:** + +- `animate`: 预定义的动画实例 +- `time`: 动画持续时间(毫秒) + +### `applyRotateAnimation` + +```typescript +function applyRotateAnimation( + operation: ICameraRotate, + animate: Animation, + time: number +): void; +``` + +为旋转操作绑定动画。 + +### `applyScaleAnimation` + +```typescript +function applyScaleAnimation( + operation: ICameraScale, + animate: Animation, + time: number +): void; +``` + +为缩放操作绑定动画。 + +### `applyTranslateTransition` + +```typescript +function applyTranslateTransition( + operation: ICameraTranslate, + animate: Transition, + time: number +): void; +``` + +为平移操作绑定渐变。 +**参数说明:** + +- `animate`: 预定义的渐变实例 +- `time`: 渐变持续时间(毫秒) + +### `applyRotateTransition` + +```typescript +function applyRotateTransition( + operation: ICameraRotate, + animate: Transition, + time: number +): void; +``` + +为旋转操作绑定渐变。 + +### `applyScaleTransition` + +```typescript +function applyScaleTransition( + operation: ICameraScale, + animate: Transition, + time: number +): void; +``` + +为缩放操作绑定渐变。 + +### `stopAllAnimates` + +```ts +function stopAllAnimates(): void; +``` + +停止所有动画。 + +### `destroy` + +```typescript +function destroy(): void; +``` + +销毁摄像机并释放所有资源。 +**示例:** + +```typescript +camera.destroy(); // 解除绑定并清理动画 +``` + +--- + +## 事件说明 + +| 事件名 | 参数 | 描述 | +| --------- | ---- | ------------------ | +| `destroy` | 无 | 摄像机被销毁时触发 | + +--- + +## 总使用示例 + +::: code-group + +```typescript [动画] +import { Animation, linear } from 'mutate-animate'; + +// 获取摄像机实例 +const item = new Sprite(); +const camera = Camera.for(item); + +// 添加平移和缩放操作 +const translate = camera.addTranslate(); +const scale = camera.addScale(); + +// 创建动画实例 +const anim = new Animation() + .mode(linear()) + .time(1000) + .move(100, 100) + .time(800) + .scale(1.5); + +// 绑定动画 +camera.applyTranslateAnimation(translate, anim, 1000); +camera.applyScaleAnimation(scale, anim, 800); + +// 启用摄像机 +camera.enable(); + +// 销毁(当不再需要时) +setTimeout(() => camera.destroy(), 2000); +``` + +```typescript [渐变] +import { Transition, hyper } from 'mutate-animate'; +// 获取摄像机实例 +const item = new Sprite(); +const camera = Camera.for(item); + +// 添加平移和缩放操作 +const translate = camera.addTranslate(); +const scale = camera.addScale(); + +// 创建渐变实例,使用双曲正弦速率曲线 +const tran = new Transition().mode(hyper('sin', 'out')).time(1000); + +// 初始化参数,这一步不会执行渐变 +tran.value.x = 0; +tran.value.y = 0; +tran.value.size = 0; + +// 对参数执行渐变,直接设置即可 +tran.value.x = 100; +tran.value.y = 200; +tran.time(800); // 设置渐变时长为 800 毫秒 +tran.value.size = 1.5; + +// 绑定动画 +camera.applyTranslateTransition(translate, tran, 1000); +camera.applyScaleTransition(scale, tran, 800); + +// 启用摄像机 +camera.enable(); + +// 销毁(当不再需要时) +setTimeout(() => camera.destroy(), 2000); +``` + +::: + +--- + +## 接口说明 + +### `ICameraTranslate` + +```typescript +interface ICameraTranslate { + readonly type: 'translate'; + readonly from: RenderItem; + x: number; // 横向偏移量 + y: number; // 纵向偏移量 +} +``` + +### `ICameraRotate` + +```typescript +interface ICameraRotate { + readonly type: 'rotate'; + readonly from: RenderItem; + angle: number; // 旋转弧度值 +} +``` + +### `ICameraScale` + +```typescript +interface ICameraScale { + readonly type: 'scale'; + readonly from: RenderItem; + x: number; // 横向缩放比 + y: number; // 纵向缩放比 +} +``` diff --git a/docs/api/motajs-render-elements/CameraAnimation.md b/docs/api/motajs-render-elements/CameraAnimation.md new file mode 100644 index 0000000..55434de --- /dev/null +++ b/docs/api/motajs-render-elements/CameraAnimation.md @@ -0,0 +1,201 @@ +# CameraAnimation API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + CameraAnimation --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +_继承自 `EventEmitter`,支持事件监听。_ + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| -------- | -------- | ---------------- | +| `camera` | `Camera` | 关联的摄像机实例 | + +--- + +## 构造方法 + +### `constructor` + +```typescript +function constructor(camera: Camera): CameraAnimation; +``` + +创建摄像机动画管理器,需绑定到特定 `Camera` 实例。 +**示例:** + +```typescript +const camera = Camera.for(renderItem); +const animation = new CameraAnimation(camera); +``` + +--- + +## 方法说明 + +### `translate` + +```typescript +function translate( + operation: ICameraTranslate, + x: number, + y: number, + time: number, + start: number, + timing: TimingFn +): void; +``` + +为平移操作添加动画。 +**参数说明:** + +- `x`, `y`: 目标偏移量(格子坐标,自动乘以 `32`,之后可能改动) +- `time`: 动画持续时间(毫秒) +- `start`: 动画开始时间(相对于总动画开始的延迟) +- `timing`: 缓动函数(输入时间完成度,输出动画完成度) + +### `rotate` + +```typescript +function rotate( + operation: ICameraRotate, + angle: number, + time: number, + start: number, + timing: TimingFn +): void; +``` + +为旋转操作添加动画。 +**参数说明:** + +- `angle`: 目标旋转弧度(如 `Math.PI` 表示 `180` 度) +- 其余参考[`rotate`](#rotate) + +### `scale` + +```typescript +function scale( + operation: ICameraScale, + scale: number, + time: number, + start: number, + timing: TimingFn +): void; +``` + +为缩放操作添加动画。 +**参数说明:** + +- `scale`: 目标缩放倍率(如 `1.5` 表示放大 `1.5` 倍) +- 其余参考[`rotate`](#rotate) + +### `start` + +```typescript +function start(): void; +``` + +启动所有已添加的动画,按时间顺序执行。 +**注意:** 调用后动画将按 `start` 参数定义的顺序触发。 + +### `destroy` + +```typescript +function destroy(): void; +``` + +销毁动画管理器并释放所有资源(停止未完成的动画)。 + +--- + +## 事件说明 + +| 事件名 | 参数 | 描述 | +| --------- | -------------------------------------------------------------------------------------------------------- | ---------------------------- | +| `animate` | `operation: CameraOperation`
`execution: CameraAnimationExecution`
`item: CameraAnimationData` | 当某个动画片段开始执行时触发 | + +--- + +## 总使用示例 + +```typescript +import { hyper, trigo } from 'mutate-animate'; + +// 创建渲染元素和摄像机 +const renderItem = new Sprite(); +const camera = Camera.for(renderItem); + +// 添加平移和旋转操作 +const translateOp = camera.addTranslate(); +const rotateOp = camera.addRotate(); + +// 创建动画管理器 +const animation = new CameraAnimation(camera); + +// 添加平移动画:1秒后开始,持续2秒,横向移动3格(3*32像素) +animation.translate( + translateOp, + 3, + 0, // x=3, y=0(自动乘32) + 2000, // 动画时长2秒 + 1000, // 延迟1秒开始 + hyper('sin', 'out') // 双曲正弦函数 +); + +// 添加旋转动画:立即开始,持续1.5秒,旋转180度 +animation.rotate( + rotateOp, + Math.PI, // 目标角度(弧度) + 1500, // 动画时长1.5秒 + 0, // 无延迟 + trigo('sin', 'out') // 正弦函数 +); + +// 启动动画 +animation.start(); + +// 监听动画事件 +animation.on('animate', (operation, execution, item) => { + console.log('动画片段开始:', item.type); +}); + +// 销毁(动画结束后) +setTimeout(() => { + animation.destroy(); + camera.destroy(); +}, 5000); +``` + +--- + +## 接口说明 + +### `CameraAnimationExecution` + +```typescript +interface { + data: CameraAnimationData[]; // 动画片段列表 + animation: Animation; // 关联的动画实例 +} +``` + +### `CameraAnimationData` + +```typescript +type CameraAnimationData = + | TranslateAnimation + | TranslateAsAnimation + | RotateAnimation + | ScaleAnimation; +``` diff --git a/docs/api/motajs-render-elements/index.md b/docs/api/motajs-render-elements/index.md new file mode 100644 index 0000000..899a74d --- /dev/null +++ b/docs/api/motajs-render-elements/index.md @@ -0,0 +1,3 @@ +# @motajs/render-elements + +目录: diff --git a/docs/api/motajs-render-style/Font.md b/docs/api/motajs-render-style/Font.md new file mode 100644 index 0000000..f5908b8 --- /dev/null +++ b/docs/api/motajs-render-style/Font.md @@ -0,0 +1,186 @@ +# Font API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + Font --> IFontConfig +``` + +_实现 `IFontConfig` 接口,表示字体配置。_ + +--- + +## 接口说明 + +### `IFontConfig` + +```typescript +interface IFontConfig { + family: string; // 字体名称(如 "Arial") + size: number; // 字号数值 + sizeUnit: string; // 字号单位(推荐 "px") + weight: number; // 字重(0-1000) + italic: boolean; // 是否斜体 +} +``` + +### `FontWeight` 枚举 + +```typescript +enum FontWeight { + Light = 300, // 细体 + Normal = 400, // 常规 + Bold = 700 // 粗体 +} +``` + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| ---------- | --------- | ------------------------- | +| `family` | `string` | 字体家族名称(只读) | +| `size` | `number` | 字号数值(只读) | +| `sizeUnit` | `string` | 字号单位(如 "px",只读) | +| `weight` | `number` | 字重数值(只读) | +| `italic` | `boolean` | 是否斜体(只读) | + +--- + +## 构造方法 + +### `constructor` + +```typescript +function constructor( + family?: string, + size?: number, + sizeUnit?: string, + weight?: number, + italic?: boolean +): Font; +``` + +创建字体实例,参数默认使用静态默认值。 +**示例:** + +```typescript +const font = new Font('Arial', 14, 'px', FontWeight.Bold, true); +``` + +--- + +## 方法说明 + +### `addFallback` + +```typescript +function addFallback(...fallback: Font[]): void; +``` + +添加后备字体(当主字体不可用时使用)。 +**注意:** 检测到递归添加时会触发 `logger.warn(62)` 警告。 +**示例:** + +```typescript +const mainFont = new Font('CustomFont'); +const fallback1 = new Font('Arial'); +const fallback2 = new Font('Helvetica'); +mainFont.addFallback(fallback1, fallback2); // 添加两个后备 +``` + +### `string` + +```typescript +function string(): string; +``` + +生成 CSS 字体字符串,包含后备字体。 +**示例:** + +```typescript +console.log(font.string()); // 示例输出:"italic 700 14px CustomFont, 400 16px Arial" +``` + +--- + +## 静态方法说明 + +### `Font.parse` + +```typescript +function parse(str: string): Font; +``` + +解析 CSS 字体字符串(支持多字体声明)。 +**示例:** + +```typescript +const parsed = Font.parse('italic 16px "Fira Sans", Arial'); +// 主字体:Fira Sans,后备:Arial +``` + +### `Font.setDefaults` + +```typescript +function setDefaults(font: Font): void; +``` + +全局设置默认字体参数。 +**示例:** + +```typescript +Font.setDefaults(new Font('Segoe UI', 14, 'px', 400, false)); +``` + +### `Font.clone` + +```typescript +function clone(font: Font, options: Partial): Font; +``` + +克隆字体并修改指定属性。 +**示例:** + +```typescript +const cloned = Font.clone(baseFont, { + size: 18, + weight: FontWeight.Bold +}); +``` + +--- + +## 总使用示例 + +```typescript +// 创建主字体 +const mainFont = new Font('CustomFont', 16, 'px', FontWeight.Normal); + +// 添加后备字体(注意避免循环引用) +const fallbackA = new Font('Arial'); +const fallbackB = new Font('Helvetica'); +fallbackA.addFallback(fallbackB); +// 错误示例(触发警告62): +// fallbackB.addFallback(fallbackA); + +mainFont.addFallback(fallbackA); + +// 生成 CSS 字符串 +console.log(mainFont.string()); +// 输出: "400 16px CustomFont, 400 16px Arial, 400 16px Helvetica" + +// 解析 CSS 字符串 +const parsed = Font.parse('italic 700 24px Fantasy, "Comic Sans"'); +parsed.addFallback(new Font('Verdana')); + +// 克隆并修改 +const boldFont = Font.clone(parsed, { + weight: FontWeight.Bold, + italic: false +}); +``` diff --git a/docs/api/motajs-render-style/index.md b/docs/api/motajs-render-style/index.md new file mode 100644 index 0000000..866d002 --- /dev/null +++ b/docs/api/motajs-render-style/index.md @@ -0,0 +1,3 @@ +# @motajs/render-style + +目录: diff --git a/docs/api/motajs-render-vue/BaseProps.md b/docs/api/motajs-render-vue/BaseProps.md new file mode 100644 index 0000000..ea70d55 --- /dev/null +++ b/docs/api/motajs-render-vue/BaseProps.md @@ -0,0 +1,134 @@ +# BaseProps 接口文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 接口定义 + +```typescript +interface BaseProps { + // 基础定位 + x?: number; // 横坐标(单位:像素) + y?: number; // 纵坐标(单位:像素) + anchorX?: number; // 横向锚点比例(0~1,默认 0) + anchorY?: number; // 纵向锚点比例(0~1,默认 0) + zIndex?: number; // 纵深层级(值越大越靠上) + + // 尺寸控制 + width?: number; // 元素宽度(单位:像素,默认 200) + height?: number; // 元素高度(单位:像素,默认 200) + + // 渲染控制 + filter?: string; // CSS滤镜(如 "blur(5px)") + hd?: boolean; // 启用高清画布(默认 true) + anti?: boolean; // 启用抗锯齿(默认 true) + noanti?: boolean; // 强制禁用抗锯齿(优先级高于 anti) + hidden?: boolean; // 隐藏元素(默认 false) + + // 变换与定位 + transform?: Transform; // 变换矩阵对象 + type?: RenderItemPosition; // 定位模式("static" | "absolute") + cache?: boolean; // 启用缓存优化(根据不同元素的特性有不同的值,多数情况下使用默认配置即可达到最优性能) + nocache?: boolean; // 强制禁用缓存(优先级高于 cache) + fall?: boolean; // 继承父元素变换矩阵(默认 false),不建议使用此参数,可能很快就会被删除 + + // 交互与样式 + id?: string; // 唯一标识符 + alpha?: number; // 不透明度(0~1,默认 1) + composite?: GlobalCompositeOperation; // 混合模式(如 "lighter") + cursor?: string; // 鼠标悬停样式(如 "pointer") + noevent?: boolean; // 禁用交互事件(默认 false) + + // 简写属性 + loc?: ElementLocator /* + [x, y, width?, height?, anchorX?, anchorY?] + 如果填写的话,两两一组要么都填要么都不填,也就是说元素数量需要是 2,4,6 个 + */; + anc?: ElementAnchor; // [anchorX, anchorY],如果填写的话,两项必填 + scale?: ElementScale; // [scaleX, scaleY],如果填写的话,两项必填 + rotate?: number; // 旋转弧度值(单位:弧度) +} +``` + +--- + +## 完整使用示例 + +```tsx +import { defineComponent } from 'vue'; +import { Transform } from '@motajs/render-core'; + +// 注意,以下属性均可选,按照自己需要填写即可,不需要的可以不用填,简单需求一般只需要修改定位 +// 而复杂需求可能需要填写更多的参数,但是基本不会出现所有参数都要填的场景 +// 编写 UI 的流程参考深度指南中的 UI 编写 +export const MyUI = defineComponent(() => { + return () => ( + + ); +}); +``` + +--- + +## 属性效果说明 + +| 属性组 | 关键效果 | +| -------------- | -------------------------------------------------------------------------- | +| **基础定位** | 元素将出现在 (100,200) 坐标,以中心点(锚点 0.5)为基准定位 | +| **尺寸控制** | 元素尺寸固定为 300x200 像素 | +| **渲染控制** | 应用阴影滤镜,高清画质,关闭抗锯齿实现像素风格 | +| **变换与定位** | 附加额外平移变换,使用绝对定位模式,禁用缓存优化 | +| **交互与样式** | 元素半透明,叠加混合模式,显示"move"光标,响应交互事件 | +| **简写属性** | 通过 loc 覆盖坐标和尺寸,anc 设置底部锚点,scale 实现拉伸/压缩,旋转 45 度 | + +--- + +## 注意事项 + +1. **优先级规则**: + - `noanti` > `anti`,`nocache` > `cache` + - 显式属性(如 `x`)与简写属性(如 `loc` 中的 `x`)相比,谁最后被设置,就用谁的 +2. **简写属性解析**: + ```ts + loc = [100, 200, 300, 200]; // → x=100, y=200, width=300, height=200 + anc = [0.5, 0]; // → anchorX=0.5, anchorY=0 + scale = [2]; // → scaleX=2, scaleY=2 + ``` +3. **其他注意事项** + - `transform.translate` 与 `x` `y` 和简写定位属性的 `x` `y` 完全等效,设置后者也会让 `transform` 的平移量改变 + - 如果不允许交互,那么光标也不会显示 + - 同 `zIndex` 下,后插入的元素会在上层,但是这也意味着如果是动态插入的元素(例如由于响应式更改而插入了一个新元素),会显示在后面代码的元素之上 +4. **常见问题** + - 参考 [指南](../../guide/ui-faq.md) diff --git a/docs/api/motajs-render-vue/GraphicBaseProps.md b/docs/api/motajs-render-vue/GraphicBaseProps.md new file mode 100644 index 0000000..697d347 --- /dev/null +++ b/docs/api/motajs-render-vue/GraphicBaseProps.md @@ -0,0 +1,167 @@ +# GraphicBaseProps API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 接口定义 + +```typescript +interface GraphicBaseProps extends BaseProps { + /** 是否填充(默认 false) */ + fill?: boolean; + /** 是否描边(默认 false) */ + stroke?: boolean; + /** 强制先描边后填充(优先级最高,默认 false) */ + strokeAndFill?: boolean; + /** 填充规则(默认 "evenodd") */ + fillRule?: CanvasFillRule; + /** 填充样式(颜色/渐变/图案) */ + fillStyle?: CanvasStyle; + /** 描边样式(颜色/渐变/图案) */ + strokeStyle?: CanvasStyle; + /** 交互时是否仅检测描边区域(默认 false) */ + actionStroke?: boolean; +} +``` + +--- + +## 核心属性说明 + +| 属性 | 类型 | 默认值 | 说明 | +| --------------- | ----------------------------------------------- | ----------- | -------------------------------------------------------------- | +| `fill` | `boolean` | `false` | 启用填充(需设置 `fillStyle`) | +| `stroke` | `boolean` | `false` | 启用描边(需设置 `strokeStyle` 和 `strokeWidth`) | +| `strokeAndFill` | `boolean` | `false` | 强制先描边后填充(覆盖 `fill` 和 `stroke` 的设置) | +| `fillRule` | `"nonzero"` \| `"evenodd"` | `"evenodd"` | 填充路径计算规则(影响复杂图形的镂空效果) | +| `fillStyle` | `string` \| `CanvasGradient` \| `CanvasPattern` | - | 填充样式(支持 CSS 颜色、渐变对象等) | +| `strokeStyle` | `string` \| `CanvasGradient` \| `CanvasPattern` | - | 描边样式 | +| `actionStroke` | `boolean` | `false` | 设为 `true` 时,交互事件仅响应描边区域(需配合 `stroke` 使用) | + +--- + +## 使用示例(以矩形为例) + +### 示例 1:仅填充模式 + +```tsx + +``` + +**效果**: + +- 200x150 矩形 +- 无描边效果 + +--- + +### 示例 2:仅描边模式 + +```tsx + +``` + +**交互特性**: + +- 4px 黑色半透明描边 +- 鼠标悬停在描边区域才会触发事件 + +--- + +### 示例 3:填充 + 描边(默认顺序) + +```tsx + +``` + +**渲染顺序**: + +1. 填充黄色背景 +2. 在填充层上绘制黑色描边 + +--- + +### 示例 4:强制先描边后填充 + +```tsx + +``` + +**渲染顺序**: + +1. 绘制紫色描边 +2. 在描边层上填充浅紫色 + **视觉效果**:描边被填充色覆盖一部分 + +--- + +## 最佳实践 + +### 交互增强技巧 + +```tsx +import { ref } from 'vue'; + +// 高亮描边交互反馈 +const hovered = ref(false); +// 使用 void 关键字屏蔽返回值,避免返回值泄漏 +const enter = () => void (hovered.value = true); +const leave = () => void (hovered.value = false); + +; +``` + +--- + +## 注意事项 + +1. **样式覆盖顺序**: + `strokeAndFill` 会强制按 **描边 → 填充** 顺序渲染,忽略 `fill` 和 `stroke` 的独立设置。 + +2. **路径闭合规则**: + `fillRule="evenodd"` 适用于以下场景: + + ```tsx + // 五角星镂空效果 + + ``` + +3. **性能问题**: + 多数情况下,图形的性能很好,不需要单独优化,但是如果你使用 `path` 标签,且内容复杂,建议添加 `cache` 属性来启用缓存,避免频繁的复杂图形绘制。 diff --git a/docs/api/motajs-render-vue/functions.md b/docs/api/motajs-render-vue/functions.md new file mode 100644 index 0000000..e52dc1a --- /dev/null +++ b/docs/api/motajs-render-vue/functions.md @@ -0,0 +1,149 @@ +# use.ts API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 函数说明 + +### `onTick` + +```typescript +function onTick(fn: (time: number) => void): void; +``` + +**功能**:注册每帧执行的回调(自动管理生命周期) +**推荐使用场景**:替代 `ticker` +**参数说明**: + +- `fn`: 接收当前时间戳的帧回调函数 + **示例**: + +```typescript +// Vue 组件中 +onTick(time => { + console.log('当前帧时间:', time); +}); +``` + +--- + +### `useAnimation` + +```typescript +function useAnimation(): [Animation]; +``` + +**功能**:创建动画实例(自动销毁资源) +**返回值**:包含动画实例的元组 +**推荐使用场景**:替代直接 `new Animation()` +**示例**: + +```typescript +const [anim] = useAnimation(); +anim.time(1000).move(100, 200); +``` + +--- + +### `useTransition` + +```typescript +function useTransition(): [Transition]; +``` + +**功能**:创建渐变实例(自动销毁资源) +**返回值**:包含渐变实例的元组 +**推荐使用场景**:替代直接 `new Transition()` +**示例**: + +```typescript +const [transition] = useTransition(); +transition.value.x = 10; +transition.time(500); +transition.value.x = 100; +``` + +--- + +### `useKey` + +```typescript +function useKey(noScope?: boolean): [Hotkey, symbol]; +``` + +**功能**:管理按键作用域(自动注销绑定) +**参数说明**: + +- `noScope`: 是否使用全局作用域(默认创建新作用域) + **返回值**:元组 [热键实例, 作用域标识] + **推荐使用场景**:替代直接操作全局热键实例 + **示例**: + +```typescript +const [hotkey, scope] = useKey(); +hotkey.realize('mykey_id', () => console.log('mykey_id emitted.')); +``` + +--- + +### `onEvent` + +```typescript +function onEvent< + T extends ERenderItemEvent, + K extends EventEmitter.EventNames +>( + item: RenderItem, + key: K, + listener: EventEmitter.EventListener +): void; +``` + +**功能**:自动管理事件监听生命周期 +**推荐使用场景**:替代直接 `item.on()` + 手动注销 +**示例**: + +```typescript +onEvent(sprite, 'click', event => { + console.log('元素被点击', event); +}); +``` + +--- + +## 总使用示例 + +```tsx +import { defineComponent } from 'vue'; +import { useAnimation, onTick, useKey } from '@motajs/render-vue'; + +export const MyComponent = defineComponent(() => { + // 动画控制 + const [anim] = useAnimation(); + anim.time(1000).rotate(Math.PI); + + // 帧循环 + onTick(time => { + console.log('当前游戏运行时间:', time); + }); + + // 按键控制 + const [hotkey, scope] = useKey(); + hotkey.realize('mykey_id', () => console.log('mykey_id emitted.')); + + return () => ; +}); +``` + +--- + +## 注意事项 + +1. **资源管理**:所有通过这些接口创建的资源(动画/渐变/事件)都会在组件卸载时自动销毁 +2. **内存安全**:使用原生接口可能导致内存泄漏,这些封装接口确保: + - 自动注销事件监听 + - 自动停止动画/渐变 + - 自动清理按键绑定 +3. **类型安全**:所有接口均包含完整的类型推断(如 `onEvent` 的事件类型检查) +4. **框架适配**:专为 Vue3 组合式 API 设计,不可用于其他框架环境 diff --git a/docs/api/motajs-render-vue/index.md b/docs/api/motajs-render-vue/index.md new file mode 100644 index 0000000..2cde0a7 --- /dev/null +++ b/docs/api/motajs-render-vue/index.md @@ -0,0 +1,3 @@ +# @motajs/render-vue + +目录: diff --git a/docs/api/motajs-render-vue/标签 container.md b/docs/api/motajs-render-vue/标签 container.md new file mode 100644 index 0000000..cf9e575 --- /dev/null +++ b/docs/api/motajs-render-vue/标签 container.md @@ -0,0 +1,139 @@ +# ContainerProps API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + ContainerProps --> BaseProps + + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface ContainerProps extends BaseProps {} // 无新增属性,完全继承 BaseProps +``` + +--- + +## 核心能力 + +1. **嵌套结构**:支持多层容器嵌套,构建复杂 UI 层级 +2. **批量更新**:通过容器隔离高频/低频更新内容 +3. **虚拟化支持**:推荐结合 `Scroll`/`Page` 组件处理大数据量场景 + +--- + +## 完整示例集 + +### 示例 1:基础容器(静态内容优化) + +```tsx +import { ref } from 'vue'; +import { Font } from '@motajs/render-style'; + +const count = ref(0); +const boldFont = new Font('Verdana', 18, 'px', 700); + +// 静态容器(启用缓存) + + {/* 静态背景 */} + + + {/* 动态计数器 */} + + + +; +``` + +**优化策略**: + +- 背景层缓存,避免重复绘制 +- 计数器单独放置在独立容器,避免高频内容污染致使低频内容也需要高频更新 + +--- + +### 示例 2:条件渲染 + 循环渲染 + +```tsx +import { ref } from 'vue'; + +// 根据状态显示不同内容 +const tab = ref<'list' | 'detail'>('list'); + +const item = [{ id: 0, name: '第一个元素' }]; + +return () => ( + + {/* 选项卡导航 */} + + + + + + {/* 条件内容区 */} + {tab === 'list' ? ( + {/* 循环渲染 */} + + {items.map((item, i) => ( + + ))} + + ) : ( + + + + )} + +); +``` + +--- + +### 示例 3:动态布局嵌套 + +```tsx +// 自适应居中布局 + + {/* 主内容卡片 */} + + + + + {/* 控制栏 */} + + + + +``` + +--- + +## 性能优化指南 + +### 缓存策略对比 + +| 场景 | 配置 | 重绘频率 | 适用场景 | +| ---------------- | -------------- | -------- | --------------- | +| 不频繁更新的内容 | `cache=true` | 偶尔重绘 | 背景/图标等 | +| 高频更新内容 | `nocache=true` | 每帧重绘 | 动画/计数器 | +| 混合内容 | 分层容器 | 按需更新 | 带静态背景的 UI | + +### 大数据量处理方案 + +考虑使用[滚动条](../user-client-modules/Scroll.md)或[分页](../user-client-modules/Page.md)组件。 + +--- + +## 注意事项 + +1. **缓存失效条件**:当任意子元素及自身发生变化时,将会自动触发更新 +2. **嵌套层级**:推荐使用容器嵌套提高缓存能力,但是并建议不嵌套过多 +3. **子元素更新**:修改容器子元素时会触发整个容器的缓存重建 +4. **内存管理**:超大缓存容器(如 4096x4096)可能触发浏览器纹理限制 diff --git a/docs/api/motajs-render-vue/标签 custom-container.md b/docs/api/motajs-render-vue/标签 custom-container.md new file mode 100644 index 0000000..2b2375a --- /dev/null +++ b/docs/api/motajs-render-vue/标签 custom-container.md @@ -0,0 +1,88 @@ +# ContainerCustomProps API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + ContainerCustomProps --> ContainerProps --> BaseProps + + click ContainerProps "./ContainerProps" + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface ContainerCustomProps extends ContainerProps { + /** + * 自定义容器渲染函数 + * @param canvas - 离屏画布对象(已应用容器的变换矩阵) + * @param children - 所有子元素(未经过滤,按照 zIndex 从小到大排列) + * @param transform - 容器自身相对于父元素的变换矩阵 + */ + render?: ( + canvas: MotaOffscreenCanvas2D, + children: RenderItem[], + transform: Transform + ) => void; +} +``` + +--- + +## 核心能力 + +1. **虚拟化渲染**:通过自定义筛选逻辑实现仅渲染想要渲染的内容 +2. **渲染劫持**:完全接管子元素的绘制流程 + +--- + +## 完整示例集 + +### 示例 1:默认渲染模式(等同普通容器) + +```tsx +// 不传 render 参数时,自动渲染全部子元素 + + + + + +``` + +--- + +### 示例 2:部分渲染(仅显示可见区域) + +```tsx +const render = ( + canvas: MotaOffscreenCanvas2D, + children: RenderItem[], + transform: Transform +) => { + // 在 [0, 0, 200, 200] 之外的内容不渲染 + children.forEach(child => { + const rect = child.getBoundingRect(); + // 不在范围内的排除 + if ( + rect.right < 0 || + rect.bottom < 0 || + rect.left > 200 || + rect.top > 200 + ) + return; + child.renderContent(canvas, transform); + }); +}; + + + {/* 循环渲染 */} + {items.map((item, i) => ( + + ))} +; +``` diff --git a/docs/api/motajs-render-vue/标签 g-bezier.md b/docs/api/motajs-render-vue/标签 g-bezier.md new file mode 100644 index 0000000..19fbac7 --- /dev/null +++ b/docs/api/motajs-render-vue/标签 g-bezier.md @@ -0,0 +1,202 @@ +# g-bezier 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + BezierProps --> GraphicBaseProps --> BaseProps + + click GraphicBaseProps "./GraphicBaseProps" + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface BezierProps extends GraphicBaseProps { + sx?: number; // 起点X坐标 + sy?: number; // 起点Y坐标 + cp1x?: number; // 第一控制点X坐标 + cp1y?: number; // 第一控制点Y坐标 + cp2x?: number; // 第二控制点X坐标 + cp2y?: number; // 第二控制点Y坐标 + ex?: number; // 终点X坐标 + ey?: number; // 终点Y坐标 + curve?: BezierParams; // 简写属性 [sx, sy, cp1x, cp1y, cp2x, cp2y, ex, ey] +} +``` + +--- + +## 核心属性说明 + +| 属性 | 类型 | 默认值 | 说明 | +| ------- | ------------------------------------------ | ------ | ------------------------------------- | +| `sx` | `number` | - | 曲线起点 X 坐标(单位:像素) | +| `sy` | `number` | - | 曲线起点 Y 坐标(单位:像素) | +| `cp1x` | `number` | - | 第一控制点 X 坐标(影响曲线起始方向) | +| `cp1y` | `number` | - | 第一控制点 Y 坐标 | +| `cp2x` | `number` | - | 第二控制点 X 坐标(影响曲线结束方向) | +| `cp2y` | `number` | - | 第二控制点 Y 坐标 | +| `ex` | `number` | - | 曲线终点 X 坐标 | +| `ey` | `number` | - | 曲线终点 Y 坐标 | +| `curve` | `[sx, sy, cp1x, cp1y, cp2x, cp2y, ex, ey]` | - | 简写属性:一次性定义全部坐标点 | + +--- + +## 完整示例集 + +### 示例 1:基础三次贝塞尔曲线 + +```tsx +// 曲线默认仅描边,不需要单独设置 stroke 属性 + +``` + +--- + +### 示例 2:虚线波浪线 + +```tsx + +``` + +**曲线形态**: + +- 起点 (50,200) → 第一控制点 (150,50) +- 第二控制点 (250,350) → 终点 (350,200) +- 形成"S"型波浪线 + +--- + +### 示例 3:动态流体效果 + +```tsx +import { ref } from 'vue'; + +const offset = ref(0); + +// 每帧更新控制点位置 +onTick(() => { + offset.value += 0.02; +}); + +; +``` + +--- + +## 控制点行为说明 + +### 控制点影响示意图 + +```typescript +/* + (cp1) + ▲ + | +(start)●━━╋━━━━━━━━━━━┓ + ┃ ┃ + ┃ (cp2) ┃ + ┃ ▼ ┃ + ┗━━━━━━━●━━(end) +*/ +``` + +- **第一控制点** (`cp1`):控制曲线起始方向的弯曲程度 +- **第二控制点** (`cp2`):控制曲线结束方向的弯曲程度 + +### 特殊形态案例 + +| 控制点布局 | 曲线形态描述 | +| ------------------------------------ | ----------------- | +| `cp1`靠近起点,`cp2`靠近终点 | 近似直线 | +| `cp1`与`cp2`对称分布 | 形成对称波浪 | +| `cp1`在起点正上方,`cp2`在终点正下方 | 创建垂直"S"型曲线 | + +--- + +## 高级用法示例 + +### 复杂路径组合 + +```tsx +// 组合多条贝塞尔曲线形成花瓣造型 + + {Array.from({ length: 5 }).map((_, i) => ( + + ))} + +``` + +--- + +## 注意事项 + +1. **闭合路径**: + 三次贝塞尔曲线默认不闭合,如需闭合需手动连接到起点: + +```tsx + +``` + +2. **控制点极值**: + 当控制点距离起点/终点过远时可能产生剧烈弯曲: + +```tsx +// 可能产生非预期锐角 + +``` diff --git a/docs/api/motajs-render-vue/标签 g-circle.md b/docs/api/motajs-render-vue/标签 g-circle.md new file mode 100644 index 0000000..412ec79 --- /dev/null +++ b/docs/api/motajs-render-vue/标签 g-circle.md @@ -0,0 +1,182 @@ +# g-circle 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + CircleProps --> GraphicBaseProps --> BaseProps + + click GraphicBaseProps "./GraphicBaseProps" + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface CircleProps extends GraphicBaseProps { + radius?: number; // 圆的半径 + start?: number; // 起始角度(单位:弧度) + end?: number; // 结束角度(单位:弧度) + circle?: CircleParams; // 简写属性 [x, y, radius, start?, end?],后两项要么都填,要么都不填 +} +``` + +--- + +## 核心属性说明 + +| 属性 | 类型 | 默认值 | 说明 | +| -------- | ------------------------- | ------ | ---------------------------------------------------------- | +| `radius` | `number` | - | 圆的半径(单位:像素) | +| `start` | `number` | `0` | 起始角度(弧度),0 弧度 = 3 点钟方向(水平向右) | +| `end` | `number` | `2π` | 结束角度(弧度),默认完整圆 | +| `circle` | `[x, y, r, start?, end?]` | - | 简写属性:
`[圆心x, 圆心y, 半径, 起始角度?, 结束角度?]` | + +--- + +## 完整示例集 + +### 示例 1:基础圆形(填充) + +```tsx + +``` + +--- + +### 示例 2:描边圆形 + +```tsx + +``` + +--- + +### 示例 3:弓形(填充闭合) + +```tsx + +``` + +**角度说明**: + +- 绘制方向:**顺时针**(从 12 点走向 9 点) +- 自动闭合路径形成扇形 + +--- + +### 示例 4:圆弧(非闭合) + +```tsx + +``` + +**路径特征**: + +- 起始角度:45 度(右上对角线方向) +- 结束角度:270 度(12 点钟方向) +- 开环不闭合,形成月牙形弧线 + +--- + +## 角度系统详解 + +### 坐标系与方向 + +```typescript +// 0弧度基准点与绘制方向示意图 +/* + Math.PI / 2 (90°) + | + | +Math.PI (180°) ——+—— 0 (0°) + | + | + Math.PI * 3 / 2 (270°) +*/ +``` + +- **0 弧度基准**:3 点钟方向(与浏览器 Canvas API 完全一致) +- **绘制方向**:角度递增为顺时针方向(`start=0, end=Math.PI/2` 绘制右下四分之一圆) + +### 特殊角度对照表 + +| 弧度值 | 角度值 | 方向 | +| ------------- | ------ | ------ | +| `0` | 0° | 正右 → | +| `Math.PI/2` | 90° | 正上 ↑ | +| `Math.PI` | 180° | 正左 ← | +| `3*Math.PI/2` | 270° | 正下 ↓ | + +--- + +## 高级用法示例 + +### 动态进度环 + +```tsx +import { ref } from 'vue'; +import { onTick } from '@motajs/render-vue'; + +const progress = ref(0); + +// 每帧更新进度 +onTick(() => { + progress.value += 0.01; +}); + +; +``` + +**效果**: + +- 0%时从顶部开始 +- 进度条顺时针增长 +- 圆角端点消除锯齿 + +--- + +## 注意事项 + +1. **简写属性优先级**: + +```tsx +// 谁最后设置用谁的 + +``` diff --git a/docs/api/motajs-render-vue/标签 g-ellipse.md b/docs/api/motajs-render-vue/标签 g-ellipse.md new file mode 100644 index 0000000..877b73e --- /dev/null +++ b/docs/api/motajs-render-vue/标签 g-ellipse.md @@ -0,0 +1,175 @@ +# g-ellipse 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + EllipseProps --> GraphicBaseProps --> BaseProps + + click GraphicBaseProps "./GraphicBaseProps" + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface EllipseProps extends GraphicBaseProps { + radiusX?: number; // 椭圆X轴半径 + radiusY?: number; // 椭圆Y轴半径 + start?: number; // 起始角度(单位:弧度) + end?: number; // 结束角度(单位:弧度) + ellipse?: EllipseParams; // 简写属性 [x, y, rx, ry, start?, end?] +} +``` + +--- + +## 核心属性说明 + +| 属性 | 类型 | 默认值 | 说明 | +| --------- | ------------------------------ | ------ | ------------------------------------------------------------------ | +| `radiusX` | `number` | - | 椭圆 X 轴半径(单位:像素) | +| `radiusY` | `number` | - | 椭圆 Y 轴半径(单位:像素) | +| `start` | `number` | `0` | 起始角度(弧度),0 弧度 = 3 点钟方向 | +| `end` | `number` | `2π` | 结束角度(弧度),默认完整椭圆 | +| `ellipse` | `[x, y, rx, ry, start?, end?]` | - | 简写属性:
`[圆心x, 圆心y, X半径, Y半径, 起始角度?, 结束角度?]` | + +--- + +## 完整示例集 + +### 示例 1:基础椭圆(填充) + +```tsx + +``` + +--- + +### 示例 2:描边椭圆 + +```tsx + +``` + +--- + +### 示例 3:椭圆弓形(闭合) + +```tsx + +``` + +**角度说明**: + +- 绘制方向:**顺时针**(从 45 度到 225 度) +- 自动闭合路径形成扇形 +- 若路径自相交,`evenodd` 规则会生成镂空 + +--- + +### 示例 4:椭圆弧线(非闭合) + +```tsx + +``` + +**路径特征**: + +- 垂直方向椭圆弧(X 半径 > Y 半径) +- 起始角度:-90 度(12 点方向) +- 结束角度:90 度(6 点方向) +- 开环形成对称弧线 + +--- + +## 角度系统详解 + +### 坐标系与方向 + +```typescript +// 角度系统与圆形一致,但受半径比例影响: +/* + radiusY + ↑ + | + radiusX +---→ +*/ +``` + +- **0 弧度基准**:3 点钟方向(与浏览器 Canvas API 一致) +- **半径影响**:当 `radiusX ≠ radiusY` 时,相同角度对应的端点位置会拉伸 +- **绘制方向**:角度递增为顺时针方向 + +### 特殊角度效果 + +| 参数组合 | 效果描述 | +| ---------------------------------- | ------------------------ | +| `radiusX=radiusY` | 退化为标准圆形 | +| `start=0, end=Math.PI` | 右半椭圆(水平方向半圆) | +| `start=Math.PI/2, end=3*Math.PI/2` | 上半椭圆(垂直方向半圆) | + +--- + +## 高级用法示例 + +### 动态仪表盘 + +```tsx +import { ref } from 'vue'; + +const value = ref(0.3); + +; +``` + +**效果**: + +- 椭圆弧仪表盘,从左上方向右侧延伸 +- 进度值 `0.3` 时覆盖 30%路径 + +--- + +## 注意事项 + +1. **简写属性优先级**: + +```tsx +// 谁最后被设置用谁的 + +``` diff --git a/docs/api/motajs-render-vue/标签 g-line.md b/docs/api/motajs-render-vue/标签 g-line.md new file mode 100644 index 0000000..b88bff2 --- /dev/null +++ b/docs/api/motajs-render-vue/标签 g-line.md @@ -0,0 +1,125 @@ +# g-line 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + LineProps --> GraphicBaseProps --> BaseProps + + click GraphicBaseProps "./GraphicBaseProps" + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface LineProps extends GraphicBaseProps { + x1?: number; // 起点X坐标 + y1?: number; // 起点Y坐标 + x2?: number; // 终点X坐标 + y2?: number; // 终点Y坐标 + line?: LineParams; // 简写属性 [x1, y1, x2, y2] +} +``` + +--- + +## 核心属性说明 + +| 属性 | 类型 | 默认值 | 说明 | +| ---------- | ----------------------------------- | -------- | ---------------------------------------------- | +| `x1` | `number` | - | 线段起点 X 坐标(单位:像素) | +| `y1` | `number` | - | 线段起点 Y 坐标(单位:像素) | +| `x2` | `number` | - | 线段终点 X 坐标(单位:像素) | +| `y2` | `number` | - | 线段终点 Y 坐标(单位:像素) | +| `line` | `[x1, y1, x2, y2]` | - | 简写属性:一次性定义起点和终点坐标 | +| `lineDash` | `number[]` | - | 虚线模式(如 `[5, 3]` 表示 5px 实线+3px 间隙) | +| `lineCap` | `"butt"` \| `"round"` \| `"square"` | `"butt"` | 线段端点样式 | + +--- + +## 完整示例集 + +### 示例 1:基础实线 + +```tsx +// 线段默认就是仅描边,因此不需要单独设置 stroke 属性 + +``` + +--- + +### 示例 2:虚线线段 + +```tsx + +``` + +**效果说明**: + +- 水平红色虚线 +- 线段端点呈圆形 + +--- + +### 示例 3:动态线段(动画) + +```tsx +import { transitioned } from '@user/client-modules'; + +// 创建渐变 +const x2 = transitioned(100, 2000, linear()); +x2.set(400); // 终点横坐标从 100 变到 400 + +return () => ( + +); +``` + +**动态效果**: + +- 线段从 100px 位置向右延伸至 400px +- 2 秒完成动画 + +--- + +## 线段样式对照表 + +| 样式组合 | 效果图示 | +| --------------------- | ----------------- | +| `lineCap="butt"` | 平头端点:⎯ | +| `lineCap="round"` | 圆头端点:⭘―――――⭘ | +| `lineCap="square"` | 方头端点:▯―――――▯ | +| `lineDash=[20,5,5,5]` | 复杂虚线:━━⧀┄⧀┄ | + +--- + +## 注意事项 + +1. **坐标系差异**: + 线段坐标基于父容器坐标系,如需相对定位建议嵌套在`container`中: + +```tsx + + {/* 实际坐标为 (100,100)→(150,150) */} + + +``` diff --git a/docs/api/motajs-render-vue/标签 g-path.md b/docs/api/motajs-render-vue/标签 g-path.md new file mode 100644 index 0000000..30cb870 --- /dev/null +++ b/docs/api/motajs-render-vue/标签 g-path.md @@ -0,0 +1,173 @@ +# g-path 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + PathProps --> GraphicBaseProps --> BaseProps + + click GraphicBaseProps "./GraphicBaseProps" + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface PathProps extends GraphicBaseProps { + path?: Path2D; // 自定义路径对象 +} +``` + +--- + +## 核心属性说明 + +| 属性 | 类型 | 默认值 | 说明 | +| -------------- | -------------------------- | ----------- | -------------------------------------------------- | +| `path` | `Path2D` | - | 自定义矢量路径(支持多路径、贝塞尔曲线等复杂形状) | +| `fillRule` | `"nonzero"` \| `"evenodd"` | `"evenodd"` | 填充规则(影响路径重叠区域的渲染) | +| `actionStroke` | `boolean` | `false` | 设为 `true` 时,交互事件仅检测描边区域 | + +--- + +## 完整示例集 + +### 示例 1:复杂星形路径 + +```tsx +// 创建五角星路径 +const starPath = new Path2D(); +for (let i = 0; i < 5; i++) { + const angle = (i * 2 * Math.PI) / 5 - Math.PI / 2; + const x = 100 + Math.cos(angle) * 50; + const y = 100 + Math.sin(angle) * 50; + if (i === 0) starPath.moveTo(x, y); + else starPath.lineTo(x, y); +} +starPath.closePath(); + +; +``` + +**效果说明**: + +- 使用`evenodd`规则自动产生星形镂空效果 +- 金色填充+橙色描边的五角星 + +--- + +### 示例 2:交互式描边检测 + +```tsx +import { ref } from 'vue'; +const [clicked, setClicked] = useState(false); + +const clicked = ref(false); + +// 创建对话气泡路径 +const bubblePath = new Path2D(); +bubblePath.moveTo(50, 20); +bubblePath.quadraticCurveTo(25, 0, 0, 20); +bubblePath.quadraticCurveTo(25, 40, 50, 20); +bubblePath.rect(0, 20, 200, 100); + +const click = () => void (clicked.value = !click.value); + +; +``` + +**交互特性**: + +- 点击描边区域切换填充颜色 +- 内部区域不响应点击事件 + +--- + +### 示例 3:组合路径(齿轮造型) + +```tsx +const gearPath = new Path2D(); +// 主体圆形 +gearPath.arc(100, 100, 80, 0, Math.PI * 2); +// 添加8个齿牙 +for (let i = 0; i < 8; i++) { + const angle = ((Math.PI * 2) / 8) * i; + gearPath.moveTo(100 + Math.cos(angle) * 90, 100 + Math.sin(angle) * 90); + gearPath.lineTo( + 100 + Math.cos(angle + Math.PI / 8) * 110, + 100 + Math.sin(angle + Math.PI / 8) * 110 + ); + gearPath.lineTo( + 100 + Math.cos(angle - Math.PI / 8) * 110, + 100 + Math.sin(angle - Math.PI / 8) * 110 + ); +} + +; +``` + +--- + +## 高级用法示例 + +### SVG 路径转换 + +```tsx +// 将SVG路径转换为Path2D +const svgPath = 'M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80'; +const path = new Path2D(svgPath); + +; +``` + +--- + +## 注意事项 + +1. **路径闭合**: + + ```tsx + // 必须显式闭合路径才能正确填充 + const path = new Path2D(); + path.moveTo(0, 0); + path.lineTo(100, 0); + path.lineTo(100, 100); + path.closePath(); // 关键闭合操作 + ``` diff --git a/docs/api/motajs-render-vue/标签 g-quad.md b/docs/api/motajs-render-vue/标签 g-quad.md new file mode 100644 index 0000000..eff64ac --- /dev/null +++ b/docs/api/motajs-render-vue/标签 g-quad.md @@ -0,0 +1,119 @@ +# g-quad 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + QuadraticProps --> GraphicBaseProps --> BaseProps + + click GraphicBaseProps "./GraphicBaseProps" + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface QuadraticProps extends GraphicBaseProps { + sx?: number; // 起点X坐标 + sy?: number; // 起点Y坐标 + cpx?: number; // 控制点X坐标 + cpy?: number; // 控制点Y坐标 + ex?: number; // 终点X坐标 + ey?: number; // 终点Y坐标 + curve?: QuadParams; // 简写属性 [sx, sy, cpx, cpy, ex, ey] +} +``` + +--- + +## 核心属性说明 + +| 属性 | 类型 | 默认值 | 说明 | +| ------- | ---------------------------- | ------ | --------------------------------------- | +| `sx` | `number` | - | 曲线起点 X 坐标(单位:像素) | +| `sy` | `number` | - | 曲线起点 Y 坐标(单位:像素) | +| `cpx` | `number` | - | 控制点 X 坐标(决定曲线弯曲方向和程度) | +| `cpy` | `number` | - | 控制点 Y 坐标 | +| `ex` | `number` | - | 曲线终点 X 坐标 | +| `ey` | `number` | - | 曲线终点 Y 坐标 | +| `curve` | `[sx, sy, cpx, cpy, ex, ey]` | - | 简写属性:一次性定义全部坐标点 | + +--- + +## 完整示例集 + +### 示例 1:基础二次贝塞尔曲线 + +```tsx + +``` + +--- + +### 示例 2:虚线抛物线 + +```tsx + +``` + +**曲线形态**: + +- 起点 (50,400) → 控制点 (250,100) → 终点 (450,400) +- 形成对称的类似抛物线形状的曲线 + +--- + +## 控制点行为说明 + +### 控制点影响示意图 + +```typescript +/* + (cpx,cpy) + ● + / \ + / \ +(start) ●-----●(end) +*/ +``` + +- **单控制点**:二次贝塞尔曲线仅有一个控制点,同时影响曲线的起始和结束方向 +- **对称性**:控制点距离起点/终点的垂直距离越大,曲线弯曲越明显 + +### 特殊形态案例 + +| 控制点布局 | 曲线形态描述 | +| ------------------------ | ------------- | +| 控制点在起点终点连线中点 | 退化为直线 | +| 控制点在起点正上方 | 形成"U"型曲线 | +| 控制点在终点右侧 | 形成"C"型曲线 | + +--- + +## 注意事项 + +1. **控制点极限值**: + 当控制点与起点/终点距离过大时可能产生锐角: + +```tsx +// 可能产生非预期的尖角形态 + +``` diff --git a/docs/api/motajs-render-vue/标签 g-rect.md b/docs/api/motajs-render-vue/标签 g-rect.md new file mode 100644 index 0000000..86f4143 --- /dev/null +++ b/docs/api/motajs-render-vue/标签 g-rect.md @@ -0,0 +1,91 @@ +# g-rect 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + RectProps --> GraphicBaseProps --> BaseProps + + click GraphicBaseProps "./GraphicBaseProps" + click BaseProps "./BaseProps" +``` + +--- + +## 使用示例 + +### 示例 1:仅填充模式 + +```tsx + +``` + +**效果**: + +- 200x150 矩形 +- 无描边效果 + +--- + +### 示例 2:仅描边模式 + +```tsx + +``` + +**交互特性**: + +- 4px 黑色半透明描边 +- 鼠标悬停在描边区域才会触发事件 + +--- + +### 示例 3:填充 + 描边(默认顺序) + +```tsx + +``` + +**渲染顺序**: + +1. 填充黄色背景 +2. 在填充层上绘制黑色描边 + +--- + +### 示例 4:强制先描边后填充 + +```tsx + +``` + +**渲染顺序**: + +1. 绘制紫色描边 +2. 在描边层上填充浅紫色 + **视觉效果**:描边被填充色覆盖一部分 diff --git a/docs/api/motajs-render-vue/标签 g-rectr.md b/docs/api/motajs-render-vue/标签 g-rectr.md new file mode 100644 index 0000000..f245ef3 --- /dev/null +++ b/docs/api/motajs-render-vue/标签 g-rectr.md @@ -0,0 +1,167 @@ +# g-rectr 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + RectRProps --> GraphicBaseProps --> BaseProps + + click GraphicBaseProps "./GraphicBaseProps" + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface RectRProps extends GraphicBaseProps { + /** + * 圆形圆角参数 [左上, 右上, 右下, 左下] + * - 1个值:全角相同 + * - 2个值:左上+右下 / 右上+左下 + * - 3个值:左上 / 右上+左下 / 右下 + * - 4个值:分别设置四个角 左上、右上、左下、右下 + */ + circle?: RectRCircleParams; + + /** + * 椭圆圆角参数 [x半径, y半径, ...] + * - 1组:全角相同 + * - 2组:左上+右下 / 右上+左下 + * - 3组:左上 / 右上+左下 / 右下 + * - 4组:分别设置四个角 左上、右上、左下、右下 + */ + ellipse?: RectREllipseParams; +} +``` + +--- + +## 核心行为规则 + +- **参数限制**:若圆角值超过 `width/height` 的 50% 或为负数,将自动修正: + - 负值 → 修正为 0 + - 超过 50% → 修正为 50% +- **参数优先级**:`ellipse` 优先级高于 `circle` + +--- + +## 完整示例集 + +### 示例 1:统一圆形圆角 + +```tsx + +``` + +--- + +### 示例 2:差异圆形圆角 + +```tsx + +``` + +--- + +### 示例 3:椭圆圆角 + +```tsx + +``` + +--- + +### 示例 4:混合椭圆圆角 + +```tsx + +``` + +--- + +## 参数对照表 + +### 圆形圆角(circle)参数规则 + +| 参数数量 | 生效规则 | +| -------- | -------------------------------------------- | +| 1 | 全角相同:`[20] → [20,20,20,20]` | +| 2 | 对角对称:`[10,30] → [10,30,30,10]` | +| 3 | 左上/对角/右下:`[10,20,30] → [10,20,30,20]` | +| 4 | 独立设置四个角:`[10,20,30,40]` | + +### 椭圆圆角(ellipse)参数规则 + +| 参数组数 | 生效规则 | +| -------- | ---------------------------------------------- | +| 1 | 全角相同:`[15,20] → 四角均为15x20` | +| 2 | 对角对称:`[10,5,20,10] → 左上+右下/右上+左下` | +| 3 | 左上/对角/右下:`[10,20,15,5,20,10]` | +| 4 | 独立设置四个角:`[10,20,15,25,20,30,5,10]` | + +--- + +## 错误处理示例 + +```tsx +// 危险参数示例 + +``` + +**实际生效值**: + +- 负值修正:`-10 → 0` +- 超限修正:`200 → min(200, 50/2=25) → 25px` +- 最终参数:`[0,25] → [0,25,25,0]` + +--- + +## 最佳实践建议 + +1. **响应式圆角**: + +```tsx +// 圆角随尺寸变化 + +``` diff --git a/docs/api/motajs-render-vue/标签 icon.md b/docs/api/motajs-render-vue/标签 icon.md new file mode 100644 index 0000000..f70b128 --- /dev/null +++ b/docs/api/motajs-render-vue/标签 icon.md @@ -0,0 +1,121 @@ +# icon 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + IconProps --> BaseProps + + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface IconProps extends BaseProps { + icon: AllNumbers | AllIds; // 图标ID或数字标识 + frame?: number; // 显示指定帧(从0开始计数) + animate?: boolean; // 是否启用帧动画循环(默认false) +} +``` + +--- + +## 核心属性说明 + +| 属性 | 类型 | 默认值 | 说明 | +| --------- | -------------------- | -------- | ------------------------------------------------------ | +| `icon` | `number` \| `string` | **必填** | 图标资源标识符(对应素材库中的图块 ID 或预设数字编码) | +| `frame` | `number` | `0` | 指定显示的帧序号(当`animate=false`时生效) | +| `animate` | `boolean` | `false` | 启用自动播放帧动画(优先级高于`frame`参数) | + +--- + +## 完整示例集 + +### 示例 1:静态显示指定帧 + +```tsx +// 显示图块ID为"greenSlime"的第3帧(索引从0开始) + +``` + +--- + +### 示例 2:动态帧动画 + +```tsx +// 自动播放4帧循环动画 + +``` + +**动画行为**: + +- 播放图标自带的 4 帧动画序列(0→1→2→3→0...) +- 动画速度由素材预设帧率决定 + +--- + +### 示例 3:交互控制动画 + +```tsx +import { ref } from 'vue'; + +const animating = ref(false); + +const click = () => void (animating.value = false); + +// 点击切换动画状态 +; +``` + +**交互逻辑**: + +- 初始状态显示第 1 帧(门关闭) +- 点击后播放开门动画 + +--- + +## 帧动画系统规则 + +### 帧索引定义 + +```typescript +// 图块素材帧结构示例 +/* + [0] [1] [2] [3] + +---+---+---+---+ + | | | | | // 4帧水平排列的图块素材 + +---+---+---+---+ +*/ +``` + +- **播放方向**:始终从 `0` 帧开始正向循环 +- **循环模式**:播放到最后一帧后回到第 `0` 帧 + +### 参数限制 + +| 场景 | 系统行为 | +| ----------------------------- | ------------------------------------- | +| `frame` 超过最大帧数 | 报错 | +| `frame` 为负数 | 报错 | +| `animate=true` 时修改 `frame` | `frame` 参数被忽略,始终从 0 开始播放 | diff --git a/docs/api/motajs-render-vue/标签 image.md b/docs/api/motajs-render-vue/标签 image.md new file mode 100644 index 0000000..5429cfd --- /dev/null +++ b/docs/api/motajs-render-vue/标签 image.md @@ -0,0 +1,103 @@ +# image 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + ImageProps --> BaseProps + + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface ImageProps extends BaseProps { + /** 必填 - 图片对象(CanvasImageSource 类型) */ + image: CanvasImageSource; +} +``` + +--- + +## 核心功能 + +- **尺寸控制**:通过 `width/height` 或 `loc` 简写属性定义图片尺寸(默认 200x200) +- **像素风支持**:通过 `noanti=true` 禁用抗锯齿 + +--- + +## 使用示例 + +### 示例 1:基础图片显示 + +```tsx +const image = core.material.images.images['myimage.webp']; +// 显示 200x200 的默认尺寸图片 +; +``` + +**等效简写**: + +```tsx +const image = core.material.images.images['myimage.webp']; + +; +``` + +--- + +### 示例 2:自定义尺寸 + +```tsx +const image = core.material.images.images['myimage.webp']; +// 方式一:直接设置宽高 +; + +// 方式二:通过 loc 简写属性 +; +``` + +--- + +### 示例 3:像素风渲染(禁用抗锯齿) + +```tsx +const pixelImage = core.material.images.images['myimage.webp']; + +// 硬核像素风格配置 +; +``` + +**效果说明**: + +- 原始 32x32 像素图 → 放大为 64x64 像素 +- 每个像素块保持锐利边缘 + +--- + +## 属性配置表 + +| 属性 | 类型 | 默认值 | 说明 | +| ------- | ------------------- | -------- | ------------------------------------------- | +| `image` | `CanvasImageSource` | **必填** | 图片资源(ImageBitmap/HTMLImageElement 等) | diff --git a/docs/api/motajs-render-vue/标签 sprite.md b/docs/api/motajs-render-vue/标签 sprite.md new file mode 100644 index 0000000..d44b0d0 --- /dev/null +++ b/docs/api/motajs-render-vue/标签 sprite.md @@ -0,0 +1,148 @@ +# sprite 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + SpriteProps --> BaseProps + + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface SpriteProps extends BaseProps { + /** + * 自定义渲染函数 + * @param canvas - 离屏画布对象 + * @param transform - 当前元素相对于父元素的变换矩阵 + */ + render?: (canvas: MotaOffscreenCanvas2D, transform: Transform) => void; +} +``` + +--- + +## 核心能力 + +通过 `render` 函数实现 **动态绘制**,可结合: + +- 基础定位/变换参数(继承 `BaseProps`) +- 动画系统(`useAnimation`) +- 帧回调(`onTick`) +- 自定义图形绘制(路径/滤镜/混合模式) + +**注意**,这个标签虽然非常基础,但是应该并不常用,因为很多内容都有对应的标签可以实现(例如线可以使用 `g-line` 标签等),因此如果你在考虑使用此标签,请确认你必须使用它,或是你的场景对性能非常敏感。 + +--- + +## 使用示例 + +以下的示例代码均应该在**组件内部**编写,哪里是组件内部请参考[指南](../../guide/ui.md)。 + +### 示例 1:基础图形 + +```tsx +import { MotaOffscreenCanvas2D } from '@motajs/render-core'; + +// 绘制旋转了 45 度的彩色方块 +const render = (canvas: MotaOffscreenCanvas2D) => { + const ctx = canvas.ctx; + ctx.fillStyle = 'rgba(255,0,0,0.8)'; + ctx.strokeStyle = 'blue'; + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.rect(0, 0, 200, 200); + ctx.fill(); + ctx.stroke(); +}; + +; +``` + +**效果**: + +- 100x100 红色方块,中心点位于 (200,200) +- 45 度旋转,蓝色描边 +- 80% 不透明度 + +--- + +### 示例 2:结合动画系统 + +```tsx +import { ref } from 'vue'; +import { useAnimation } from '@motajs/render-vue'; + +// 平移动画 + 动态缩放 +const [anim] = useAnimation(); +anim.time(2000).move(100, 0).scale(1.5); + +const loc = ref([0, 0]); +const scale = ref([1, 1]); + +onTick(() => { + loc.value = [anim.x, anim.y]; + scale.value = [anim.size, anim.size]; +}); + +const render = canvas => { + const ctx = canvas.ctx; + ctx.rect(0, 0, 200, 200); + ctx.fill(); +}; + +return () => ; +``` + +**效果**: + +- 矩形横向放大 1.5 倍,横向位置移动 100px +- 2 秒线性动画 + +--- + +### 示例 3:交互事件 + 滤镜 + +```tsx +import { ref } from 'vue'; + +// 悬浮模糊 +const filter = ref('none'); + +const enter = () => { + filter.value = 'blur(2px)'; +}; +const leave = () => { + filter.value = 'none'; +}; + +return () => ( + +); +``` + +**效果**: + +- 鼠标悬浮时添加模糊滤镜 +- 鼠标悬浮显示指针光标 + +--- + +## 注意事项 + +1. **坐标系**:`render` 函数内使用 **局部坐标系**,锚点变换已自动处理 +2. **循环更新**:避免在 `render` 中循环更新自身 diff --git a/docs/api/motajs-render-vue/标签 text.md b/docs/api/motajs-render-vue/标签 text.md new file mode 100644 index 0000000..50fb216 --- /dev/null +++ b/docs/api/motajs-render-vue/标签 text.md @@ -0,0 +1,160 @@ +# TextProps API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + TextProps --> BaseProps + + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface TextProps extends BaseProps { + text?: string; // 显示的文字内容 + fillStyle?: CanvasStyle; // 文字填充样式(颜色/渐变/图案) + strokeStyle?: CanvasStyle; // 文字描边样式 + font?: Font; // 字体配置对象 + strokeWidth?: number; // 描边宽度(单位:像素) +} +``` + +--- + +## 使用示例 + +### 1. 基本文本渲染 + +```tsx +import { Font } from '@motajs/render-style'; + +; +``` + +**效果**: + +- 在 (100,50) 位置显示蓝色 "Hello World" +- 使用 24px 粗体 Arial 字体 +- 无描边效果 + +--- + +### 2. 描边文字 + 填充组合 + +```tsx +import { Font } from '@motajs/render-style'; + +; +``` + +**效果**: + +- 金色文字带黑色半透明描边 +- 32px 加粗斜体 Verdana +- 2px 描边宽度 + +--- + +### 3. 动态更新文本 + +```tsx +import { ref } from 'vue'; +import { Font } from '@motajs/render-style'; + +// Vue3 组件示例 +const count = ref(0); + +onTick(() => { + count.value++; +}); + +return () => ( + +); +``` + +--- + +## 高级用法示例 + +### 文字路径动画 + +```tsx +import { ref } from 'vue'; +import { Font, onTick } from '@motajs/render'; + +const offset = ref(0); + +onTick(() => { + offset.value = (offset.value + 1) % 100; +}); + +; +``` + +--- + +### 文字阴影 + 滤镜 + +```tsx +import { Font } from '@motajs/render-style'; + +; +``` + +--- + +## 属性兼容性表 + +| 属性 | 是否继承 BaseProps | 动态更新支持 | 性能影响等级 | +| ------------- | ------------------ | ------------ | ------------ | +| `text` | 否 | ✔️ | 中 | +| `fillStyle` | 否 | ✔️ | 中 | +| `strokeStyle` | 否 | ✔️ | 中 | +| `font` | 否 | ✔️ | 高 | +| `strokeWidth` | 否 | ✔️ | 低 | + +--- + +## 注意事项 + +1. 如果需要显示多行文本,考虑使用 [TextContent](../user-client-modules/TextContent.md) +2. 考虑到浏览器兼容性,不建议在颜色中填写一些新标准的语法,例如 `rgb(0.3, 0.6, 0.8 / 0.6)` `#rgba` 等 diff --git a/docs/api/motajs-render-vue/标签 winskin.md b/docs/api/motajs-render-vue/标签 winskin.md new file mode 100644 index 0000000..7e65c53 --- /dev/null +++ b/docs/api/motajs-render-vue/标签 winskin.md @@ -0,0 +1,117 @@ +# winskin 标签 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + WinskinProps --> BaseProps + + click BaseProps "./BaseProps" +``` + +--- + +## 接口定义 + +```typescript +interface WinskinProps extends BaseProps { + /** + * 窗口皮肤图片资源ID + */ + image: ImageIds; + + /** + * 边框粗细 + * - 设置为 32 时表示原始大小(16 像素宽度),默认为 32 + * - 设为0时仅显示中心内容区 + */ + borderSize?: number; +} +``` + +--- + +## 核心功能演示 + +### 示例 1:基础窗口皮肤 + +```tsx +// 使用默认边框(borderSize=32) + + + + + +``` + +--- + +### 示例 2:不同边框粗细对比 + +```tsx +// 细边框(borderSize=16) +; + +// 粗边框(borderSize=32) +; + +// 无边框(borderSize=0) +; +``` + +**效果差异**: + +- 细边框:内容区域更大,适合信息密集场景 +- 粗边框:装饰性更强,适合标题窗口 +- 无边框:仅保留中心纹理,适合全屏背景 + +--- + +## 九宫格原理示意图 + +```typescript +/* + +-------------------+ + | 1 top 2 | ← borderSize + | | + | | +left | 4 center 3 | right + | | + | | + | 5 bottom 6 | + +-------------------+ +*/ +``` + +--- + +## 高级用法示例 + +### 动态边框动画 + +```tsx +import { hyper } from 'mutate-animate'; +import { transitioned } from '@user/client-modules'; +import { onTick } from '@motajs/render-vue'; + +const border = transitioned(16, 1000, hyper('sin', 'in-out')); +onTick(() => { + if (border.value === 16) border.set(32); + if (border.value === 32) border.set(16) +}) + + + + +; +``` diff --git a/docs/api/motajs-render/index.md b/docs/api/motajs-render/index.md new file mode 100644 index 0000000..0bb0fed --- /dev/null +++ b/docs/api/motajs-render/index.md @@ -0,0 +1,16 @@ +# @motajs/render + +此模块包含如下模块的内容,可以直接引用: + +- [@motajs/render-core](../motajs-render-core/) +- [@motajs/render-elements](../motajs-render-elements/) +- [@motajs/render-style](../motajs-render-style/) +- [@motajs/render-vue](../motajs-render-vue/) + +引入示例: + +```ts +import { Container } from '@motajs/render'; +// 二者等价,不需要单独使用一个量来接收,注意与 @motajs/client 引入方式区分 +import { Container } from '@motajs/render-core'; +``` diff --git a/docs/api/motajs-system-action/Hotkey.md b/docs/api/motajs-system-action/Hotkey.md new file mode 100644 index 0000000..60f600d --- /dev/null +++ b/docs/api/motajs-system-action/Hotkey.md @@ -0,0 +1,311 @@ +# Hotkey API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +```mermaid +graph LR + Hotkey --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +## 类描述 + +`Hotkey` 是按键系统的核心类,用于管理按键绑定、辅助键状态、按键分组及事件触发逻辑。继承自 `EventEmitter`,支持自定义事件监听。主要用于实现复杂的快捷键系统。 + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| -------------- | ---------------------------- | -------------------------------------------- | +| `id` | `string` | 控制器的唯一标识符 | +| `name` | `string` | 控制器的显示名称 | +| `data` | `Record` | 存储所有已注册的按键配置 | +| `keyMap` | `Map` | 按键代码到配置的映射(支持多键绑定同一操作) | +| `enabled` | `boolean` | 当前控制器是否启用(默认 `false`) | +| `list`(静态) | `Hotkey[]` | 静态属性,存储所有已创建的控制器实例 | + +--- + +## 构造方法 + +```typescript +function constructor(id: string, name: string): Hotkey; +``` + +- **参数** + - `id`: 控制器的唯一标识符 + - `name`: 控制器的显示名称 + +**示例** + +```typescript +const editorHotkey = new Hotkey('editor', '编辑器快捷键'); +``` + +--- + +## 方法说明 + +### `register` + +```typescript +function register(data: RegisterHotkeyData): this; +``` + +注册一个按键配置。 + +- **参数** + ```typescript + interface RegisterHotkeyData { + id: string; // 按键唯一标识(可含数字后缀,如 "copy_1") + name: string; // 显示名称(如 "复制") + defaults: KeyCode; // 默认按键代码 + ctrl?: boolean; // 是否默认需要 Ctrl 辅助键 + shift?: boolean; // 是否默认需要 Shift 辅助键 + alt?: boolean; // 是否默认需要 Alt 辅助键 + } + ``` + +**示例** + +```typescript +editorHotkey.register({ + id: 'copy', + name: '复制', + defaults: KeyCode.KeyC, + ctrl: true +}); +``` + +--- + +### `realize` + +```typescript +function realize(id: string, func: HotkeyFunc, config?: HotkeyEmitConfig): this; +``` + +为按键绑定触发逻辑。 + +- **参数** + - `id`: 目标按键 ID(无需后缀) + - `func`: 触发时执行的函数 + - `config`: 触发类型配置(节流/超时等) + +**示例** + +```typescript +editorHotkey.realize( + 'copy', + (id, key, ev) => { + console.log('执行复制操作'); + }, + { type: 'down-throttle', throttle: 500 } +); +``` + +--- + +### `group` + +```typescript +function group(id: string, name: string, keys?: RegisterHotkeyData[]): this; +``` + +创建按键分组,后续注册的按键自动加入该组。 + +- **参数** + - `id`: 分组唯一标识 + - `name`: 分组显示名称 + - `keys`: 可选,预注册的按键列表 + +--- + +### `set` + +```typescript +function set(id: string, key: KeyCode, assist: number, emit?: boolean): void; +``` + +动态修改按键绑定。 + +- **参数** + - `id`: 目标按键 ID + - `key`: 新按键代码 + - `assist`: 辅助键状态(二进制位:Ctrl=1<<0, Shift=1<<1, Alt=1<<2) + - `emit`: 是否触发 `set` 事件(默认 `true`) + +--- + +### `when` + +```typescript +function when(fn: () => boolean): this; +``` + +为当前作用域的按键绑定添加触发条件。 + +- **参数** + - `fn`: 条件函数,返回 `true` 时允许触发按键逻辑 + +**示例** + +```typescript +// 仅在游戏处于运行状态时允许触发 +controller.when(() => gameState === 'running'); +``` + +--- + +### `enable` + +```typescript +function enable(): void; +``` + +### `disable` + +```typescript +function disable(): void; +``` + +启用/禁用整个按键控制器(禁用后所有按键事件将被忽略)。 + +**示例** + +```typescript +// 暂停游戏时禁用按键 +controller.disable(); +``` + +--- + +### `use` + +```typescript +function use(symbol: symbol): void; +``` + +切换当前作用域,后续 `realize` 方法绑定的逻辑将关联到该作用域。 + +- **参数** + - `symbol`: 唯一作用域标识符 + +--- + +### `dispose` + +```typescript +function dispose(symbol?: symbol): void; +``` + +释放指定作用域及其绑定的所有按键逻辑。 + +- **参数** + - `symbol`(可选): 要释放的作用域(默认释放当前作用域) + +**示例** + +```typescript +const scope = Symbol(); +controller.use(scope); +// ...绑定操作... +controller.dispose(scope); // 释放该作用域 +``` + +--- + +### `emitKey` + +```typescript +function emitKey( + key: KeyCode, + assist: number, + type: KeyEventType, + ev: KeyboardEvent +): boolean; +``` + +手动触发按键事件(可用于模拟按键操作)。 + +- **参数** + - `key`: 按键代码 + - `assist`: 辅助键状态(二进制位:Ctrl=1<<0, Shift=1<<1, Alt=1<<2) + - `type`: 事件类型(`'up'` 或 `'down'`) + - `ev`: 原始键盘事件对象 +- **返回值** + `true` 表示事件被成功处理,`false` 表示无匹配逻辑 + +**示例** + +```typescript +// 模拟触发 Ctrl+S 保存操作 +controller.emitKey( + KeyCode.KeyS, + 1 << 0, // Ctrl 激活 + 'down', + new KeyboardEvent('keydown') +); +``` + +--- + +## 静态方法说明 + +### `Hotkey.get` + +```typescript +function get(id: string): Hotkey | undefined; +``` + +**静态方法**:根据 ID 获取控制器实例。 + +--- + +## 事件说明 + +| 事件名 | 参数类型 | 触发时机 | +| --------- | --------------------------------------------------- | ---------------- | +| `set` | `[id: string, key: KeyCode, assist: number]` | 按键绑定被修改时 | +| `emit` | `[key: KeyCode, assist: number, type: KeyEmitType]` | 按键被触发时 | +| `press` | `[key: KeyCode]` | 按键被按下时 | +| `release` | `[key: KeyCode]` | 按键被释放时 | + +**事件监听示例** + +```typescript +editorHotkey.on('emit', (key, assist) => { + console.log(`按键 ${KeyCode[key]} 触发,辅助键状态:${assist}`); +}); +``` + +--- + +## 总使用示例 + +::: code-group + +```typescript [注册] +import { gameKey } from '@motajs/system-action'; + +gameKey.register({ + id: 'jump', + name: '跳跃', + defaults: KeyCode.Space +}); +``` + +```typescript [实现] +import { useKey } from '@motajs/render-vue'; + +const [gameKey] = useKey(); + +// 绑定跳跃逻辑 +gameKey.realize('jump', () => { + player.jump(); +}); +``` + +::: diff --git a/docs/api/motajs-system-action/Keyboard.md b/docs/api/motajs-system-action/Keyboard.md new file mode 100644 index 0000000..f3929fa --- /dev/null +++ b/docs/api/motajs-system-action/Keyboard.md @@ -0,0 +1,221 @@ +# Keyboard API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +```mermaid +graph LR + Keyboard --> EventEmitter +``` + +## 类描述 + +`Keyboard` 是虚拟键盘的核心类,用于管理动态按键布局、处理按键事件及辅助键状态。继承自 `EventEmitter`,支持自定义事件监听。 + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| -------------- | ---------------- | ----------------------------------------------------------- | +| `id` | `string` | 键盘的唯一标识符 | +| `keys` | `KeyboardItem[]` | 当前键盘包含的按键列表(响应式数组) | +| `assist` | `number` | 辅助键状态(二进制位表示:Ctrl=1<<0, Shift=1<<1, Alt=1<<2) | +| `fontSize` | `number` | 按键文本字体大小(默认 18) | +| `list`(静态) | `Keyboard[]` | 静态属性,存储所有已创建的键盘实例 | + +**KeyboardItem 结构**: + +```typescript +interface KeyboardItem { + key: KeyCode; // 按键代码 + text?: string; // 显示文本(可选) + x: number; // X 坐标 + y: number; // Y 坐标 + width: number; // 宽度 + height: number; // 高度 +} +``` + +--- + +## 构造方法 + +```typescript +function constructor(id: string): Keyboard; +``` + +- **参数** + - `id`: 键盘的唯一标识符 + +**示例** + +```typescript +const numpad = new Keyboard('numpad'); +``` + +--- + +## 方法说明 + +### `add` + +```typescript +function add(item: KeyboardItem): Keyboard; +``` + +### `remove` + +```typescript +function remove(item: KeyboardItem): Keyboard; +``` + +添加/移除按键,返回当前实例以便链式调用。 + +**示例** + +```typescript +// 添加数字键 1 +numpad.add({ + key: KeyCode.Digit1, + text: '1', + x: 0, + y: 0, + width: 60, + height: 60 +}); + +// 移除按键 +numpad.remove(existingKey); +``` + +--- + +### `extend` + +```typescript +function extend( + keyboard: Keyboard, + offsetX?: number, + offsetY?: number +): Keyboard; +``` + +继承其他键盘的按键布局并添加偏移量。 + +**示例** + +```typescript +const extendedKB = new Keyboard('extended'); +extendedKB.extend(numpad, 100, 0); // 向右偏移 100px +``` + +--- + +### `emitKey` + +```typescript +function emitKey(key: KeyboardItem, index: number): void; +``` + +模拟触发按键事件(自动处理辅助键状态)。 + +--- + +### `createScope` + +```typescript +function createScope(): symbol; +``` + +### `disposeScope` + +```typescript +function disposeScope(): void; +``` + +管理事件监听作用域: + +- `createScope`: 创建新作用域(返回唯一标识符) +- `disposeScope`: 释放当前作用域 + +--- + +### `withAssist` + +```typescript +function withAssist(assist: number): symbol; +``` + +创建预设辅助键状态的作用域(如 `Ctrl+Shift`)。 + +--- + +### `Keyboard.get` + +```typescript +function get(id: string): Keyboard | undefined; +``` + +**静态方法**:根据 ID 获取键盘实例。 + +--- + +## 事件说明 + +| 事件名 | 参数类型 | 触发时机 | +| -------------- | ------------------------- | ------------------ | +| `add` | `KeyboardItem` | 新增按键时 | +| `remove` | `KeyboardItem` | 移除按键时 | +| `extend` | `Keyboard` | 继承其他键盘布局时 | +| `emit` | `item, assist, index, ev` | 触发按键时 | +| `scopeCreate` | `symbol` | 创建作用域时 | +| `scopeDispose` | `symbol` | 释放作用域时 | + +**事件监听示例** + +```typescript +numpad.on('emit', (item, assist) => { + console.log(`按键 ${item.key} 触发,辅助键状态:${assist}`); +}); +``` + +--- + +## 总使用示例 + +```typescript +import { KeyCode } from '@motajs/client-base'; +import { Keyboard } from '@motajs/system-action'; + +// 创建数字键盘 +const numpad = new Keyboard('numpad'); + +// 添加基础按键 +numpad + .add({ key: KeyCode.Digit1, x: 0, y: 0, width: 60, height: 60 }) + .add({ key: KeyCode.Digit2, x: 60, y: 0, width: 60, height: 60 }); + +// 添加功能键(带辅助状态) +const ctrlScope = numpad.withAssist(1 << 0); // Ctrl 激活 +numpad.add({ + key: KeyCode.KeyC, + text: '复制', + x: 120, + y: 0, + width: 120, + height: 60 +}); + +// 监听复制键 +numpad.on('emit', item => { + if (item.key === KeyCode.KeyC) { + console.log('执行复制操作'); + } +}); + +// 触发按键 +numpad.emitKey(numpad.keys[0], 0); // 模拟按下数字 1 + +// 获取键盘实例 +const foundKB = Keyboard.get('numpad'); +``` diff --git a/docs/api/motajs-system-action/index.md b/docs/api/motajs-system-action/index.md new file mode 100644 index 0000000..970f853 --- /dev/null +++ b/docs/api/motajs-system-action/index.md @@ -0,0 +1,3 @@ +# @motajs/system-action + +目录: diff --git a/docs/api/motajs-system-ui/GameUI.md b/docs/api/motajs-system-ui/GameUI.md new file mode 100644 index 0000000..c8dae21 --- /dev/null +++ b/docs/api/motajs-system-ui/GameUI.md @@ -0,0 +1,97 @@ +# GameUI API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +```mermaid +graph LR + GameUI --> IGameUI +``` + +_实现 `IGameUI` 接口_ + +## 接口描述 + +`IGameUI` 是 UI 系统的核心接口,定义了 UI 实例的基础结构和静态操作方法。 + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| -------------- | ---------------------------------- | ------------------------------------------------------------------- | +| `name` | `string` | 只读,UI 的唯一标识名称 | +| `component` | `C extends UIComponent` | 只读,关联的 Vue 组件实例 | +| `list`(静态) | `Map>` | 静态属性,存储所有已注册的 UI 实例,键为 `name`,值为 `GameUI` 实例 | + +--- + +## 构造方法 + +### `consturctor` + +```typescript +function constructor(name: string, component: C): GameUI; +``` + +- **参数** + - `name`: UI 的唯一标识名称 + - `component`: 关联的 Vue 组件实例 + +**示例** + +```typescript +import { defineComponent } from 'vue'; + +export const MyComponent = defineComponent(...); + +// 创建 UI 实例并自动注册到静态列表 +export const MyUI = new GameUI('my-ui', MyComponent); +``` + +--- + +## 方法说明 + +### `GameUI.get` + +```typescript +function get(id: string): GameUI | null; +``` + +**静态方法**:根据 UI 名称从静态列表获取实例。 + +- **参数** + - `id`: UI 的唯一标识名称 +- **返回值** + 匹配的 `GameUI` 实例,未找到时返回 `null` + +**示例** + +```typescript +// 获取名为 "home" 的 UI 实例 +const ui = GameUI.get('my-ui'); +if (ui) { + console.log(ui.component); // 输出关联的 Vue 组件 +} +``` + +--- + +## 总使用示例 + +```tsx +import { defineComponent } from 'vue'; +import { GameUI } from '@motajs/system-ui'; + +// 定义组件 +export const MyCom = defineComponent(() => { + return () => ( + + + + ); +}); + +// 定义 UI 实例 +export const MyUI = new GameUI('my-ui', MyCom); +``` diff --git a/docs/api/motajs-system-ui/UIController.md b/docs/api/motajs-system-ui/UIController.md new file mode 100644 index 0000000..e781db1 --- /dev/null +++ b/docs/api/motajs-system-ui/UIController.md @@ -0,0 +1,284 @@ +# UIController API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +```mermaid +graph LR + UIController --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +## 类描述 + +`UIController` 是 UI 控制系统的核心类,负责管理 UI 实例的显示栈、背景控制以及多种显示模式。继承自 `EventEmitter`,支持事件监听。想要编写 UI 请参考[深度指南](../../guide/ui.md)。 + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| --------------------- | ---------------------------- | --------------------------------------------------------------- | +| `stack` | `IUIInstance[]` (响应式数组) | 当前管理的 UI 实例栈 | +| `mode` | `UIMode` | UI 显示模式,默认为 `LastOnlyStack` | +| `background` | `IGameUI` | 背景 UI 的配置实例 | +| `backIns` | `ShallowRef` | 背景 UI 实例的响应式引用 | +| `showBack` | `ComputedRef` | 当前是否显示背景(用户设置与系统状态共同决定) | +| `active`(只读) | `boolean` | 系统是否显示背景 UI(等价于 `sysShowBack.value`) | +| `controllers`(静态) | `Map` | 静态属性,存储所有已创建的控制器实例,键为 `id`,值为控制器实例 | + +--- + +## 构造方法 + +### `constructor` + +```typescript +function constructor(id: string): UIController; +``` + +- **参数** + - `id`: 控制器的唯一标识符(若重复会触发警告日志) + +**示例** + +```typescript +const mainController = new UIController('main'); +``` + +--- + +## 方法说明 + +### `render` + +```typescript +function render(): VNode; +``` + +渲染 UI 容器组件(用于 Vue 挂载)。 + +**示例** + +```tsx +import { defineComponent } from 'vue'; +import { UIController } from '@motajs/system-ui'; + +export const myController = new UIController('my-controller'); + +export const MyCom = defineComponent(() => { + return () => {myController.render()}; +}); +``` + +--- + +### `setBackground` + +```typescript +function setBackground( + back: IGameUI, + vBind: UIProps +): void; +``` + +设置背景 UI 并初始化其实例。 + +- **参数** + - `back`: 背景 UI 配置实例 + - `vBind`: 传递给背景组件的 Props 对象 + +**示例** + +```typescript +import { BackgroundUI } from './background'; + +// 显示背景组件,并传入参数 theme='dark' +mainController.setBackground(BackgroundUI, { theme: 'dark' }); +``` + +--- + +### `hideBackground` + +```typescript +function hideBackground(): void; +``` + +隐藏背景 UI (不影响系统状态)。 + +--- + +### `showBackground` + +```typescript +function showBackground(): void; +``` + +显示背景 UI(不影响系统状态)。 + +--- + +### `keep` + +```typescript +function keep(): IKeepController; +``` + +维持背景显示(防闪烁),返回控制器对象: + +```typescript +interface IKeepController { + safelyUnload(): void; // 安全卸载(仅在栈为空时关闭) + unload(): void; // 强制立即卸载 +} +``` + +**示例** + +```typescript +const keeper = mainController.keep(); +// 执行某些操作后... +keeper.safelyUnload(); +``` + +--- + +### `open` + +```typescript +function open( + ui: IGameUI, + vBind: UIProps, + alwaysShow?: boolean +): IUIInstance; +``` + +打开一个新 UI 实例并加入栈中。 + +- **参数** + - `ui`: UI 配置实例 + - `vBind`: 组件 Props + - `alwaysShow`: 是否强制显示(默认 `false`) +- **返回值** + 打开的 UI 实例,可以用于关闭等操作 + +**示例** + +```typescript +import { MyUI } from './myUI'; + +const instance = mainController.open(MyUI, { param: 80 }); +``` + +--- + +### `close` + +```typescript +function close(ui: IUIInstance): void; +``` + +关闭指定 UI 实例(根据当前模式可能影响其他实例)。 + +--- + +### `closeAll` + +```typescript +function closeAll(ui?: IGameUI): void; +``` + +关闭所有或指定类型的所有 UI 实例。 + +- **参数** + - `ui`(可选): 指定要关闭的 UI 类型,不填时表示关闭所有 UI + +--- + +### `lastOnly` + +```typescript +function lastOnly(stack?: boolean): void; +``` + +切换显示模式:仅显示最后一个 UI(可设置为栈模式) + +--- + +### `showAll` + +```typescript +function showAll(stack?: boolean): void; +``` + +切换显示模式:显示所有非隐藏 UI(可设置为栈模式) + +--- + +### `showCustom` + +```typescript +function showCustom(config: IUICustomConfig): void; +``` + +切换显示模式:使用自定义模式(需实现 `IUICustomConfig`),参考[指南](../../guide/ui-system.md#自定义显示模式) + +--- + +### `UIController.getController` + +```typescript +function getController(id: string): UIController | null; +``` + +**静态方法**:根据 ID 获取控制器实例。 + +**示例** + +```typescript +const ctrl = UIController.getController('main'); +``` + +--- + +## 事件说明 + +| 事件名 | 参数类型 | 触发时机 | +| ------- | ------------------------------- | ------------------ | +| `open` | `ui: IGameUI, ins: IUIInstance` | 新 UI 实例被打开时 | +| `close` | `ins: IUIInstance` | UI 实例被关闭时 | + +**事件监听示例** + +```typescript +mainController.on('open', (ui, ins) => { + console.log(`Opened UI: ${ui.name}`); +}); +``` + +--- + +## 总使用示例 + +```typescript +import { BackgroundUI, DialogUI } from './myUI'; +import { mainController } from '@user/client-modules'; + +// 事件监听 +mainController.on('close', ins => { + console.log('UI closed:', ins.ui.name); +}); + +// 设置背景 +mainController.setBackground(BackgroundUI, { color: '#333' }); + +// 打开 UI +const dialogIns = mainController.open(DialogUI, { title: '提示' }); + +// 切换显示模式,仅显示最后一个,启用栈模式 +mainController.lastOnly(true); + +// 关闭 UI +mainController.close(dialogIns); +``` diff --git a/docs/api/motajs-system-ui/UIInstance.md b/docs/api/motajs-system-ui/UIInstance.md new file mode 100644 index 0000000..53c7890 --- /dev/null +++ b/docs/api/motajs-system-ui/UIInstance.md @@ -0,0 +1,121 @@ +# UIInstance API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +```mermaid +graph LR + UIInstance --> IUIInstance +``` + +_实现 `IUIInstance` 接口_ + +## 类描述 + +`UIInstance` 表示通过 `GameUI` 模板创建的具体 UI 实例,用于管理单个 UI 实例的状态和数据绑定。实现了 `IUIInstance` 接口。 + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| ------------ | ------------ | -------------------------------------------------------- | +| `key` | `number` | 只读,实例的唯一标识(用于 Vue 的 `key` 属性) | +| `ui` | `IGameUI` | 只读,关联的 UI 配置实例(即创建该实例的 `GameUI` 模板) | +| `vBind` | `UIProps` | 只读,传递给 UI 组件的响应式 Props 对象 | +| `hidden` | `boolean` | 当前实例是否处于隐藏状态 | +| `alwaysShow` | `boolean` | 是否强制保持显示(不受显示模式影响) | + +--- + +## 构造方法 + +```typescript +function constructor( + ui: IGameUI, + vBind: UIProps, + alwaysShow: boolean = false +): UIInstance; +``` + +- **参数** + - `ui`: 关联的 `GameUI` 配置实例 + - `vBind`: 初始化的组件 Props 对象 + - `alwaysShow`: 是否强制保持显示(默认 `false`) + +**注意事项**:一般不需要手动创建 `UIInstance` 实例,请使用 [`UIController.open`](./UIController.md#open) 打开 UI 并创建实例。 + +--- + +## 方法说明 + +### `setVBind` + +```typescript +function setVBind(data: Partial>, merge?: boolean): void; +``` + +更新组件的响应式 Props。 + +- **参数** + - `data`: 需要更新的数据(部分 Props) + - `merge`: 是否与现有数据合并(默认 `true`),若为 `false` 则完全覆盖 + +**示例** + +```typescript +// 合并更新音量值 +instance.setVBind({ volume: 60 }); + +// 覆盖所有 Props +instance.setVBind({ theme: 'dark' }, false); +``` + +--- + +### `hide` + +```typescript +function hide(): void; +``` + +控制实例的显示状态(直接操作 `hidden` 属性)。 + +**示例** + +```typescript +instance.hide(); // 隐藏 UI +setTimeout(() => instance.show(), 1000); // 1 秒后显示 +``` + +--- + +### `show` + +```typescript +function show(): void; +``` + +控制实例的显示状态(直接操作 `hidden` 属性)。 + +**示例** + +```typescript +instance.show(); // 隐藏 UI +setTimeout(() => instance.show(), 1000); // 1 秒后显示 +``` + +--- + +## 总使用示例 + +```typescript +import { myController, MyUI } from './myUI'; + +const myIns = myController.open(MyUI, { title: '警告' }); + +// 动态更新 props +myIns.setVBind({ title: '错误' }); + +// 设置显示状态 +myIns.show(); +``` diff --git a/docs/api/motajs-system-ui/index.md b/docs/api/motajs-system-ui/index.md new file mode 100644 index 0000000..f84a151 --- /dev/null +++ b/docs/api/motajs-system-ui/index.md @@ -0,0 +1,3 @@ +# @motajs/system-ui + +目录: diff --git a/docs/api/motajs-system/index.md b/docs/api/motajs-system/index.md new file mode 100644 index 0000000..76a8633 --- /dev/null +++ b/docs/api/motajs-system/index.md @@ -0,0 +1,25 @@ +# @motajs/system + +包含两个模块: + +- [`@motajs/system-action`](../motajs-system-action/index.md) +- [`@motajs/system-ui`](../motajs-system-ui/index.md) + +## 引入示例 + +```ts +import { gameKey, UIController } from '@motajs/system'; + +gameKey.register(...); +const myController = new UIController('my-controller'); +``` + +等效于: + +```ts +import { gameKey } from '@motajs/system-action'; +import { UIController } from '@motajs/system-ui'; + +gameKey.register(...); +const myController = new UIController('my-controller'); +``` diff --git a/docs/api/motajs-types/index.md b/docs/api/motajs-types/index.md new file mode 100644 index 0000000..d3d5030 --- /dev/null +++ b/docs/api/motajs-types/index.md @@ -0,0 +1,3 @@ +# @motajs/types + +目录: diff --git a/docs/api/user-client-modules/AudioDecoder.md b/docs/api/user-client-modules/AudioDecoder.md new file mode 100644 index 0000000..249c8aa --- /dev/null +++ b/docs/api/user-client-modules/AudioDecoder.md @@ -0,0 +1,142 @@ +# AudioDecoder API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 类描述 + +音频解码系统的核心抽象类,为不同音频格式提供统一的解码接口。主要处理浏览器原生不支持音频格式的解码任务(如 iOS 平台的 Ogg 格式)。 + +--- + +## 静态成员说明 + +### `decoderMap` + +```typescript +declare const decoderMap: Map AudioDecoder>; +``` + +解码器注册表,存储格式类型与解码器类的映射关系 + +--- + +## 静态方法说明 + +### `AudioDecoder.registerDecoder` + +```typescript +function registerDecoder( + type: AudioType, + decoder: new () => AudioDecoder +): void; +``` + +注册自定义解码器到全局解码器系统 + +| 参数 | 类型 | 说明 | +| ------- | ------------------------ | -------------- | +| type | `AudioType` | 音频格式类型 | +| decoder | `new () => AudioDecoder` | 解码器构造函数 | + +--- + +### `AudioDecoder.decodeAudioData` + +```typescript +function decodeAudioData( + data: Uint8Array, + player: AudioPlayer +): Promise; +``` + +核心解码入口方法,自动选择最佳解码方案 + +| 参数 | 类型 | 说明 | +| ------ | ------------- | ---------------- | +| data | `Uint8Array` | 原始音频字节数据 | +| player | `AudioPlayer` | 音频播放器实例 | + +**处理流程**: + +1. 通过文件头检测音频类型 +2. 优先使用浏览器原生解码能力 +3. 无原生支持时查找注册的自定义解码器 +4. 返回标准 `AudioBuffer` 格式数据 + +--- + +## 抽象方法说明 + +### `abstract create` + +```typescript +function create(): Promise; +``` + +初始化解码器实例(需分配 WASM 内存等资源) + +--- + +### `abstract destroy` + +```typescript +function destroy(): void; +``` + +销毁解码器实例(需释放资源) + +--- + +### `abstract decode` + +```typescript +function decode(data: Uint8Array): Promise; +``` + +流式解码方法(分块处理) + +| 参数 | 类型 | 说明 | +| ---- | ------------ | ------------ | +| data | `Uint8Array` | 音频数据分块 | + +--- + +### `abstract decodeAll` + +```typescript +function decodeAll(data: Uint8Array): Promise; +``` + +全量解码方法(单次处理完整文件) + +--- + +### `abstract flush` + +```typescript +function flush(): Promise; +``` + +冲刷解码器缓冲区,获取残留数据 + +--- + +## 数据结构 + +### IAudioDecodeData + +```typescript +interface IAudioDecodeData { + channelData: Float32Array[]; // 各声道 PCM 数据 + samplesDecoded: number; // 已解码采样数 + sampleRate: number; // 采样率 (Hz) + errors: IAudioDecodeError[]; // 解码错误集合 +} +``` + +## 内置解码器 + +- `VorbisDecoder`: 解码 ogg vorbis 音频。 +- `OpusDecoder`: 解码 ogg opus 音频。 diff --git a/docs/api/user-client-modules/AudioEffect.md b/docs/api/user-client-modules/AudioEffect.md new file mode 100644 index 0000000..0853131 --- /dev/null +++ b/docs/api/user-client-modules/AudioEffect.md @@ -0,0 +1,207 @@ +# AudioEffect API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 类描述 + +音频处理管道的核心抽象类,为构建音频效果链提供基础框架。所有效果器通过输入/输出节点串联,形成可定制的音频处理流水线。 + +--- + +## 核心架构 + +音频播放流程: + +```mermaid +graph LR + Source --> Effect1 + Effect1 --> Effect2[...] + Effect2 --> GainNode + GainNode --> Destination +``` + +--- + +## 抽象成员说明 + +| 成员 | 类型 | 说明 | +| -------- | ----------- | -------------------------- | +| `input` | `AudioNode` | 效果器输入节点(必须实现) | +| `output` | `AudioNode` | 效果器输出节点(必须实现) | + +--- + +## 核心方法说明 + +### `connect` + +```typescript +function connect(target: IAudioInput, output?: number, input?: number): void; +``` + +连接至下游音频节点 + +| 参数 | 类型 | 说明 | +| ------ | ------------- | -------------------------- | +| target | `IAudioInput` | 目标效果器/节点 | +| output | `number` | 当前效果器输出通道(可选) | +| input | `number` | 目标效果器输入通道(可选) | + +--- + +### `disconnect` + +```typescript +function disconnect( + target?: IAudioInput, + output?: number, + input?: number +): void; +``` + +断开与下游节点的连接 + +--- + +### `abstract start` + +```typescript +function start(): void; +``` + +效果器激活时调用(可用于初始化参数) + +--- + +### `abstract end` + +```typescript +function end(): void; +``` + +效果器停用时调用(可用于资源回收) + +--- + +## 自定义效果器示例 + +### 混响效果器实现 + +```typescript +export class ReverbEffect extends AudioEffect { + private convolver: ConvolverNode; + private dryGain: GainNode; + private wetGain: GainNode; + + constructor(ac: AudioContext) { + super(ac); + + // 创建节点网络 + this.dryGain = ac.createGain(); + this.wetGain = ac.createGain(); + this.convolver = ac.createConvolver(); + + // 定义输入输出 + this.input = this.dryGain; + this.output = this.ac.createGain(); + + // 构建处理链 + this.dryGain.connect(this.output); + this.dryGain.connect(this.convolver); + this.convolver.connect(this.wetGain); + this.wetGain.connect(this.output); + } + + /** 设置混响强度 */ + setMix(value: number) { + this.dryGain.gain.value = 1 - value; + this.wetGain.gain.value = value; + } + + /** 加载脉冲响应 */ + async loadImpulse(url: string) { + const response = await fetch(url); + const buffer = await this.ac.decodeAudioData( + await response.arrayBuffer() + ); + this.convolver.buffer = buffer; + } + + start() { + this.output.gain.value = 1; + } + + end() { + this.output.gain.value = 0; + } +} +``` + +--- + +## 内置效果器说明 + +### StereoEffect(立体声控制) + +```mermaid +graph LR + Input --> Panner[PannerNode] + Panner --> Output +``` + +- 控制声相/3D 空间定位 +- 支持设置声音方位和位置 + +### VolumeEffect(音量控制) + +```mermaid +graph LR + Input --> Gain[GainNode] + Gain --> Output +``` + +- 全局音量调节 +- 支持实时音量渐变 + +### ChannelVolumeEffect(多声道控制) + +```mermaid +graph LR + Input --> Splitter[ChannelSplitter] + Splitter --> Gain1 + Splitter --> Gain2 + Gain1 --> Merger + Gain2 --> Merger + Merger --> Output +``` + +- 6 声道独立音量控制 +- 支持环绕声场调节 + +### DelayEffect(延迟效果) + +```mermaid +graph LR + Input --> Delay[DelayNode] + Delay --> Output +``` + +- 基础延迟效果 +- 精确到采样级的延迟控制 + +### EchoEffect(回声效果) + +```mermaid +graph LR + Input --> Gain + Gain --> Delay + Delay --> Gain[反馈循环] + Gain --> Output +``` + +- 带反馈的延迟效果 +- 自动渐弱回声处理 + +--- diff --git a/docs/api/user-client-modules/AudioPlayer.md b/docs/api/user-client-modules/AudioPlayer.md new file mode 100644 index 0000000..0a5125b --- /dev/null +++ b/docs/api/user-client-modules/AudioPlayer.md @@ -0,0 +1,172 @@ +# AudioPlayer API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 类描述 + +音频系统的核心控制器,负责管理音频上下文、路由系统、效果器工厂和全局音频参数。支持多音轨管理和 3D 音频空间化配置。 + +```mermaid +graph LR + AudioPlayer --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 核心架构 + +```mermaid +graph TD + Player[AudioPlayer] --> Sources[音频源工厂] + Player --> Effects[效果器工厂] + Player --> Routes[路由系统] + Player --> Listener[3D 听者配置] +``` + +--- + +## 属性说明 + +| 属性名 | 类型 | 说明 | +| ------------- | ------------------------- | ------------------------ | +| `ac` | `AudioContext` | Web Audio API 上下文实例 | +| `audioRoutes` | `Map` | 已注册的音频路由表 | +| `gain` | `GainNode` | 全局音量控制节点 | + +--- + +## 方法说明 + +此处暂时只列出方法的简易说明。方法理解难度不高,如果需要可以自行查看代码以及其相关注释来查看如何使用。 + +### 音频源工厂方法 + +| 方法名 | 返回值 | 说明 | +| ----------------------- | -------------------- | ----------------------------- | +| `createSource(Source)` | `AudioSource` | 创建自定义音频源 | +| `createStreamSource()` | `AudioStreamSource` | 创建流式音频源(直播/长音频) | +| `createElementSource()` | `AudioElementSource` | 基于 HTML5 Audio 元素的音源 | +| `createBufferSource()` | `AudioBufferSource` | 基于 AudioBuffer 的静态音源 | + +### 效果器工厂方法 + +| 方法名 | 返回值 | 说明 | +| ----------------------------- | --------------------- | ---------------------------- | +| `createEffect(Effect)` | `AudioEffect` | 创建自定义效果器 | +| `createVolumeEffect()` | `VolumeEffect` | 全局音量控制器 | +| `createStereoEffect()` | `StereoEffect` | 立体声场控制器 | +| `createChannelVolumeEffect()` | `ChannelVolumeEffect` | 多声道独立音量控制(6 声道) | +| `createDelayEffect()` | `DelayEffect` | 精确延迟效果器 | +| `createEchoEffect()` | `EchoEffect` | 回声效果器(带反馈循环) | + +### 路由管理方法 + +| 方法名 | 参数 | 说明 | +| --------------------- | -------------------- | -------------- | +| `createRoute(source)` | `AudioSource` | 创建新播放路由 | +| `addRoute(id, route)` | `string, AudioRoute` | 注册命名路由 | +| `getRoute(id)` | `string` | 获取已注册路由 | +| `removeRoute(id)` | `string` | 移除指定路由 | + +### 全局控制方法 + +| 方法名 | 参数 | 说明 | +| ------------------------------- | ------------------------ | -------------------- | +| `setVolume(volume)` | `number` (0.0-1.0) | 设置全局音量 | +| `getVolume()` | - | 获取当前全局音量 | +| `setListenerPosition(x,y,z)` | `number, number, number` | 设置听者 3D 空间坐标 | +| `setListenerOrientation(x,y,z)` | `number, number, number` | 设置听者朝向 | +| `setListenerUp(x,y,z)` | `number, number, number` | 设置听者头顶朝向 | + +--- + +## 使用示例 + +### 基础音乐播放 + +```typescript +import { audioPlayer } from '@user/client-modules'; + +// 创建音频源(以音频缓冲为例) +const bgmSource = audioPlayer.createBufferSource(); + +// 创建播放路由 +const bgmRoute = audioPlayer.createRoute(bgmSource); + +// 添加效果链 +bgmRoute.addEffect([ + audioPlayer.createStereoEffect(), + audioPlayer.createVolumeEffect() +]); + +// 播放控制 +audioPlayer.play('bgm'); +audioPlayer.pause('bgm'); +``` + +### 3D 环境音效 + +```typescript +import { audioPlayer } from '@user/client-modules'; + +// 配置3D听者 +audioPlayer.setListenerPosition(0, 0, 0); // 听者在原点 +audioPlayer.setListenerOrientation(0, 0, -1); // 面朝屏幕内 + +// 创建环境音源 +const ambientSource = audioPlayer.createBufferSource(); +await ambientSource.setBuffer(/* 这里填写音频缓冲 */); + +// 配置3D音效路由 +const ambientRoute = audioPlayer.createRoute(ambientSource); +const stereo = audioPlayer.createStereoEffect(); +stereo.setPosition(5, 2, -3); // 音源位于右前方高处 +ambientRoute.addEffect(stereo); + +// 循环播放 +ambientRoute.setLoop(true); +audioPlayer.addRoute('ambient', ambientRoute); +audioPlayer.play('ambient'); +``` + +--- + +## 生命周期管理 + +```mermaid +sequenceDiagram + participant User + participant AudioPlayer + participant AudioContext + + User->>AudioPlayer: new AudioPlayer() + AudioPlayer->>AudioContext: 创建音频上下文 + User->>AudioPlayer: createRoute() + AudioPlayer->>AudioRoute: 实例化路由 + User->>AudioPlayer: play() + AudioPlayer->>AudioContext: 启动音频时钟 + loop 播放周期 + AudioPlayer->>AudioRoute: 更新状态 + end + User->>AudioPlayer: stop() + AudioPlayer->>AudioRoute: 释放资源 + AudioPlayer->>AudioContext: 关闭上下文 +``` + +--- + +## 注意事项 + +1. **空间音频配置** + 3D 效果需统一坐标系: + + ```txt + (0,0,0) 屏幕中心 + X+ → 右 + Y+ ↑ 上 + Z+ ⊙ 朝向用户 + ``` diff --git a/docs/api/user-client-modules/AudioRoute.md b/docs/api/user-client-modules/AudioRoute.md new file mode 100644 index 0000000..681f00f --- /dev/null +++ b/docs/api/user-client-modules/AudioRoute.md @@ -0,0 +1,221 @@ +# AudioRoute 音频播放路由 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 类描述 + +音频播放控制的核心类,负责管理音频源与效果器的连接关系,协调播放状态转换,并处理音频管线生命周期。 + +```mermaid +graph LR + AudioRoute --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 属性说明 + +| 属性名 | 类型 | 说明 | +| ------------- | ------------------ | ------------------------------------------------ | +| `output` | `AudioNode` | 最终输出节点(继承自 IAudioOutput) | +| `effectRoute` | `AudioEffect[]` | 效果器链数组(按顺序存储已连接的效果器实例) | +| `endTime` | `number` | 淡出过渡时长(单位:秒),默认 0 | +| `status` | `AudioStatus` | 当前播放状态(见下方枚举定义) | +| `duration` | `number` (getter) | 音频总时长(单位:秒) | +| `currentTime` | `number` (get/set) | 当前播放进度(单位:秒),设置时会触发 seek 操作 | + +--- + +### AudioStatus 枚举 + +```typescript +enum AudioStatus { + Playing, // 正在播放 + Pausing, // 淡出暂停过程中 + Paused, // 已暂停 + Stoping, // 淡出停止过程中 + Stoped // 已停止 +} +``` + +--- + +## 方法说明 + +### `setEndTime` + +```typescript +function setEndTime(time: number): void; +``` + +设置淡出过渡时长 + +| 参数 | 类型 | 说明 | +| ---- | -------- | ------------------------ | +| time | `number` | 淡出动画时长(单位:秒) | + +--- + +### `onStart` + +```typescript +function onStart(fn?: (route: AudioRoute) => void): void; +``` + +注册播放开始钩子函数 + +| 参数 | 类型 | 说明 | +| ---- | ----------------- | ------------------------ | +| `fn` | `(route) => void` | 播放开始时触发的回调函数 | + +--- + +### `onEnd` + +```typescript +function onEnd(fn?: (time: number, route: AudioRoute) => void): void; +``` + +注册播放结束钩子函数 + +| 参数 | 类型 | 说明 | +| ---- | --------------------------- | --------------------------------------------- | +| `fn` | `(duration, route) => void` | 淡出阶段开始时触发的回调,duration 为淡出时长 | + +--- + +### `play` + +```typescript +function play(when?: number = 0): Promise; +``` + +启动/恢复音频播放 + +| 参数 | 类型 | 说明 | +| ------ | -------- | -------------------------------------- | +| `when` | `number` | 基于 AudioContext 时间的启动时刻(秒) | + +--- + +### `pause` + +```typescript +function pause(): Promise; +``` + +触发暂停流程(执行淡出过渡) + +--- + +### `resume` + +```typescript +function resume(): void; +``` + +从暂停状态恢复播放(执行淡入过渡) + +--- + +### `stop` + +```typescript +function stop(): Promise; +``` + +完全停止播放并释放资源 + +--- + +### `addEffect` + +```typescript +function addEffect(effect: AudioEffect | AudioEffect[], index?: number): void; +``` + +添加效果器到处理链 + +| 参数 | 类型 | 说明 | +| -------- | ------------------ | ------------------------------ | +| `effect` | `AudioEffect`/数组 | 要添加的效果器实例 | +| `index` | `number` (可选) | 插入位置,负数表示从末尾倒计数 | + +--- + +### `removeEffect` + +```typescript +function removeEffect(effect: AudioEffect): void; +``` + +从处理链移除效果器 + +| 参数 | 类型 | 说明 | +| -------- | ------------- | ------------------ | +| `effect` | `AudioEffect` | 要移除的效果器实例 | + +--- + +## 事件说明 + +| 事件名 | 参数 | 触发时机 | +| -------------- | ---- | ------------------ | +| `updateEffect` | - | 效果器链发生变更时 | +| `play` | - | 开始/恢复播放时 | +| `stop` | - | 完全停止播放后 | +| `pause` | - | 进入暂停状态后 | +| `resume` | - | 从暂停状态恢复时 | + +--- + +## 总使用示例 + +```typescript +import { audioPlayer } from '@user/client-modules'; + +// 创建音频播放器和路由 +const source = audioPlayer.createBufferSource(); +const route = audioPlayer.createRoute(audioSource); + +// 配置效果链 +const stereo = audioPlayer.createStereoEffect(); +const echo = audioPlayer.createEchoEffect(); +const volume = audioPlayer.createVolumeEffect(); + +route.addEffect([stereo, echo], 0); // 插入到链首 +route.addEffect(volume); // 音量控制放到链尾 + +// 播放暂停 +await route.play(); +await route.pause(); +route.resume(); // 继续操作不是异步,不需要 await +await route.stop(); +``` + +--- + +## 处理流程示意图 + +```mermaid +sequenceDiagram + participant User + participant AudioRoute + participant Effects + + User->>AudioRoute: play() + AudioRoute->>Effects: 启动所有效果器 + Effects-->>AudioRoute: 准备完成 + AudioRoute->>Source: 开始播放 + loop 播放中 + AudioRoute->>Effects: 实时音频处理 + end + User->>AudioRoute: pause() + AudioRoute->>Effects: 启动淡出过渡 + Effects-->>AudioRoute: 过渡完成 + AudioRoute->>Source: 暂停播放 +``` diff --git a/docs/api/user-client-modules/AudioSource.md b/docs/api/user-client-modules/AudioSource.md new file mode 100644 index 0000000..e3c0e20 --- /dev/null +++ b/docs/api/user-client-modules/AudioSource.md @@ -0,0 +1,184 @@ +# AudioSource API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 类描述 + +音频系统的源头抽象类,定义了音频播放的核心控制接口。支持多种音频源类型,包括流媒体、HTML 音频元素和静态音频缓冲。 + +```mermaid +graph LR + AudioPlayer --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 抽象成员说明 + +| 成员 | 类型 | 说明 | +| ------------- | ----------- | ------------------------ | +| `output` | `AudioNode` | 音频输出节点(必须实现) | +| `duration` | `number` | 音频总时长(秒) | +| `currentTime` | `number` | 当前播放时间(秒) | +| `playing` | `boolean` | 播放状态标识 | + +--- + +## 核心方法说明 + +### `abstract play` + +```typescript +function play(when?: number): void; +``` + +启动音频播放时序 + +| 参数 | 类型 | 说明 | +| ---- | -------- | ----------------------------------------------- | +| when | `number` | 预定播放时间(基于 `AudioContext.currentTime`) | + +--- + +### `abstract stop` + +```typescript +function stop(): number; +``` + +停止播放并返回停止时刻 + +--- + +### `abstract connect` + +```typescript +function connect(target: IAudioInput): void; +``` + +连接至音频处理管线 + +| 参数 | 类型 | 说明 | +| ------ | ------------- | ------------------- | +| target | `IAudioInput` | 下游处理节点/效果器 | + +--- + +### `abstract setLoop` + +```typescript +function setLoop(loop: boolean): void; +``` + +设置循环播放模式 + +--- + +## 事件系统 + +| 事件名 | 参数 | 触发时机 | +| ------ | ---- | -------------- | +| `play` | - | 开始播放时 | +| `end` | - | 自然播放结束时 | + +--- + +## 自定义音频源示例 + +### 网络实时通话源 + +```typescript +class WebRTCAudioSource extends AudioSource { + private mediaStream: MediaStreamAudioSourceNode; + output: AudioNode; + + constructor(ac: AudioContext, stream: MediaStream) { + super(ac); + this.mediaStream = ac.createMediaStreamSource(stream); + this.output = this.mediaStream; + } + + get duration() { + return Infinity; + } // 实时流无固定时长 + get currentTime() { + return this.ac.currentTime; + } + + play() { + this.mediaStream.connect(this.output); + this.playing = true; + this.emit('play'); + } + + stop() { + this.mediaStream.disconnect(); + this.playing = false; + return this.ac.currentTime; + } + + connect(target: IAudioInput) { + this.output.connect(target.input); + } + + setLoop() {} // 实时流不支持循环 +} + +// 使用示例 +navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => { + const source = new WebRTCAudioSource(audioContext, stream); + source.connect(effectsChain); + source.play(); +}); +``` + +--- + +## 内置实现说明 + +### AudioStreamSource(流媒体源) + +```mermaid +graph LR + Network[网络数据流] --> Buffer[缓冲区] + Buffer --> Decoder[音频解码器] + Decoder --> Output[实时音频节点] +``` + +- 支持渐进式加载 +- 动态缓冲管理 +- 适用于浏览器自身不支持的音频类型 + +### AudioElementSource(HTML 音频元素源) + +```mermaid +graph LR + AudioTag[audio 元素] -->|音频流| Output[媒体元素源节点] +``` + +- 基于 HTML5 Audio 元素 +- 支持跨域资源 +- 自动处理音频格式兼容 + +### AudioBufferSource(静态音频缓冲源) + +```mermaid +graph LR + File[音频文件] --> Decode[解码为 AudioBuffer] + Decode --> Output[缓冲源节点] +``` + +- 完整音频数据预加载 +- 精确播放控制 +- 支持内存音频播放 + +--- + +## 注意事项 + +1. **时间精度** + 所有时间参数均以 `AudioContext.currentTime` 为基准,精度可达 0.01 秒 diff --git a/docs/api/user-client-modules/BgmController.md b/docs/api/user-client-modules/BgmController.md new file mode 100644 index 0000000..0930c54 --- /dev/null +++ b/docs/api/user-client-modules/BgmController.md @@ -0,0 +1,158 @@ +# BgmController API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +```mermaid +graph LR + BgmController --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +## 类描述 + +`BgmController` 是背景音乐系统的核心控制器,支持多 BGM 的加载、音量控制、渐变切换和播放状态管理。继承自 `EventEmitter`,提供完整的音频事件监听机制。 + +--- + +## 泛型说明 + +- `T extends string`: BGM 的唯一标识符类型(默认为项目预定义的 `BgmIds`) + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| ---------------- | --------- | ----------------------------------------- | +| `prefix` | `string` | BGM 资源路径前缀(默认 `bgms.`) | +| `playingBgm` | `T` | 当前正在播放的 BGM ID | +| `enabled` | `boolean` | 是否启用音频控制(默认 true) | +| `transitionTime` | `number` | 音频切换渐变时长(单位:毫秒,默认 2000) | + +--- + +## 核心方法说明 + +### `setTransitionTime` + +```typescript +function setTransitionTime(time: number): void; +``` + +设置所有 BGM 的渐变切换时长。 + +- **参数** + - `time`: 渐变时长(毫秒) + +--- + +### `blockChange` + +```typescript +function blockChange(): void; +``` + +### `unblockChange` + +```typescript +function unblockChange(): void; +``` + +屏蔽/解除屏蔽 BGM 切换(用于特殊场景)。 + +--- + +### `setVolume` + +```typescript +function setVolume(volume: number): void; +``` + +### `getVolume` + +```typescript +function getVolume(): number; +``` + +控制全局音量(范围 0-1)。 + +--- + +### `setEnabled` + +```typescript +function setEnabled(enabled: boolean): void; +``` + +启用/禁用整个 BGM 系统(禁用时停止所有播放)。 + +--- + +### `addBgm` + +```typescript +function addBgm(id: T, url?: string): void; +``` + +加载并注册 BGM 资源。 + +- **参数** + - `id`: BGM 唯一标识 + - `url`: 自定义资源路径(默认 `project/bgms/${id}`) + +--- + +### `removeBgm` + +```typescript +function removeBgm(id: T): void; +``` + +移除已注册的 BGM 资源。 + +--- + +### 播放控制方法 + +```typescript +function play(id: T, when?: number): void; // 播放指定 BGM(带渐变) +function pause(): void; // 暂停当前 BGM(保留进度) +function resume(): void; // 继续播放当前 BGM +function stop(): void; // 停止当前 BGM(重置进度) +``` + +--- + +## 事件说明 + +| 事件名 | 参数 | 触发时机 | +| -------- | ---- | ----------------- | +| `play` | `[]` | 开始播放新 BGM 时 | +| `pause` | `[]` | 暂停播放时 | +| `resume` | `[]` | 继续播放时 | +| `stop` | `[]` | 完全停止播放时 | + +--- + +## 总使用示例 + +```typescript +import { bgmController } from '@user/client-modules'; + +// 设置全局参数 +bgmCtrl.setTransitionTime(1500); +bgmCtrl.setVolume(0.8); + +// 播放控制 +bgmCtrl.play('battle.mp3'); // 播放战斗BGM +bgmCtrl.pause(); // 暂停(如打开菜单) +bgmCtrl.resume(); // 继续播放 +bgmCtrl.play('boss_battle.mp3'); // 切换至BOSS战BGM +bgmCtrl.stop(); // 完全停止(如战斗结束) + +// 事件监听 +bgmCtrl.on('play', () => { + console.log('BGM 开始播放:', bgmCtrl.playingBgm); +}); +``` diff --git a/docs/api/user-client-modules/HeroKeyMover.md b/docs/api/user-client-modules/HeroKeyMover.md new file mode 100644 index 0000000..a5e5350 --- /dev/null +++ b/docs/api/user-client-modules/HeroKeyMover.md @@ -0,0 +1,147 @@ +# HeroKeyMover API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +## 类描述 + +`HeroKeyMover` 是勇士按键移动的核心控制器,负责将热键系统与勇士移动逻辑结合,实现基于键盘输入的连续移动控制。支持多方向优先级处理和移动中断机制。 + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| ------------ | ----------- | ---------------------------------------- | +| `hotkey` | `Hotkey` | 关联的热键控制器实例 | +| `mover` | `HeroMover` | 勇士移动逻辑执行器 | +| `scope` | `symbol` | 当前移动触发的作用域(默认使用主作用域) | +| `hotkeyData` | `MoveKey` | 移动方向与热键的映射配置 | + +--- + +## 构造方法 + +```typescript +function constructor( + hotkey: Hotkey, + mover: HeroMover, + config?: MoveKeyConfig +): HeroKeyMover; +``` + +- **参数** + - `hotkey`: 已配置的热键控制器实例 + - `mover`: 勇士移动逻辑实例 + - `config`: 自定义方向键映射配置(可选) + +**默认按键映射**: + +```typescript +const map = { + left: 'moveLeft', + right: 'moveRight', + up: 'moveUp', + down: 'moveDown' +}; +``` + +--- + +## 方法说明 + +### `setScope` + +```typescript +function setScope(scope: symbol): void; +``` + +设置当前移动控制的作用域(用于多场景隔离)。 + +- **参数** + - `scope`: 唯一作用域标识符 + +--- + +### `press` + +```typescript +function press(dir: Dir): void; +``` + +触发指定方向的移动按键按下状态。 + +- **参数** + - `dir`: 移动方向(`'left' | 'right' | 'up' | 'down'`) + +--- + +### `release` + +```typescript +function release(dir: Dir): void; +``` + +解除指定方向的移动按键按下状态。 + +- **参数** + - `dir`: 要释放的移动方向 + +--- + +### `tryStartMove` + +```typescript +function tryStartMove(): boolean; +``` + +尝试启动移动逻辑(自动根据当前方向键状态判断)。 + +- **返回值** + `true` 表示移动成功启动,`false` 表示条件不满足 + +--- + +### `endMove` + +```typescript +function endMove(): void; +``` + +立即终止当前移动过程。 + +--- + +### `destroy` + +```typescript +function destroy(): void; +``` + +销毁控制器实例(自动解除所有事件监听)。 + +--- + +## 总使用示例 + +```typescript +import { gameKey, mainScope } from '@motajs/system-action'; + +// 初始化移动控制器 +const keyMover = new HeroKeyMover( + gameKey, + heroMover, + { left: 'moveLeft', right: 'moveRight' } // 自定义部分按键映射 +); + +// 设置允许触发的作用域 +keyMover.setScope(mainScope); + +// 销毁控制器 +keyMover.destroy(); +``` + +## 移动优先级机制 + +1. **最后按下优先**:当同时按下多个方向键时,以后按下的方向为准 +2. **队列延续**:在移动过程中持续检测按键状态,自动延续移动队列 +3. **作用域隔离**:只有当前作用域匹配时才会响应按键事件 diff --git a/docs/api/user-client-modules/SoundPlayer.md b/docs/api/user-client-modules/SoundPlayer.md new file mode 100644 index 0000000..28f36da --- /dev/null +++ b/docs/api/user-client-modules/SoundPlayer.md @@ -0,0 +1,197 @@ +# SoundPlayer API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 类描述 + +音效管理核心类,提供短音频的加载、播放和空间化控制功能。推荐通过全局单例 `soundPlayer` 使用。 + +```mermaid +graph LR + AudioPlayer --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 属性说明 + +| 属性名 | 类型 | 说明 | +| --------- | --------------------- | ---------------------- | +| `enabled` | `boolean` | 总开关状态(默认启用) | +| `buffer` | `Map` | 已加载音效缓冲存储池 | +| `playing` | `Set` | 当前活跃音效 ID 集合 | +| `gain` | `VolumeEffect` | 全局音量控制器 | + +--- + +## 方法说明 + +### 基础控制 + +#### setEnabled + +```typescript +function setEnabled(enabled: boolean): void; +``` + +启用/禁用音效系统(禁用时立即停止所有音效) + +| 参数 | 类型 | 说明 | +| ------- | --------- | ------------ | +| enabled | `boolean` | 是否启用音效 | + +--- + +#### setVolume / getVolume + +```typescript +function setVolume(volume: number): void; +function getVolume(): number; +``` + +全局音量控制(范围 0.0~1.0) + +--- + +### 资源管理 + +#### add + +```typescript +async function add(id: T, data: Uint8Array): Promise; +``` + +加载并缓存音效资源 + +| 参数 | 类型 | 说明 | +| ---- | ------------ | ---------------- | +| id | `T` | 音效唯一标识符 | +| data | `Uint8Array` | 原始音频字节数据 | + +--- + +### 播放控制 + +#### play + +```typescript +function play( + id: T, + position?: [number, number, number], + orientation?: [number, number, number] +): number; +``` + +播放指定音效(返回音效实例 ID) + +| 参数 | 类型 | 默认值 | 说明 | +| ----------- | ----------- | --------- | ------------------------- | +| id | `T` | - | 音效标识符 | +| position | `[x, y, z]` | `[0,0,0]` | 3D 空间坐标(右手坐标系) | +| orientation | `[x, y, z]` | `[1,0,0]` | 声音传播方向向量 | + +**坐标系说明**: + +```txt +(0,0,0) 听者位置 +X+ → 右 +Y+ ↑ 上 +Z+ ⊙ 朝向听者正前方 +``` + +--- + +#### stop + +```typescript +function stop(num: number): void; +``` + +停止指定音效实例 + +| 参数 | 类型 | 说明 | +| ---- | -------- | -------------------- | +| num | `number` | play() 返回的实例 ID | + +--- + +#### stopAllSounds + +```typescript +function stopAllSounds(): void; +``` + +立即停止所有正在播放的音效 + +--- + +## 使用示例 + +### 基础音效系统 + +```typescript +import { soundPlayer } from '@user/client-modules'; + +// 播放射击音效(右侧声场) +const shotId = soundPlayer.play('shoot', [2, 0, 0]); + +// 播放爆炸音效(左后方) +soundPlayer.play('explosion', [-3, 0, -2], [-1, 0, -1]); + +// 停止特定音效 +soundPlayer.stop(shotId); + +// 全局音量控制 +soundPlayer.setVolume(0.7); +``` + +### 3D 环境音效 + +```typescript +// 汽车引擎循环音效 +let engineSoundId = -1; + +function startEngine() { + engineSoundId = soundPlayer.play('engine', [0, 0, -5]); +} + +function updateCarPosition(x: number, z: number) { + const route = audioPlayer.getRoute(`sounds.${engineSoundId}`); + const stereo = route?.effectRoute[0] as StereoEffect; + stereo?.setPosition(x, 0, z); +} +``` + +--- + +## 生命周期管理 + +```mermaid +sequenceDiagram + participant User + participant SoundPlayer + participant AudioPlayer + + User->>SoundPlayer: add('explosion', data) + SoundPlayer->>AudioPlayer: decodeAudioData() + AudioPlayer-->>SoundPlayer: AudioBuffer + User->>SoundPlayer: play('explosion') + SoundPlayer->>AudioPlayer: 创建路由/效果器 + AudioPlayer-->>SoundPlayer: 音效ID + loop 播放周期 + SoundPlayer->>AudioPlayer: 更新空间参数 + end + User->>SoundPlayer: stop(id) + SoundPlayer->>AudioPlayer: 释放路由资源 +``` + +--- + +## 注意事项 + +1. **实例数量限制** + 同时播放音效建议不超过 32 个,可通过优先级系统管理 diff --git a/docs/api/user-client-modules/StreamLoader.md b/docs/api/user-client-modules/StreamLoader.md new file mode 100644 index 0000000..f07ea57 --- /dev/null +++ b/docs/api/user-client-modules/StreamLoader.md @@ -0,0 +1,208 @@ +# StreamLoader API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +```mermaid +graph LR + StreamLoader --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +## 类描述 + +`StreamLoader` 是流式加载大文件的核心类,支持分块读取网络资源并通过事件机制传递数据。继承自 `EventEmitter`,实现 `IStreamController` 接口,提供流传输控制能力。 + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| --------- | --------- | ---------------------- | +| `url` | `string` | 只读,要加载的资源 URL | +| `loading` | `boolean` | 当前是否处于加载状态 | + +--- + +## 构造方法 + +```typescript +function constructor(url: string): StreamLoader; +``` + +- **参数** + - `url`: 要加载的资源地址 + +**示例** + +```typescript +const loader = new StreamLoader('/api/large-file'); +``` + +--- + +## 方法说明 + +### `pipe` + +```typescript +function pipe(reader: IStreamReader): this; +``` + +将流数据管道传递给读取器对象。 + +- **参数** + - `reader`: 实现 `IStreamReader` 接口的对象 + +**示例** + +```typescript +class MyReader implements IStreamReader { + async pump(data, done) { + console.log('收到数据块:', data); + } + // ... 还有一些其他需要实现的方法,参考总是用示例 +} +loader.pipe(new MyReader()); +``` + +--- + +### `start` + +```typescript +function start(): Promise; +``` + +启动流传输流程(自动处理分块读取与分发)。 + +--- + +### `cancel` + +```typescript +function cancel(reason?: string): void; +``` + +终止当前流传输。 + +- **参数** + - `reason`: 终止原因描述(可选) + +**示例** + +```typescript +// 用户取消加载 +loader.cancel('用户手动取消'); +``` + +--- + +## 事件说明 + +| 事件名 | 参数类型 | 触发时机 | +| ------ | --------------------------------- | ------------------------ | +| `data` | `data: Uint8Array, done: boolean` | 每接收到一个数据块时触发 | + +**事件监听示例** + +```typescript +loader.on('data', (data, done) => { + if (done) console.log('传输完成'); +}); +``` + +--- + +## 相关接口说明 + +### IStreamReader + +```typescript +export interface IStreamReader { + /** + * 接受字节流流传输的数据 + * @param data 传入的字节流数据,只包含本分块的内容 + * @param done 是否传输完成 + */ + pump( + data: Uint8Array | undefined, + done: boolean, + response: Response + ): Promise; + + /** + * 当前对象被传递给加载流时执行的函数 + * @param controller 传输流控制对象 + */ + piped(controller: IStreamController): void; + + /** + * 开始流传输 + * @param stream 传输流对象 + * @param controller 传输流控制对象 + */ + start( + stream: ReadableStream, + controller: IStreamController, + response: Response + ): Promise; + + /** + * 结束流传输 + * @param done 是否传输完成,如果为 false 的话,说明可能是由于出现错误导致的终止 + * @param reason 如果没有传输完成,那么表示失败的原因 + */ + end(done: boolean, reason?: string): void; +} +``` + +- `pump`: 处理每个数据块 +- `piped`: 当读取器被绑定到流时调用 +- `start`: 流传输开始时调用 +- `end`: 流传输结束时调用 + +--- + +## 总使用示例 + +```typescript +// 创建流加载器 +const loader = new StreamLoader('/api/video-stream'); + +const videoElement = document.createElement('video'); + +// 实现自定义读取器 +class VideoStreamReader implements IStreamReader { + async pump(data, done) { + if (data) videoElement.appendBuffer(data); + if (done) videoElement.play(); + } + + piped(controller) { + console.log('流传输管道连接成功'); + } + + start() { + console.log('开始流式加载'); + } + + end() { + console.log('流式加载结束'); + } +} + +const reader = new VideoStreamReader(); + +// 绑定读取器并启动 +loader.pipe(reader); +loader.start(); + +// 监听进度 +loader.on('data', (_, done) => { + if (!done) updateProgressBar(); +}); + +// 错误处理 +videoElement.onerror = () => loader.cancel('视频解码错误'); +``` diff --git a/docs/api/user-client-modules/TextContentParser.md b/docs/api/user-client-modules/TextContentParser.md new file mode 100644 index 0000000..b01cbae --- /dev/null +++ b/docs/api/user-client-modules/TextContentParser.md @@ -0,0 +1,157 @@ +# TextContentParser API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +## 类描述 + +`TextContentParser` 是文字解析核心工具,用于处理文本排版、转义字符解析及动态样式管理。支持自动分词换行、图标嵌入和样式栈控制。 + +--- + +## 方法说明 + +### `parse` + +```typescript +function parse(text: string, width: number): ITextContentRenderObject; +``` + +解析文本并生成渲染数据对象: + +```typescript +interface ITextContentRenderObject { + lineHeights: number[]; // 每行高度 + lineWidths: number[]; // 每行宽度 + data: ITextContentRenderable[]; // 渲染元素集合 +} +``` + +--- + +## 转义字符语法说明 + +### 1. 颜色控制 `\r[color]` + +- **语法**:`\r[颜色值]` +- **栈模式**:支持嵌套,用`\r`恢复上一级颜色 +- **颜色格式**:支持 CSS 颜色字符串 + +```typescript +// 示例:红→黄→红→默认 +'\\r[red]危险!\\r[yellow]警告\\r恢复红色\\r默认'; +``` + +### 2. 字号控制 `\c[size]` + +- **语法**:`\c[字号(px)]` +- **栈模式**:用`\c`恢复上一级字号 + +```typescript +// 示例:24px→32px→24px +'普通\\c[24]标题\\c[32]超大标题\\c恢复'; +``` + +### 3. 字体家族 `\g[family]` + +- **语法**:`\g[字体名称]` +- **栈模式**:用`\g`恢复上一级字体 + +```typescript +'默认\\g[黑体]中文黑体\\g恢复默认'; +``` + +### 4. 粗体切换 `\d` + +- **语法**:`\d`(开关模式) + +```typescript +'正常\\d粗体\\d正常'; +``` + +### 5. 斜体切换 `\e` + +- **语法**:`\e`(开关模式) + +```typescript +'正常\\e斜体\\e正常'; +``` + +### 6. 等待间隔 `\z[wait]` + +- **语法**:`\z[等待字符数]` +- **计算规则**:`间隔时间 = 字符数 * 当前interval配置` + +```typescript +'开始对话\\z[10](暂停500ms)继续'; +``` + +### 7. 图标嵌入 `\i[icon]` + +- **语法**:`\i[图标ID]` +- **图标规范**:需预加载到资源管理器 + +```typescript +'攻击\\i[sword]造成伤害'; +``` + +### 8. 表达式 `${}` + +- **语法**:与模板字符串语法一致,不过是在渲染的时候实时计算,而非字符串声明时计算 + +```typescript +'${core.status.hero.atk * 10}'; // 显示勇士攻击乘 10 +'${core.status.hero.atk > 100 ? "高攻击" : "低攻击"}'; // 条件表达式 +'${(() => { if (a > 10) return 100; else return 10; })()}'; // 嵌入函数 +``` + +--- + +## 综合使用示例 + +### 战斗伤害提示 + +```typescript +const text = + '\\r[#ff0000]\\c[24]\\d敌人\\i[monster]对你造成\\c[32]\\r[yellow]500\\c\\r伤害!\\z[5]\\d\\e(按空格跳过)'; + +const result = parser.parse(text, 400); + +/* 解析结果: +[ + { type: 'text', color: '#ff0000', size:24, bold:true, text:'敌人' }, + { type: 'icon', id:'monster' }, + { type: 'text', color:'#ff0000', size:24, text:'对你造成' }, + { type: 'text', color:'yellow', size:32, text:'500' }, + { type: 'text', color:'#ff0000', size:24, text:'伤害!' }, + { type: 'wait', duration:250 }, // 假设 interval=50 + { type: 'text', bold:false, italic:true, text:'(按空格跳过)' } +] +*/ +``` + +### 多语言混合排版 + +```typescript +const multiLangText = + '\\g[Times New Roman]Hello\\g[宋体]你好\\i[globe]\\z[3]\\g切换为\\r[blue]Français'; + +// 效果:英文→中文+地球图标→等待→蓝色法文 +``` + +--- + +## 注意事项 + +1. **转义字符格式** + + - 必须使用 **双反斜杠**(`\\`)表示转义 + - 错误示例:`\r[red]`(单反斜杠 `\r` 可能会被识别为换行) + - 正确示例:`\\r[red]` + +2. **栈操作规则** + + ```typescript + // 颜色栈示例 + '默认\\r[red]红\\r[blue]蓝\\r恢复红\\r恢复默认'; + // 等效于:push(默认)→push(红)→push(蓝)→pop→pop + ``` diff --git a/docs/api/user-client-modules/TextContentTyper.md b/docs/api/user-client-modules/TextContentTyper.md new file mode 100644 index 0000000..9f76150 --- /dev/null +++ b/docs/api/user-client-modules/TextContentTyper.md @@ -0,0 +1,245 @@ +# TextContentTyper API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +```mermaid +graph LR + TextContentTyper --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +## 类描述 + +`TextContentTyper` 是文字逐字输出(打字机效果)的核心控制器,继承自 `EventEmitter`。用于管理文字排版、渲染时序及样式配置,支持动态修改文本内容和样式。 + +--- + +## 核心属性说明 + +| 属性名 | 类型 | 描述 | +| -------- | ----------------------- | ---------------------------------------------- | +| `config` | `Required` | 当前文字渲染配置(包含字体、行高、对齐等参数) | +| `parser` | `TextContentParser` | 文字解析器实例(负责分词、分行等底层处理) | + +--- + +## 核心方法说明 + +### `constructor` + +```typescript +function constructor(config: Partial): TextContentTyper; +``` + +初始化打字机实例,接受文字配置参数: + +```typescript +interface ITextContentConfig { + /** 字体 */ + font: Font; + /** 是否持续上一次的文本,开启后,如果修改后的文本以修改前的文本为开头,那么会继续播放而不会从头播放(暂未实现,后续更新) */ + keepLast: boolean; + /** 打字机时间间隔,即两个字出现之间相隔多长时间 */ + interval: number; + /** 行高 */ + lineHeight: number; + /** 分词规则 */ + wordBreak: WordBreak; + /** 文字对齐方式 */ + textAlign: TextAlign; + /** 行首忽略字符,即不会出现在行首的字符 */ + ignoreLineStart: Iterable; + /** 行尾忽略字符,即不会出现在行尾的字符 */ + ignoreLineEnd: Iterable; + /** 会被分词规则识别的分词字符 */ + breakChars: Iterable; + /** 填充样式 */ + fillStyle: CanvasStyle; + /** 描边样式 */ + strokeStyle: CanvasStyle; + /** 线宽 */ + strokeWidth: number; + /** 文字宽度,到达这么宽之后换行 */ + width: number; +} +``` + +--- + +### `setConfig` + +```typescript +function setConfig(config: Partial): void; +``` + +动态更新配置参数(支持部分更新) + +--- + +### `setText` + +```typescript +function setText(text: string): void; +``` + +设置要显示的文本内容(自动重置播放进度) + +--- + +### `type` + +```typescript +function type(): void; +``` + +启动逐字显示效果 + +--- + +### `typeAll` + +```typescript +function typeAll(): void; +``` + +立即完整显示所有文字 + +--- + +### `setRender` + +```typescript +function setRender(render: TyperFunction): void; +``` + +设置自定义渲染逻辑: + +```typescript +type TyperFunction = ( + data: TyperRenderable[], // 待渲染元素 + typing: boolean // 是否正在播放中 +) => void; +``` + +--- + +## 事件说明 + +| 事件名 | 参数 | 触发时机 | +| ----------- | ---- | ------------------ | +| `typeStart` | `[]` | 开始逐字显示时 | +| `typeEnd` | `[]` | 全部文字显示完成时 | + +--- + +## 使用示例 + +### 基础用法 - 对话框文字 + +```typescript +// 初始化配置 +const typer = new TextContentTyper({ + font: new Font('黑体', 18), + interval: 50, + lineHeight: 1.2, + width: 400 +}); + +// 设置文本内容 +typer.setText(`「这是逐字显示的文字效果... + 第二行会自动换行」`); + +// 注册渲染逻辑 +typer.setRender((elements, isTyping) => { + elements.forEach(element => { + if (element.type === TextContentType.Text) { + drawText(element.x, element.y, element.text); + } + }); +}); + +// 开始播放 +typer.type(); +``` + +### 动态样式修改 + +```typescript +// 修改为红色斜体 +typer.setConfig({ + font: new Font('楷体', 20), + fillStyle: '#ff0000' +}); + +// 修改播放速度 +typer.setConfig({ interval: 30 }); +``` + +--- + +## 底层数据结构 + +### 渲染元素类型 + +```typescript +type TyperRenderable = + | TyperTextRenderable // 文本元素 + | TyperIconRenderable // 图标元素 + | TyperWaitRenderable; // 等待间隔 +``` + +::: code-group + +```ts [TyperTextRenderable] +interface TyperTextRenderable { + type: TextContentType.Text; + x: number; + y: number; + text: string; + font: string; + fillStyle: CanvasStyle; + strokeStyle: CanvasStyle; + /** 文字画到哪个索引 */ + pointer: number; + /** 这段文字的总高度 */ + height: number; +} +``` + +```ts [TyperIconRenderable] +interface TyperIconRenderable { + type: TextContentType.Icon; + x: number; + y: number; + width: number; + height: number; + renderable: RenderableData | AutotileRenderable; +} +``` + +```ts [TyperWaitRenderable] +interface TyperWaitRenderable { + type: TextContentType.Wait; + wait: number; + waited: number; +} +``` + +::: + +--- + +## 注意事项 + +1. **性能优化** + 当处理长文本(>1000 字)时,建议预调用 `parser.parse()` 进行分页 + +2. **坐标系统** + 所有坐标基于初始化时设置的 `width` 参数进行相对计算 + +3. **动态修改限制** + 在播放过程中修改配置可能导致渲染异常,建议在 `typeEnd` 事件后操作 + +4. **使用场景** + 本接口的使用场景并不多,建议使用 `TextContent` 组件。如果必须使用的话,可以直接阅读源码来看一些实现细节。 diff --git a/docs/api/user-client-modules/TextboxStore.md b/docs/api/user-client-modules/TextboxStore.md new file mode 100644 index 0000000..c6a8451 --- /dev/null +++ b/docs/api/user-client-modules/TextboxStore.md @@ -0,0 +1,166 @@ +# TextboxStore API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +```mermaid +graph LR + TextboxStore --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 类描述 + +`TextboxStore` 是文本框的集中管理器,继承自 `EventEmitter`。所有 `Textbox` 组件实例化时会自动注册到该类的静态 `list` 中,支持通过 ID 精准控制特定文本框。 + +--- + +## 核心方法说明 + +### `TextboxStore.get` + +```typescript +function get(id: string): TextboxStore | undefined; +``` + +**静态方法**:通过 ID 获取已注册的文本框控制器 + +- **参数** + `id`: 文本框的唯一标识符 +- **返回值** + 找到返回实例,否则返回 `undefined` + +--- + +### `setText` + +```typescript +function setText(text: string): void; +``` + +**动态更新文本内容** + +- **特性** + - 自动重置打字机进度 + - 触发重新排版计算 + +--- + +### `modify` + +```typescript +function modify(data: Partial): void; +``` + +**动态修改文本框配置** + +- **参数** + `data`: 需更新的属性(支持所有 `TextboxProps` 属性) + +--- + +### `endType` + +```typescript +function endType(): void; +``` + +**立即结束打字机动画** + +- **特性** + - 强制显示全部文本 + - 触发 `typeEnd` 事件 + +--- + +### `show` + +```ts +function show(): void; +``` + +### `hide` + +```ts +function hide(): void; +``` + +控制文本框的显示和隐藏。 + +--- + +## 使用示例 + +### 跨场景更新对话内容 + +```typescript +// 在剧情管理器中的调用 +const updateChapterDialog = (chapterId: string) => { + const store = TextboxStore.get(`chapter_${chapterId}`); + store?.setText(getChapterText(chapterId)); + store?.modify({ title: `第 ${chapterId} 章` }); +}; +``` + +### 紧急提示打断当前动画 + +```typescript +// 强制显示关键信息 +const showEmergencyAlert = () => { + const alertBox = TextboxStore.get('system_alert'); + alertBox?.setText('警告!基地即将爆炸!'); + alertBox?.endType(); // 跳过打字动画 + alertBox?.show(); +}; +``` + +### 动态样式调整 + +```typescript +// 根据昼夜切换对话框样式 +const updateDialogStyle = (isNight: boolean) => { + TextboxStore.list.forEach(store => { + store.modify({ + backColor: isNight ? '#1A1A32' : '#F0F0FF', + titleFill: isNight ? '#E6E6FA' : '#2F4F4F' + }); + }); +}; +``` + +--- + +## 注意事项 + +1. **ID 管理规范** + 建议显式指定可预测的 ID 格式: + + ```tsx + // 创建时指定可追踪 ID + + ``` + +2. **未找到实例处理** + 调用前需做空值检测: + + ```typescript + const store = TextboxStore.get('custom_id'); + if (!store) { + console.warn('文本框未注册: custom_id'); + return; + } + ``` + +3. **生命周期匹配** + 在组件卸载时自动注销实例,请勿持有长期引用 + +4. **批量操作优化** + 同时操作多个实例时建议使用迭代器: + ```typescript + // 隐藏所有对话框 + TextboxStore.list.forEach(store => store.hide()); + ``` diff --git a/docs/api/user-client-modules/TipStore.md b/docs/api/user-client-modules/TipStore.md new file mode 100644 index 0000000..d8b7882 --- /dev/null +++ b/docs/api/user-client-modules/TipStore.md @@ -0,0 +1,147 @@ +# TipStore API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 类描述 + +`TipStore` 是提示框的集中管理器,提供全局访问和控制提示组件的能力。所有通过 `` 组件注册的实例会自动加入静态 `list` 容器,支持通过 ID 精准控制特定提示框。 + +--- + +## 核心方法说明 + +### `TipStore.get` + +```typescript +function get(id: string): TipStore | undefined; +``` + +**静态方法**:通过 ID 获取已注册的提示框控制器 + +| 参数 | 类型 | 必填 | 说明 | +| ---- | -------- | ---- | ---------------- | +| `id` | `string` | 是 | 提示框的唯一标识 | + +**返回值**:找到返回实例,否则返回 `undefined` + +--- + +### `TipStore.use` + +```typescript +function use(id: string, data: TipExpose): TipStore; +``` + +**静态方法**:注册提示框实例到全局管理器(通常在组件内部使用) + +| 参数 | 类型 | 必填 | 说明 | +| ------ | ----------- | ---- | ----------------------- | +| `id` | `string` | 是 | 提示框的唯一标识 | +| `data` | `TipExpose` | 是 | 来自 Tip 组件的暴露接口 | + +--- + +### `drawTip` + +```typescript +function drawTip(text: string, icon?: AllIds | AllNumbers): void; +``` + +**显示提示内容**(支持带图标的提示) + +| 参数 | 类型 | 必填 | 说明 | +| ------ | ---------------------- | ---- | ------------------------------- | +| `text` | `string` | 是 | 提示文字内容 | +| `icon` | `AllIds \| AllNumbers` | 否 | 图标资源 ID(字符串或数字形式) | + +**特性**: + +- 自动触发淡入动画 +- 3 秒无操作后自动淡出 +- 重复调用会重置计时器 + +--- + +## 使用示例 + +### 基础提示 + +```typescript +// 获取预先注册的提示框 +const tip = TipStore.get('item-get-tip'); + +// 显示纯文本提示 +tip?.drawTip('获得金币 x100'); + +// 显示带图标的提示 +tip?.drawTip('获得 传说之剑', 'legend_sword'); +``` + +### 全局广播提示 + +```typescript +// 向所有提示框发送通知 +TipStore.list.forEach(store => { + store.drawTip('系统将在5分钟后维护', 'warning'); +}); +``` + +### 动态内容提示 + +```typescript +// 组合动态内容 +const showDamageTip = (damage: number) => { + TipStore.get('combat-tip')?.drawTip( + `造成 ${damage} 点伤害`, + damage > 1000 ? 'critical_hit' : 'normal_hit' + ); +}; +``` + +--- + +## 生命周期管理 + +### 组件注册流程 + +```tsx +// 在组件定义时注册实例 +; + +// 在业务逻辑中调用 +const showQuestComplete = () => { + TipStore.get('quest-tip')?.drawTip('任务「勇者的试炼」完成!'); +}; +``` + +--- + +## 注意事项 + +1. **自动清理机制** + 组件卸载时自动注销实例,跨场景访问时需确保目标组件已挂载 + +2. **错误处理** + 建议封装安全访问方法: + + ```typescript + const safeDrawTip = (id: string, text: string) => { + const instance = TipStore.get(id); + if (!instance) { + console.error(`Tip ${id} not registered`); + return; + } + instance.drawTip(text); + }; + ``` + +3. **动画队列** + 连续调用时会中断当前动画,建议重要提示添加延迟: + ```typescript + tip.drawTip('第一条提示'); + setTimeout(() => { + tip.drawTip('第二条重要提示'); + }, 3200); // 等待淡出动画结束 + ``` diff --git a/docs/api/user-client-modules/WeatherController.md b/docs/api/user-client-modules/WeatherController.md new file mode 100644 index 0000000..c8addd9 --- /dev/null +++ b/docs/api/user-client-modules/WeatherController.md @@ -0,0 +1,217 @@ +# WeatherController API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +```mermaid +graph LR + WeatherController --> IWeather +``` + +_实现 `IWeather` 接口_ + +## 类描述 + +`WeatherController` 是天气系统的核心控制器,支持动态管理多种天气效果(如雨、雪、雾等),可将天气效果绑定到任意渲染元素上,实现多场景独立天气控制。 + +--- + +## 属性说明 + +| 属性名 | 类型 | 描述 | +| -------------- | -------------------------------- | ----------------------------------------------------------------- | +| `id` | `string` | 只读,控制器的唯一标识符 | +| `active` | `Set` | 当前激活的天气实例集合 | +| `list`(静态) | `Map` | 静态属性,存储所有注册的天气类型(键为天气 ID,值为天气构造函数) | +| `map`(静态) | `Map` | 静态属性,存储所有控制器实例 | + +--- + +## 构造方法 + +```typescript +function constructor(id: string): WeatherController; +``` + +- **参数** + - `id`: 控制器的标识符 + +## 方法说明 + +### `activate` + +```typescript +function activate(id: string, level?: number): IWeather | undefined; +``` + +激活指定天气。 + +- **参数** + - `id`: 已注册的天气 ID + - `level`: 天气强度等级(可选) + +--- + +### `bind` + +```typescript +function bind(item?: RenderItem): void; +``` + +绑定/解绑渲染元素。 + +- **参数** + - `item`: 要绑定的渲染元素(不传则解绑) + +--- + +### `deactivate` + +```typescript +function deactivate(weather: IWeather): void; +``` + +关闭指定天气效果。 + +--- + +### `clearWeather` + +```typescript +function clearWeather(): void; +``` + +清空所有天气效果。 + +--- + +### `getWeather` + +```typescript +function getWeather( + weather: new (level?: number) => T +): T | null; +``` + +获取指定天气实例。 + +**示例** + +```ts +import { RainWeather } from '@user/client-modules'; + +const rain = controller.getWeather(RainWeather); +``` + +--- + +### `destroy` + +```typescript +function destroy(): void; +``` + +摧毁这个天气控制器,摧毁后不可继续使用。 + +--- + +## 静态方法说明 + +### `WeatherController.register` + +```typescript +function register(id: string, weather: Weather): void; +``` + +**静态方法**:注册新的天气类型。 + +- **参数** + - `id`: 天气唯一标识(如 "rain") + - `weather`: 天气类(需实现 `IWeather` 接口) + +--- + +### `WeatherController.get` + +```typescript +function get(id: string): WeatherController | undefined; +``` + +- **参数** + - `id`: 要获得的控制器标识符 + +## 天气接口说明 + +```typescript +interface IWeather { + activate(item: RenderItem): void; // 初始化天气效果 + frame(): void; // 每帧更新逻辑 + deactivate(item: RenderItem): void; // 清除天气效果 +} +``` + +--- + +## 内置天气 + +- `rain`: 下雨天气 + +## 总使用示例 实现滤镜天气效果 + +::: code-group + +```typescript [定义天气] +// 定义灰度滤镜天气 +class GrayFilterWeather implements IWeather { + private scale: number; + private now: number = 0; + private item?: RenderItem; + + constructor(level: number = 5) { + this.scale = level / 10; + } + + activate(item: RenderItem) { + // 添加灰度滤镜 + item.filter = `grayscale(0)`; + this.item = item; + } + + frame() { + // 动态调整滤镜强度(示例:正弦波动) + if (this.item) { + const intensity = ((Math.sin(Date.now() / 1000) + 1) * scale) / 2; + this.item.filter = `grayscale(${itensity})`; + } + } + + deactivate(item: RenderItem) { + item.filter = `none`; + } +} + +// 注册天气类型 +WeatherController.register('gray-filter', GrayFilterWeather); +``` + +```tsx [使用天气] +import { defineComponent, onMounted } from 'vue'; +import { Container } from '@motajs/render'; +import { useWeather } from '@user/client-modules'; + +const MyCom = defineComponent(() => { + const [controller] = useWeather(); + + const root = ref(); + + onMounted(() => { + // 绑定天气的渲染元素 + controller.bind(root.value); + // 激活天气效果 + controller.activate('gray-filter', 5); + }); + + return () => ; +}); +``` + +::: diff --git a/docs/api/user-client-modules/functions.md b/docs/api/user-client-modules/functions.md new file mode 100644 index 0000000..b2de6dd --- /dev/null +++ b/docs/api/user-client-modules/functions.md @@ -0,0 +1,410 @@ +# 模块函数 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +## 钩子 + +### `onOrientationChange` + +```typescript +function onOrientationChange(hook: OrientationHook): void; +``` + +监听屏幕方向变化事件。 +**参数** + +- `hook`: 方向变化回调函数 + +```typescript +type OrientationHook = ( + orientation: Orientation, // 当前方向 + width: number, // 窗口宽度 + height: number // 窗口高度 +) => void; +``` + +**示例** - 响应式布局 + +```typescript +import { onOrientationChange, Orientation } from './use'; + +onOrientationChange((orient, width) => { + if (orient === Orientation.Portrait) { + // 竖屏模式 + adjustMobileLayout(width); + } else { + // 横屏模式 + resetDesktopLayout(); + } +}); +``` + +--- + +### `onLoaded` + +```typescript +function onLoaded(hook: () => void): void; +``` + +在游戏核心资源加载完成后执行回调(若已加载则立即执行)。 + +--- + +## 过渡动画控制 + +### 通用接口 + +```typescript +interface ITransitionedController { + readonly ref: Ref; // 响应式引用 + readonly value: T; // 当前值 + set(value: T, time?: number): void; // 设置目标值 + mode(timing: TimingFn): void; // 设置缓动曲线 + setTime(time: number): void; // 设置默认时长 +} +``` + +### `transitioned` + +```typescript +function transitioned( + value: number, // 初始值 + time: number, // 默认过渡时长(ms) + curve: TimingFn // 缓动函数(如 linear()) +): ITransitionedController | null; +``` + +创建数值渐变控制器(仅限组件内使用)。 + +**示例** - 旋转动画 + +```tsx +// Vue 组件内 +const rotate = transitioned(0, 500, hyper('sin', 'out')); + +// 触发动画 +rotate.set(Math.PI, 800); // 800ms 内旋转到 180 度 + +// 模板中使用 +; +``` + +### `transitionedColor` + +```typescript +function transitionedColor( + color: string, // 初始颜色(目前支持 #RGB/#RGBA/rgb()/rgba()) + time: number, // 默认过渡时长(ms) + curve: TimingFn // 缓动函数 +): ITransitionedController | null; +``` + +创建颜色渐变控制器(仅限组件内使用)。 + +**示例** - 背景色过渡 + +```tsx +// Vue 组件内 +const bgColor = transitionedColor('#fff', 300, linear()); + +// 触发颜色变化 +bgColor.set('rgba(255, 0, 0, 0.5)'); // 渐变为半透明红色 + +// 模板中使用 +; +``` + +--- + +### 注意事项 + +1. **组件生命周期**:过渡控制器必须在 Vue 组件内部创建,卸载时自动销毁 +2. **性能优化**:避免在频繁触发的回调(如每帧渲染)中创建新控制器 +3. **颜色格式**:`transitionedColor` 支持 HEX/RGB/RGBA,但不支持 HSL +4. **默认时长**:调用 `set()` 时不传时间参数则使用初始化时设置的时间 + +### 高级用法示例 + +#### 组合动画 + +```typescript +// 同时控制位置和透明度 +const posX = transitioned(0, 500, linear()); +const alpha = transitioned(1, 300, linear()); + +const moveAndFade = () => { + posX.set(200); + alpha.set(0); +}; + +// 组件卸载时自动清理动画资源 +``` + +## 组件控制 + +### `getConfirm` + +```typescript +function getConfirm( + controller: IUIMountable, // UI 控制器 + text: string, // 确认内容 + loc: ElementLocator, // 定位配置 + width: number, // 对话框宽度(像素) + props?: Partial // 扩展配置 +): Promise; +``` + +--- + +#### 参数说明 + +| 参数名 | 类型 | 必填 | 描述 | +| ------------ | -------------------------- | ---- | ---------------------------------------------- | +| `controller` | `IUIMountable` | 是 | UI 控制器实例(通常从组件 props 获取) | +| `text` | `string` | 是 | 需要用户确认的文本内容 | +| `loc` | `ElementLocator` | 是 | 对话框位置配置(需包含 x,y 坐标及锚点) | +| `width` | `number` | 是 | 对话框宽度(像素),高度自动计算 | +| `props` | `Partial` | 否 | 扩展配置项(支持所有 ConfirmBox 组件的 props) | + +--- + +#### 返回值 + +返回 `Promise`: + +- `true` 表示用户点击确认 +- `false` 表示用户取消或关闭 + +--- + +#### 使用示例 + +##### 基础用法 - 删除确认 + +```tsx +import { defineComponent } from 'vue'; +import { DefaultProps } from '@motajs/render'; +import { GameUI } from '@motajs/system-ui'; + +// 在业务逻辑中调用,注意,组件需要使用 UI 控制器打开,它会自动传递 controller 参数 +const MyCom = defineComponent(props => { + const handleDeleteItem = async (itemId: string) => { + const confirmed = await getConfirm( + props.controller, // 从组件 props 获取控制器 + `确认删除 ID 为 ${itemId} 的项目吗?`, + [208, 208, void 0, void 0, 0.5, 0.5], // 居中显示 + 208 + ); + + if (confirmed) { + api.deleteItem(itemId); + } + }; + + return () => ( + + {/* 假设有一个按钮在点击后触发上面的删除函数 */} + handleDeleteItem(item.id)} /> + + ); +}); + +export const MyUI = new GameUI('my-ui', MyCom); +``` + +##### 自定义按钮文本 + +```typescript +import { mainUIController } from '@user/client-modules'; +// 注意,如果在 client-modules/render/ui 下编写代码,应该引入: +import { mainUIController } from './controller.ts'; + +// 修改确认/取消按钮文案 +const result = await getConfirm( + // 传入主 UI 控制器也可以 + mainUIController, + '切换场景将丢失未保存进度', + [208, 208, void 0, void 0, 0.5, 0.5], + 320, + { + yesText: '继续切换', + noText: '留在当前', + selFill: '#e74c3c', + border: '#c0392b' + } +); +``` + +--- + +### `getChoice` + +```typescript +function getChoice( + controller: IUIMountable, // UI 控制器 + choices: ChoiceItem[], // 选项数组 + loc: ElementLocator, // 定位配置 + width: number, // 对话框宽度(像素) + props?: Partial // 扩展配置 +): Promise; +``` + +#### 参数说明 + +| 参数名 | 类型 | 必填 | 描述 | +| ------------ | ----------------------- | ---- | ------------------------------------------- | +| `controller` | `IUIMountable` | 是 | UI 控制器实例(通常从组件 props 获取) | +| `choices` | `ChoiceItem[]` | 是 | 选项数组,格式为 `[key, text]` 的元组 | +| `loc` | `ElementLocator` | 是 | 对话框位置配置(需包含 x,y 坐标及锚点) | +| `width` | `number` | 是 | 对话框宽度(像素),高度自动计算 | +| `props` | `Partial` | 否 | 扩展配置项(支持所有 Choices 组件的 props) | + +#### 返回值 + +返回 `Promise`: + +- 解析为选中项的 `key` 值 + +#### 使用示例 + +##### 基础用法 - 难度选择 + +```typescript +import { getChoice, mainUIController } from '@user/client-modules'; + +// 写到异步函数里面 +const selectedDifficulty = await getChoice( + mainUIController, + [ + ['easy', '新手模式'], + ['normal', '普通模式'], + ['hard', '困难模式'] + ], + [208, 208, void 0, void 0, 0.5, 0.5], // 居中显示 + 208, + { + title: '选择难度', + titleFont: new Font('黑体', 24) + } +); + +// 判断选择的内容 +if (selectedDifficulty === 'hard') { + applyHardcoreRules(); +} +``` + +##### 分页支持 - 角色选择 + +```typescript +import { getChoice, mainUIController } from '@user/client-modules'; + +// 生成 200 个角色选项 +const characterOptions = Array.from( + { length: 200 }, + (_, i) => [i, `角色 #${i + 1}`] as ChoiceItem +); + +const chosenId = await getChoice( + mainUIController, + characterOptions, + [208, 208, void 0, void 0, 0.5, 0.5], + 208, + { + maxHeight: 400, // 超过 400px 自动分页 + winskin: 'winskin.png', + interval: 12 + } +); +``` + +##### 动态样式配置 + +```typescript +import { getChoice, mainUIController } from '@user/client-modules'; + +// 自定义主题风格 +const choiceResult = await getChoice( + mainUIController, + [ + ['light', '浅色主题'], + ['dark', '深色主题'], + ['oled', 'OLED 深黑'] + ], + [208, 208, void 0, void 0, 0.5, 0.5], + 300, + { + color: 'rgba(30,30,30,0.9)', + border: '#4CAF50', + selFill: '#81C784', + titleFill: '#FFF59D' + } +); +``` + +### `waitbox` + +```typescript +function waitbox( + controller: IUIMountable, + loc: ElementLocator, + width: number, + promise: Promise, + props?: Partial> +): Promise; +``` + +#### 参数说明 + +| 参数名 | 类型 | 必填 | 默认值 | 描述 | +| ------------ | -------------------------- | ---- | ------ | ---------------------------------------------------- | +| `controller` | `IUIMountable` | 是 | - | UI 挂载控制器(通常传递父组件的 `props.controller`) | +| `loc` | `ElementLocator` | 是 | - | 定位参数 | +| `width` | `number` | 是 | - | 内容区域宽度(像素) | +| `promise` | `Promise` | 是 | - | 要监视的异步操作 | +| `props` | `Partial>` | 否 | `{}` | 扩展配置项(继承 `Background` + `TextContent` 属性) | + +--- + +#### 返回值 + +| 类型 | 说明 | +| ------------ | ----------------------------------------------------------------------------------- | +| `Promise` | 与传入 `Promise` 联动的代理 `Promise`,在以下情况会 `reject`:原始 `Promise` 被拒绝 | + +--- + +#### 使用示例 + +##### 等待网络请求 + +```typescript +// 获取用户数据 +const userData = await waitbox( + props.controller, + [400, 300, void 0, void 0, 0.5, 0.5], // 居中定位 + 300, + fetch('/api/user'), + { + text: '加载用户信息...', + winskin: 'ui/loading_panel' + } +); +``` + +### 注意事项 + +1. **控制器有效性** + 必须确保传入的 `controller` 已正确挂载且未销毁 + +2. **异步特性** + 需使用 `await` 或 `.then()` 处理返回的 Promise + +3. **定位系统** + Y 轴坐标基于 Canvas 坐标系(向下为正方向) + +4. **额外参考** + - [组件 ConfirmBox](./组件%20ConfirmBox.md) + - [组件 Choices](./组件%20Choices.md) + - [组件 Waitbox](./组件%20Waitbox.md) diff --git a/docs/api/user-client-modules/index.md b/docs/api/user-client-modules/index.md new file mode 100644 index 0000000..ba85d58 --- /dev/null +++ b/docs/api/user-client-modules/index.md @@ -0,0 +1,3 @@ +# @user/client-modules + +目录: diff --git a/docs/api/user-client-modules/图标组件.md b/docs/api/user-client-modules/图标组件.md new file mode 100644 index 0000000..6da0135 --- /dev/null +++ b/docs/api/user-client-modules/图标组件.md @@ -0,0 +1,37 @@ +# 图标组件 API + +## Props 属性说明 + +| 属性名 | 类型 | 必填 | 描述 | +| ------ | ---------------- | ---- | ---------- | +| `loc` | `ElementLocator` | 是 | 图标定位符 | + +图标比例固定,会自动根据传入的长宽缩放。 + +## 图标列表 + +- `RollbackIcon`: 回退图标 +- `RetweenIcon`: 回收图标 +- `ViewMapIcon`: 浏览地图图标 +- `DanmakuIcon`: 弹幕图标 +- `ReplayIcon`: 回放图标 +- `numpadIcon`: 数字键盘图标 +- `PlayIcon`: 开始播放图标 +- `PauseIcon`: 暂停播放图标 +- `DoubleArrow`: 双箭头图标(向右) +- `StepForward`: 单步向前图标 + +## 使用示例 + +```tsx +import { defineComponent } from 'vue'; +import { RollbackIcon } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + return () => ( + + + + ); +}); +``` diff --git a/docs/api/user-client-modules/组件 Arrow.md b/docs/api/user-client-modules/组件 Arrow.md new file mode 100644 index 0000000..fca36f8 --- /dev/null +++ b/docs/api/user-client-modules/组件 Arrow.md @@ -0,0 +1,50 @@ +# Arrow 组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 核心特性 + +- **两点连线**:通过坐标点绘制任意方向箭头 +- **头部定制**:可调节箭头尖端大小 +- **样式控制**:支持颜色自定义 + +--- + +## Props 属性说明 + +| 属性名 | 类型 | 默认值 | 描述 | +| ------- | ---------------------------------- | ------ | ----------------------------------------- | +| `arrow` | `[number, number, number, number]` | 必填 | 箭头坐标 [起点 x, 起点 y, 终点 x, 终点 y] | +| `head` | `number` | `8` | 箭头头部尺寸(像素) | +| `color` | `CanvasStyle` | `#fff` | 箭头颜色 | + +--- + +## 使用示例 + +### 基础箭头 + +```tsx +// 从 (50, 100) 到 (200, 300) 的基础箭头 + +``` + +### 定制样式 + +```tsx +// 红色粗箭头(头部尺寸12px) + +``` + +### 虚线箭头 + +```tsx +// 带虚线效果的箭头 + +``` diff --git a/docs/api/user-client-modules/组件 Background.md b/docs/api/user-client-modules/组件 Background.md new file mode 100644 index 0000000..37a6985 --- /dev/null +++ b/docs/api/user-client-modules/组件 Background.md @@ -0,0 +1,78 @@ +# Background 背景组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 核心特性 + +- **双样式模式**:支持图片皮肤或纯色填充 +- **精准定位**:像素级坐标控制 +- **静态呈现**:无内置动画的稳定背景层 + +--- + +## Props 属性说明 + +| 属性名 | 类型 | 默认值 | 描述 | +| --------- | ---------------- | -------- | ----------------------------- | +| `loc` | `ElementLocator` | **必填** | 背景定位 | +| `winskin` | `ImageIds` | - | 皮肤图片资源 ID(优先级最高) | +| `color` | `CanvasStyle` | `"#333"` | 填充颜色(无皮肤时生效) | +| `border` | `CanvasStyle` | `"#666"` | 边框颜色(无皮肤时生效) | + +--- + +## 使用示例 + +### 图片皮肤模式 + +```tsx +// 使用预加载的UI背景图 + +``` + +### 纯色模式 + +```tsx +// 自定义颜色背景 + +``` + +### 对话框组合 + +```tsx +// 对话框容器 + + + + + +``` + +--- + +## 注意事项 + +1. **样式优先级** + 同时指定参数时的生效顺序: + + ```tsx + // 以下配置仅生效 winskin + + ``` + +2. **默认边框** + 未指定 border 时的行为: + + ```tsx + // 无边框(指定为透明色) + ; + + // 默认白色边框(当未指定任何参数时) + ; + ``` diff --git a/docs/api/user-client-modules/组件 Choices.md b/docs/api/user-client-modules/组件 Choices.md new file mode 100644 index 0000000..0de7953 --- /dev/null +++ b/docs/api/user-client-modules/组件 Choices.md @@ -0,0 +1,159 @@ +# Choices 选项框组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 组件特性 + +- **多选一机制**:从多个选项中选择一项 +- **自动分页**:通过 `maxHeight` 控制分页 +- **灵活样式**:支持图片背景/纯色背景 + 自定义字体 +- **键盘导航**:方向键选择 + Enter 确认 +- **动态内容**:支持异步加载选项数据 + +--- + +## Props 属性说明 + +```mermaid +graph LR + ConfirmBoxProps --> TextContentProps + + click TextContentProps "./组件%20TextContent" +``` + +本组件完全继承 `TextContent` 组件的参数,参考 [组件 TextContent](./组件%20TextContent.md) + +| 属性名 | 类型 | 默认值 | 描述 | +| ----------- | ---------------- | -------- | ------------------------------------- | +| `choices` | `ChoiceItem[]` | 必填 | 选项数组,格式为 `[key, text]` 的元组 | +| `loc` | `ElementLocator` | 必填 | 定位配置(需包含 x,y 坐标及锚点) | +| `width` | `number` | 必填 | 选项框宽度(像素) | +| `maxHeight` | `number` | `360` | 最大高度(超过时自动分页) | +| `text` | `string` | - | 主说明文本(显示在标题下方) | +| `title` | `string` | - | 标题文本 | +| `winskin` | `ImageIds` | - | 背景图片资源 ID(与 color 互斥) | +| `color` | `CanvasStyle` | `#333` | 背景颜色(未设置 winskin 时生效) | +| `border` | `CanvasStyle` | `gold` | 边框颜色/样式 | +| `selFont` | `Font` | 系统默认 | 选项文本字体 | +| `selFill` | `CanvasStyle` | `#fff` | 选项文本颜色 | +| `titleFont` | `Font` | 系统默认 | 标题字体 | +| `titleFill` | `CanvasStyle` | `gold` | 标题颜色 | +| `interval` | `number` | `16` | 选项间垂直间距(像素) | + +--- + +## Events 事件说明 + +| 事件名 | 参数 | 触发时机 | +| -------- | ---------------- | ---------------------- | +| `choose` | `key: ChoiceKey` | 用户选择任意选项时触发 | + +--- + +## 使用示例 + +### 基础用法 - 系统设置 + +```tsx +import { defineComponent } from 'vue'; +import { Choices, ChoiceItem } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + const options: ChoiceItem[] = [ + ['low', '低画质'], + ['medium', '中画质'], + ['high', '高画质'] + ]; + + return () => ( + console.log(`Choose ${key}.`)} + /> + ); +}); +``` + +### 分页处理 - 角色选择 + +```tsx +import { defineComponent } from 'vue'; +import { Choices, ChoiceItem } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + // 生成 50 个角色选项 + const characters: ChoiceItem[] = Array.from( + { length: 50 }, + (_, i) => [`char_${i}`, `角色 ${i + 1}`] as ChoiceItem + ); + + return () => ( + + ); +}); +``` + +### 动态内容 + 自定义样式 + +```tsx +import { defineComponent } from 'vue'; +import { Choices, ChoiceItem } from '@user/client-modules'; +import { onTick } from '@motajs/render'; + +export const MyCom = defineComponent(() => { + const dynamicOptions = ref([]); + + onTick(() => { + // 每帧生成随机选项名称 + dynamicOptions.value = Array.from( + { length: 50 }, + (_, i) => + [ + `char_${i}`, + `随机数 ${Math.random().toFixed(8)}` + ] as ChoiceItem + ); + }); + + return () => ( + + ); +}); +``` + +--- + +## 注意事项 + +1. **选项键值唯一性** + 每个选项的 `key` 必须唯一,否则可能引发不可预期行为 + +2. **分页计算规则** + 分页依据 `maxHeight` 和字体大小自动计算,需确保字体大小一致 + +3. **使用更方便的函数**:多数情况下,你不需要使用本组件,使用包装好的函数往往会更加方便,参考 [`getChoice`](./functions.md#getchoice) diff --git a/docs/api/user-client-modules/组件 ConfirmBox.md b/docs/api/user-client-modules/组件 ConfirmBox.md new file mode 100644 index 0000000..31f5b4f --- /dev/null +++ b/docs/api/user-client-modules/组件 ConfirmBox.md @@ -0,0 +1,124 @@ +# ConfirmBox 确认框组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +## 组件特性 + +- **双选项支持**:是/否选择 +- **灵活样式**:支持图片背景或纯色背景 +- **键盘交互**:支持按键操作 +- **自动布局**:根据内容动态计算高度 +- **事件驱动**:提供明确的用户选择反馈 + +--- + +## Props 属性说明 + +```mermaid +graph LR + ConfirmBoxProps --> TextContentProps + + click TextContentProps "./组件%20TextContent" +``` + +本组件完全继承 `TextContent` 组件的参数,参考 [组件 TextContent](./组件%20TextContent.md) + +| 属性名 | 类型 | 默认值 | 描述 | +| ------------ | ---------------- | ------------ | --------------------------------- | +| `text` | `string` | 必填 | 显示的主文本内容 | +| `width` | `number` | 必填 | 确认框宽度(像素) | +| `loc` | `ElementLocator` | 必填 | 定位配置 | +| `winskin` | `ImageIds` | - | 背景图片资源 ID(与 color 互斥) | +| `color` | `CanvasStyle` | `'#333'` | 背景颜色(未设置 winskin 时生效) | +| `border` | `CanvasStyle` | `'gold'` | 边框颜色/样式 | +| `selFont` | `Font` | 系统默认字体 | 选项按钮字体 | +| `selFill` | `CanvasStyle` | `'#d48'` | 选项按钮文本颜色 | +| `yesText` | `string` | `'是'` | 确认按钮文本 | +| `noText` | `string` | `'否'` | 取消按钮文本 | +| `defaultYes` | `boolean` | `true` | 默认选中确认按钮 | + +--- + +## Events 事件说明 + +| 事件名 | 参数 | 触发时机 | +| ------ | ---- | --------------------------- | +| `yes` | - | 用户选择确认时触发 | +| `no` | - | 用户选择取消或按 Esc 时触发 | + +--- + +## 使用示例 + +### 基础用法 - 文本确认 + +```tsx +import { defineComponent } from 'vue'; +import { ConfirmBox } from '@user/client-modules'; + +export const MyCom defineComponent(() => { + return () => ( + console.log('用户确认保存')} + onNo={() => console.log('用户取消保存')} + /> + ); +}); +``` + +### 图片背景 + 自定义按钮 + +```tsx +import { defineComponent } from 'vue'; +import { ConfirmBox } from '@user/client-modules'; +import { Font } from '@motajs/render'; + +export const MyCom = defineComponent(() => { + return () => ( + + ); +}); +``` + +### 动态内容 + 编程控制 + +```tsx +import { defineComponent, computed } from 'vue'; +import { ConfirmBox } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + const count = ref(0); + const myText = computed(() => `当前确认次数与取消次数差值:${count.value}`); + + return () => ( + void count.value++} // 每次确认次数加一 + onNo={() => void count.value--} // 每次确认次数减一 + /> + ); +}); +``` + +## 注意事项 + +1. **使用更方便的函数**:多数情况下,你不需要使用本组件,使用包装好的函数往往会更加方便,参考 [`getConfirm`](./functions.md#getconfirm) diff --git a/docs/api/user-client-modules/组件 Page.md b/docs/api/user-client-modules/组件 Page.md new file mode 100644 index 0000000..01c0b4f --- /dev/null +++ b/docs/api/user-client-modules/组件 Page.md @@ -0,0 +1,192 @@ +# Page 分页组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +## 组件描述 + +分页组件用于将大量内容分割为多个独立页面展示,支持通过编程控制或用户交互进行页面切换。适用于存档界面、多步骤表单等场景。 + +--- + +## Props 属性说明 + +| 属性名 | 类型 | 默认值 | 描述 | +| -------------- | ---------------- | ----------------- | -------------------------------- | +| `pages` | `number` | 必填 | 总页数 | +| `loc` | `ElementLocator` | 必填 | 页码组件定位配置(坐标系及位置) | +| `font` | `Font` | `Font.defaults()` | 页码文本字体配置(可选) | +| `hideIfSingle` | `boolean` | `false` | 当总页数为 1 时是否隐藏页码组件 | + +--- + +## Events 事件说明 + +| 事件名 | 参数类型 | 触发时机 | +| ------------ | ---------------- | ------------------------------- | +| `pageChange` | `(page: number)` | 当前页码变化时触发(从 0 开始) | + +--- + +## Slots 插槽说明 + +### `default` + +接收当前页码(从 0 开始)并返回需要渲染的内容 +**参数** + +- `page: number` 当前页码索引(0-based) + +--- + +## Exposed Methods 暴露方法 + +| 方法名 | 参数 | 返回值 | 描述 | +| ------------ | --------------- | -------- | --------------------------------------------------- | +| `changePage` | `page: number` | `void` | 跳转到指定页码(0-based,自动约束在有效范围内) | +| `movePage` | `delta: number` | `void` | 基于当前页码进行偏移切换(如 +1 下一页,-1 上一页) | +| `now` | - | `number` | 获取当前页码索引(0-based) | + +--- + +## 使用示例 + +### 基础用法 - 多页文本展示 + +```tsx +import { defineComponent } from 'vue'; +import { Page, PageExpose } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + return () => ( + + {page => ( + + )} + + ); +}); +``` + +### 监听页面修改 + +```tsx +import { defineComponent, ref } from 'vue'; +import { Page, PageExpose } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + // 示例数据 + const pages = [ + { content: '第一页内容' }, + { content: '第二页内容' }, + { content: '第三页内容' } + ]; + + // 分页组件引用 + const pageRef = ref(); + + // 页码变化回调 + const handlePageChange = (currentPage: number) => { + // 可以使用参数获得当前页码,加一是因为页码是从 0 开始的 + console.log(`当前页码:${currentPage + 1}`); + // 或者也可以使用 Page 组件的接口获得当前页码 + console.log(`当前页码:${pageRef.value!.now() + 1}`); + }; + + return () => ( + + {page => } + + ); +}); +``` + +### 动态配置示例 + +```tsx +import { defineComponent, ref } from 'vue'; +import { Page, PageExpose } from '@user/client-modules'; + +// 带统计面板的复杂分页 +export const MyCom = defineComponent(() => { + const dataPages = [ + /* 复杂数据结构 */ + ]; + + // 暴露方法实现翻页逻辑 + const pageRef = ref(); + const jumpToAnalysis = () => pageRef.value?.changePage(3); // 1-based + + return () => ( + + {/* 分页内容 */} + + {page => ( + + {/* 这里面可以写一些复杂的渲染内容,或者单独写成一个组件,把页码作为参数传入 */} + + + + )} + + + {/* 自定义跳转按钮 */} + + + ); +}); +``` + +### 边缘检测示例 + +```tsx +import { defineComponent, ref } from 'vue'; + +// 边界处理逻辑 +export const MyCom = defineComponent(() => { + const pageRef = ref(); + + // 自定义边界提示 + const handleEdge = () => { + const current = pageRef.value?.now() ?? 0; + const total = pageRef.value?.pages ?? 0; + + // 到达边界时提示(可以换成其他提示方式) + if (current === 0) core.drawTip('已经是第一页'); + if (current === total - 1) core.drawTip('已经是最后一页'); + }; + + return () => ( + + {page => } + + ); +}); +``` + +--- + +## 注意事项 + +1. **自动约束**:切换页码时会自动约束在 `[0, pages-1]` 范围内 diff --git a/docs/api/user-client-modules/组件 Progress.md b/docs/api/user-client-modules/组件 Progress.md new file mode 100644 index 0000000..322da96 --- /dev/null +++ b/docs/api/user-client-modules/组件 Progress.md @@ -0,0 +1,107 @@ +# Progress 组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 核心特性 + +- **动态进度显示**:支持 0.0~1.0 范围的进度可视化 +- **双色样式分离**:可分别定制已完成/未完成部分样式 +- **精准定位**:支持像素级坐标控制 +- **平滑过渡**:数值变化自动触发重绘 + +--- + +## Props 属性说明 + +| 属性名 | 类型 | 默认值 | 描述 | +| ------------ | ---------------- | -------- | --------------------- | +| `loc` | `ElementLocator` | **必填** | 进度条容器坐标 | +| `progress` | `number` | **必填** | 当前进度值(0.0~1.0) | +| `success` | `CanvasStyle` | `green` | 已完成部分填充样式 | +| `background` | `CanvasStyle` | `gray` | 未完成部分填充样式 | +| `lineWidth` | `number` | `2` | 进度条线宽(像素) | + +--- + +## 使用示例 + +### 基础用法 + +```tsx +import { defineComponent, ref } from 'vue'; +import { Progress } from '@user/client-modules'; +import { onTick } from '@motajs/render'; + +export const MyCom = defineComponent(() => { + // 创建响应式进度值 + const loadingProgress = ref(0); + + // 模拟进度更新 + onTick(() => { + if (loadingProgress.value < 1) { + loadingProgress.value += 0.002; + } + }); + + return () => ( + + ); +}); +``` + +### 自定义样式 + +```tsx +// 自定义进度条的已完成和未完成部分的样式 + +``` + +### 垂直进度条 + +```tsx +// 通过旋转容器实现垂直效果,注意锚点的使用 + + + +``` + +--- + +## 动画效果实现 + +### 平滑过渡示例 + +```tsx +import { transitioned } from '@user/client-modules'; +import { pow } from 'mutate-animate'; + +const progressValue = transitioned(0, 2000, pow(2, 'out')); +progressValue.set(1); // 2秒内完成二次曲线平滑过渡 + +return () => ( + +); +``` + +--- + +## 注意事项 + +1. **坐标系统** + 实际渲染高度由 `loc[3]` 参数控制,会自动上下居中: + + ```tsx + // 情况1:显式指定高度为8px + + ``` diff --git a/docs/api/user-client-modules/组件 Scroll.md b/docs/api/user-client-modules/组件 Scroll.md new file mode 100644 index 0000000..29ae75f --- /dev/null +++ b/docs/api/user-client-modules/组件 Scroll.md @@ -0,0 +1,118 @@ +# Scroll 滚动组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +## 组件特性 + +- **虚拟滚动**:自动裁剪可视区域外元素 +- **双模式支持**:垂直/水平滚动(默认垂直) +- **性能优化**:动态计算可视区域,支持万级元素流畅滚动 +- **编程控制**:支持精准定位滚动位置 + +--- + +## Props 属性说明 + +| 属性名 | 类型 | 默认值 | 描述 | +| ---------- | ---------------- | ------- | ------------------------------------------------- | +| `hor` | `boolean` | `false` | 启用水平滚动模式 | +| `noscroll` | `boolean` | `false` | 是否不显示滚动条,可用于一些特殊场景 | +| `loc` | `ElementLocator` | 必填 | 滚动容器定位配置 | +| `padEnd` | `number` | `0` | 滚动到底部/右侧的额外留白(用于修正自动计算误差) | + +--- + +## Exposed Methods 暴露方法 + +| 方法名 | 参数 | 返回值 | 描述 | +| ----------------- | --------------------------------- | -------- | --------------------------------------------------- | +| `scrollTo` | `position: number, time?: number` | `void` | 滚动到指定位置(单位:像素),time 为过渡时间(ms) | +| `getScrollLength` | - | `number` | 获取最大可滚动距离(单位:像素) | + +--- + +## Slots 插槽说明 + +### `default` + +接收滚动内容,**必须直接包含可渲染元素** +⚠️ 禁止嵌套 container 包裹,推荐平铺结构: + +```tsx +// ✅ 正确写法 + + + + +; + +// ❌ 错误写法(影响虚拟滚动计算) + + + // 会导致整体被视为单个元素 + + + +; +``` + +--- + +## 使用示例 + +### 基础垂直滚动 + +```tsx +import { defineComponent } from 'vue'; + +export const MyCom = defineComponent(() => { + const list = Array(200).fill(0); + + return () => ( + + {list.map((_, index) => ( + + ))} + + ); +}); +``` + +### 水平滚动 + 编程控制 + +```tsx +import { defineComponent, ref, onMounted } from 'vue'; + +export const MyCom = defineComponent(() => { + const list = Array(200).fill(0); + const scrollRef = ref(); + + // 滚动水平 100 像素位置,动画时长 500 毫秒 + onMounted(() => { + scrollRef.value?.scrollTo(100, 500); + }); + + return () => ( + + {list.map((_, index) => ( + + ))} + + ); +}); +``` + +--- + +## 性能优化指南 + +### 1. 替代方案建议 + +⚠️ **当子元素数量 > 1000 时**,推荐改用分页组件: + +```tsx +// 使用 Page 组件处理超大数据集 + + {page => renderChunk(data.slice(page * 50, (page + 1) * 50))} + +``` diff --git a/docs/api/user-client-modules/组件 ScrollText.md b/docs/api/user-client-modules/组件 ScrollText.md new file mode 100644 index 0000000..cc9e7ea --- /dev/null +++ b/docs/api/user-client-modules/组件 ScrollText.md @@ -0,0 +1,160 @@ +# ScrollText 组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 核心特性 + +- **自动滚动**:支持设定滚动速度的纵向滚动效果 +- **长文本支持**:内置高性能文本渲染引擎 +- **精准控制**:提供播放/暂停/调速等操作接口 +- **智能布局**:自动计算文本高度和滚动距离 + +--- + +## Props 属性说明 + +```mermaid +graph LR + ScrollTextProps --> TextContentProps + ScrollTextProps --> ScrollProps + + click TextContentProps "./组件%20TextContent" + click ScrollProps "./组件%20Scroll" +``` + +完全继承 `TextContent` 组件和 `Scroll` 组件的参数和事件。 + +| 属性名 | 类型 | 默认值 | 描述 | +| ------- | ---------------- | ------ | --------------------------- | +| `speed` | `number` | 必填 | 滚动速度(像素/秒) | +| `width` | `number` | 必填 | 文本区域固定宽度(像素) | +| `loc` | `ElementLocator` | 必填 | 容器定位 [x,y,width,height] | +| `pad` | `number` | `16` | 首行前空白距离(像素) | + +--- + +## 事件说明 + +| 事件名 | 参数 | 触发时机 | +| ----------- | ---- | -------------------- | +| `scrollEnd` | - | 滚动到文本末尾时触发 | + +--- + +## Exposed Methods 暴露方法 + +| 方法名 | 参数 | 返回值 | 描述 | +| ---------- | --------------- | ------ | --------------------------- | +| `pause` | - | void | 暂停滚动 | +| `resume` | - | void | 继续滚动 | +| `setSpeed` | `speed: number` | void | 动态调整滚动速度(像素/秒) | +| `rescroll` | - | void | 立即重置到起始位置重新滚动 | + +--- + +## 使用示例 + +### 基础滚动 + +```tsx +import { defineComponent } from 'vue'; +import { ScrollText } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + const longText = '序幕\n'.repeat(100) + '——全剧终——'; + + return () => ( + + ); +}); +``` + +### 动态控制 + +```tsx +import { defineComponent, ref } from 'vue'; +import { ScrollText } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + const longText = '序幕\n'.repeat(100) + '——全剧终——'; + const scrollRef = ref(); + + // 暂停/恢复控制 + const toggleScroll = () => { + if (scrollRef.value?.isPaused) { + scrollRef.value.resume(); + } else { + scrollRef.value?.pause(); + } + }; + + // 速度控制 + const accelerate = () => { + scrollRef.value?.setSpeed(200); + }; + + return () => ( + console.log('滚动结束')} + /> + ); +}); +``` + +### 复杂排版 + +```tsx +const staffText = + '\\c[32]====制作人员====\\c\n\n' + + '\\r[#FFD700]总监督\\r\t\t张三\n' + + '\\r[#00FF00]美术指导\\r\\t李四\n' + + '\\i[logo]\n' + + '特别感谢:某某公司'; + +; +``` + +--- + +## 注意事项 + +1. **容器尺寸** + 实际可滚动区域计算公式: + + ``` + 可视高度 = loc[3](容器高度) + 滚动距离 = 文本总高度 + pad(首行前空白) + ``` + +2. **速度控制** + 推荐速度范围 50-200 像素/秒 + +3. **组合动画** + 可与容器变换配合实现复杂效果: + ```tsx + + + + ``` diff --git a/docs/api/user-client-modules/组件 Selection.md b/docs/api/user-client-modules/组件 Selection.md new file mode 100644 index 0000000..3a86afd --- /dev/null +++ b/docs/api/user-client-modules/组件 Selection.md @@ -0,0 +1,77 @@ +# Selection 组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 核心特性 + +- **动态高亮**:自动呼吸动画效果 +- **双样式模式**:支持图片皮肤或纯色样式 +- **精准定位**:像素级坐标控制 +- **透明度动画**:可定制不透明度变化范围 + +--- + +## Props 属性说明 + +| 属性名 | 类型 | 默认值 | 描述 | +| ------------ | ------------------ | -------------- | --------------------------------- | +| `loc` | `ElementLocator` | **必填** | 光标定位 | +| `winskin` | `ImageIds` | - | 图片资源 ID(优先级最高) | +| `color` | `CanvasStyle` | `#ddd` | 填充颜色(无皮肤时生效) | +| `border` | `CanvasStyle` | `gold` | 边框颜色(无皮肤时生效) | +| `alphaRange` | `[number, number]` | `[0.25, 0.55]` | 不透明度波动范围 [最小值, 最大值] | + +--- + +## 使用示例 + +### 图片皮肤模式 + +```tsx +// 使用预加载的游戏皮肤资源 + +``` + +--- + +### 纯色模式 + +```tsx +// 自定义颜色方案 + +``` + +--- + +## 注意事项 + +1. **样式优先级** + 同时指定 `winskin` 和颜色参数时: + + ```tsx + // 以下配置将忽略 color/border 参数 + + ``` + +2. **动画速度** + 呼吸动画固定为 2000ms/周期,暂不支持自定义时长 + +3. **点击反馈** + 建议配合事件系统实现点击效果: + ```tsx + + + + + ``` diff --git a/docs/api/user-client-modules/组件 TextContent.md b/docs/api/user-client-modules/组件 TextContent.md new file mode 100644 index 0000000..1dbe2c4 --- /dev/null +++ b/docs/api/user-client-modules/组件 TextContent.md @@ -0,0 +1,184 @@ +# TextContent 文本组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 核心特性 + +- **自动布局**:根据宽度自动换行 +- **样式控制**:支持动态修改字体/颜色/描边 +- **打字机效果**:逐字显示支持 +- **动态高度**:自适应或固定高度模式 + +--- + +## Props 属性说明 + +| 属性名 | 类型 | 默认值 | 描述 | +| ----------------- | ------------- | ----------------- | ------------------------------ | +| `text` | `string` | - | 显示文本(支持转义字符) | +| `width` | `number` | 必填 | 文本区域宽度(像素) | +| `fill` | `boolean` | `true` | 是否对文字填充 | +| `stroke` | `boolean` | `false` | 是否对文字描边 | +| `font` | `Font` | 系统默认字体 | 字体配置对象 | +| `lineHeight` | `number` | `0` | 行间距(像素) | +| `interval` | `number` | `50` | 打字机字符间隔(ms) | +| `autoHeight` | `boolean` | `false` | 是否根据内容自动调整高度 | +| `fillStyle` | `CanvasStyle` | `#fff` | 文字填充颜色 | +| `strokeStyle` | `CanvasStyle` | `#000` | 文字描边颜色 | +| `strokeWidth` | `number` | `1` | 描边宽度 | +| `textAlign` | `TextAlign` | `TextAlign.Left` | 文字对齐方式 | +| `wordBreak` | `WordBreak` | `WordBreak.Space` | 文本分词原则,将会影响换行表现 | +| `breakChars` | `string` | - | 会被分词规则识别的分词字符 | +| `ignoreLineStart` | `string` | - | 不允许出现在行首的字符 | +| `ignoreLineEnd` | `string` | - | 不允许出现在行尾的字符 | + +--- + +## 事件说明 + +| 事件名 | 参数 | 触发时机 | +| -------------- | ---------------- | ------------------ | +| `typeStart` | - | 开始逐字显示时 | +| `typeEnd` | - | 全部文字显示完成时 | +| `updateHeight` | `height: number` | 文本高度变化时 | + +--- + +## Exposed Methods 暴露方法 + +| 方法名 | 参数 | 返回值 | 描述 | +| ----------- | ---- | -------- | ---------------------------- | +| `retype` | - | `void` | 从头开始重新打字 | +| `showAll` | - | `void` | 立刻结束打字机,显示所有文字 | +| `getHeight` | - | `number` | 获得当前文本的高度 | + +--- + +## 使用示例 + +### 基础用法 - 对话文本 + +```tsx +import { defineComponent } from 'vue'; +import { TextContent } from '@user/client-modules'; +import { Font } from '@motajs/render'; + +export const MyCom = defineComponent(() => { + return () => ( + console.log('显示完成')} // 打字机结束后执行 + /> + ); +}); +``` + +### 自定义样式 + 描边效果 + +```tsx +import { defineComponent } from 'vue'; +import { TextContent } from '@user/client-modules'; +import { Font } from '@motajs/render'; + +export const MyCom = defineComponent(() => { + return () => ( + + ); +}); +``` + +### 动态内容更新 + +```tsx +import { defineComponent, ref } from 'vue'; +import { TextContent } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + const dynamicText = ref('初始内容'); + + setTimeout(() => { + dynamicText.value = '更新后的内容\\z[5]带暂停效果'; + }, 2000); + + return () => ( + console.log('当前高度:', h)} // 当高度发生变化时触发 + /> + ); +}); +``` + +### 禁用动画效果 + +```tsx +import { defineComponent } from 'vue'; +import { TextContent } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + return () => ( + + ); +}); +``` + +### 多语言复杂排版 + +```tsx +import { defineComponent } from 'vue'; +import { TextContent } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + const complexText = + '\\g[Times New Roman]Hello\\g[宋体] 你好 \\i[flag]\\n' + + '\\r[#FF5733]Multi\\r[#3498db]-\\r[#2ECC71]Color\\r\\n' + + '\\c[18]Small\\c[24]Size\\c[30]Changes'; + + return () => ( + console.log('开始渲染复杂文本')} + /> + ); +}); +``` + +--- + +## 转义字符示例 + +```tsx +// 颜色/字体/图标综合使用 +const styledText = + '\\r[#FF0000]警告!\\g[方正粗宋]\\c[24]' + + '\\i[warning_icon]发现异常\\z[10]\\n' + + '请立即处理\\r\\g\\c'; + +; +``` + +转义字符具体用法参考 [TextContentParser](./TextContentParser.md#转义字符语法说明) diff --git a/docs/api/user-client-modules/组件 Textbox.md b/docs/api/user-client-modules/组件 Textbox.md new file mode 100644 index 0000000..c0a2e44 --- /dev/null +++ b/docs/api/user-client-modules/组件 Textbox.md @@ -0,0 +1,173 @@ +# Textbox 对话框组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +本文档描述在 `TextContent` 基础上扩展的对话框组件,专为剧情对话、系统提示等场景设计,支持背景、标题等装饰元素。 + +--- + +## 特有属性说明 + +```mermaid +graph LR + TextboxProps --> TextContentProps + + click TextContentProps "./组件%20TextContent" +``` + +| 属性名 | 类型 | 默认值 | 描述 | +| -------------- | ------------- | -------------- | ------------------------------------- | +| `backColor` | `CanvasStyle` | `#222` | 背景颜色(与 `winskin` 互斥) | +| `winskin` | `ImageIds` | - | 背景图片资源 ID(优先于 `backColor`) | +| `padding` | `number` | `8` | 内容区域与边框的内边距(像素) | +| `title` | `string` | - | 标题文本内容 | +| `titleFont` | `Font` | `18px Verdana` | 标题字体配置 | +| `titleFill` | `CanvasStyle` | `gold` | 标题文字颜色 | +| `titleStroke` | `CanvasStyle` | `transparent` | 标题描边颜色 | +| `titlePadding` | `number` | `8` | 标题在其背景的间距(像素) | + +--- + +## 事件说明 + +```mermaid +graph LR + TextboxEmits --> TextContentEmits + + click TextContentEmits "./组件%20TextContent" +``` + +完全继承 `TextContent` 的事件。 + +--- + +## Exposed Methods 暴露方法 + +| 方法名 | 参数 | 返回值 | 描述 | +| --------- | ---- | ------ | ---------------------------- | +| `retype` | - | `void` | 从头开始重新打字 | +| `showAll` | - | `void` | 立刻结束打字机,显示所有文字 | +| `show` | - | `void` | 显示这个文本框 | +| `hide` | - | `void` | 隐藏这个文本框 | + +--- + +## Slots 插槽说明 + +### default + +背景插槽,传入后可以自定义背景 + +```tsx +// 例如使用一张图片作为背景 + + + + + +``` + +### title + +标题背景插槽,自定义标题背景 + +```tsx +// 与 default 一起使用 + + {{ + // 背景图 + default: () => , + // 标题背景图 + title: () => + }} + +``` + +## 使用示例 + +### 基础对话框 + +```tsx +import { defineComponent } from 'vue'; +import { Textbox } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + return () => ( + + ); +}); +``` + +### 纯色背景 + 复杂标题 + +```tsx +import { defineComponent } from 'vue'; +import { Textbox } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + return () => ( + + ); +}); +``` + +### 动态标题交互 + +```tsx +import { defineComponent } from 'vue'; +import { Textbox, TextbosExpose } from '@user/client-modules'; + +export const MyCom = defineComponent(() => { + const currentTitle = ref(); + + // 点击按钮切换标题 + const toggleTitle = () => { + currentTitle.value += 1; + }; + + return () => ( + + + + + ); +}); +``` + +--- + +## 布局结构示意图 + +```mermaid +graph TB + Dialog[对话框] --> Background[背景层] + Dialog --> Title[标题层] + Dialog --> Content[内容层] + + Background -->|winskin/backColor| 渲染背景 + Title -->|title 配置| 标题文本 + Content -->|padding 控制| 文字内容 +``` diff --git a/docs/api/user-client-modules/组件 Tip.md b/docs/api/user-client-modules/组件 Tip.md new file mode 100644 index 0000000..1eae585 --- /dev/null +++ b/docs/api/user-client-modules/组件 Tip.md @@ -0,0 +1,65 @@ +# Tip 组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +## 参数说明(Props) + +| 参数名 | 类型 | 默认值 | 说明 | +| -------- | ------------------ | -------- | ---------------------------------------- | +| `loc` | `ElementLocator` | 必填 | 容器基础定位参数 [x,y,width,height] | +| `pad` | `[number, number]` | `[4,4]` | 图标与文字的边距配置 [水平边距,垂直边距] | +| `corner` | `number` | `4` | 圆角矩形的圆角半径 | +| `id` | `string` | 自动生成 | 提示框唯一标识(需全局唯一) | + +## 暴露接口(Expose) + +| 方法名 | 参数 | 返回值 | 说明 | +| --------- | ----------------------------------------------- | ------ | --------------------------------------------------- | +| `drawTip` | `text: string`
`icon?: AllIds \| AllNumbers` | `void` | 显示带图标的提示文本(图标支持字符串 ID 或数字 ID) | + +## 使用示例 + +```tsx +import { defineComponent } from 'vue'; +import { Tip } from './tip'; + +// 在游戏界面中定义提示组件 +export const MyCom = defineComponent(() => { + return () => ( + + + + ); +}); + +// 在业务代码中调用提示,使用 TipStore 类 +const tip = TipStore.get('global-tip'); +tip?.drawTip('宝箱已解锁!', 'chest_icon'); +``` + +## 特性说明 + +1. **自动布局**: + + - 根据图标尺寸自动计算容器宽度 + - 文字垂直居中显示 + - 图标与文字间距自动适配 + +2. **动画效果**: + + - 默认带有 500ms 双曲正弦缓动的淡入动画 + - 3 秒无操作后自动淡出 + - 支持通过`alpha`参数自定义过渡效果 + +## 注意事项 + +1. **全局单例**:建议通过 `TipStore` 进行全局管理,避免重复创建 +2. **ID 唯一性**:未指定 `id` 时会自动生成格式为 `@default-tip-数字` 的标识 +3. **自动隐藏**:调用 `drawTip` 后 3 秒自动隐藏,连续调用会重置计时 +4. **性能优化**:使用 `lodash` 的 `debounce` 进行隐藏操作防抖 +5. **动画配置**:可通过修改 `hyper('sin', 'in-out')` 参数调整动画曲线 diff --git a/docs/api/user-client-modules/组件 Waitbox.md b/docs/api/user-client-modules/组件 Waitbox.md new file mode 100644 index 0000000..9cd2d94 --- /dev/null +++ b/docs/api/user-client-modules/组件 Waitbox.md @@ -0,0 +1,104 @@ +# WaitBox 等待框组件 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 核心特性 + +- **Promise 绑定**:自动监控 `Promise` 状态 +- **复合式组件**:集成背景+文字+加载动画 +- **双重控制**:支持自动/手动完成等待 +- **动态布局**:根据内容自动计算高度 + +--- + +## 组件定位 + +> 💡 更推荐使用 `waitbox` 工具函数,该组件主要用于需要深度定制的场景。参考 [此文档](./functions.md#waitbox)。 + +--- + +## Props 属性说明 + +| 属性名 | 类型 | 必填 | 描述 | +| --------- | ---------------- | ---- | ----------------------- | +| `promise` | `Promise` | 否 | 要监控的 `Promise` 对象 | +| `loc` | `ElementLocator` | 是 | 容器定位 | +| `width` | `number` | 是 | 内容区域宽度(像素) | +| `text` | `string` | 否 | 等待提示文字 | +| `pad` | `number` | `16` | 文字与边缘间距 | + +### 继承属性 + +- 支持所有 `Background` 背景属性 +- 支持所有 `TextContent` 文本属性 + +--- + +## 事件说明 + +| 事件名 | 参数 | 触发时机 | +| --------- | ---- | -------------------------- | +| `resolve` | `T` | `Promise` 完成时返回结果值 | + +--- + +## Exposed Methods 暴露方法 + +| 方法名 | 参数 | 描述 | +| --------- | --------- | ---------------------------- | +| `resolve` | `data: T` | 手动完成等待(立即触发事件) | + +--- + +## 使用示例 + +### 基础组件用法 + +```tsx +// 等待网络请求 +const fetchPromise = fetchData(); + + console.log('收到数据:', data)} +/>; +``` + +### 手动控制示例 + +```tsx +const waitRef = ref>(); + +// 手动结束等待 +const forceComplete = () => { + waitRef.value?.resolve(Date.now()); +}; + +return () => ( + +); +``` + +--- + +## 注意事项 + +1. **推荐用法** + 90% 场景应使用 `waitbox` 函数,以下情况才需要直接使用组件: + + - 需要永久显示的等待界面 + - 需要组合复杂子组件 + - 需要复用同一个等待实例 diff --git a/docs/api/user-data-base/index.md b/docs/api/user-data-base/index.md new file mode 100644 index 0000000..ae599ee --- /dev/null +++ b/docs/api/user-data-base/index.md @@ -0,0 +1,3 @@ +# @user/data-base + +目录: diff --git a/docs/api/user-data-base/钩子.md b/docs/api/user-data-base/钩子.md new file mode 100644 index 0000000..4fc989b --- /dev/null +++ b/docs/api/user-data-base/钩子.md @@ -0,0 +1,97 @@ +# 游戏事件钩子 API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## GameLoading 加载进度钩子 + +### 核心事件说明 + +| 事件名 | 触发时机 | 参数 | +| ------------------ | -------------------------- | ---- | +| `coreLoaded` | 核心脚本加载完成时 | 无 | +| `autotileLoaded` | 所有自动元件资源加载完成时 | 无 | +| `coreInit` | 核心类初始化完成时 | 无 | +| `loaded` | 所有启动必要资源加载完成时 | 无 | +| `registered` | 客户端和数据端都完成挂载时 | 无 | +| `dataRegistered` | 数据端服务挂载完成时 | 无 | +| `clientRegistered` | 渲染端挂载完成时 | 无 | + +--- + +### 使用示例 + +```typescript +import { loading } from '@user/data-base'; + +// 监听核心初始化事件 +loading.on('coreInit', () => { + console.log('核心系统已就绪'); + initializeCustomModules(); +}); + +// 监听完整加载事件 +loading.once('loaded', () => { + showMainMenu(); + preloadOptionalAssets(); +}); +``` + +--- + +## GameEvent 游戏运行时钩子 + +### 核心事件说明 + +| 事件名 | 触发时机 | 参数 | +| ------------------ | ------------------------------------ | ------------------------------------------------------------------------------- | +| `reset` | 游戏初始化时,例如读档后、进入游戏后 | 无 | +| `mounted` | 游戏 DOM 挂载完成后 | 无 | +| `statusBarUpdate` | 状态栏更新时 | 无 | +| `renderLoaded` | 渲染端加载完成时 | 无 | +| `afterGetItem` | 拾取道具后 | `[itemId: 道具ID, x: 坐标X, y: 坐标Y, isGentleClick: 是否轻击]` | +| `afterOpenDoor` | 成功开门后 | `[doorId: 门动画ID, x: 坐标X, y: 坐标Y]` | +| `afterChangeFloor` | 楼层切换完成后 | `[floorId: 新楼层ID]` | +| `moveOneStep` | 玩家移动一步后 | `[x: 新坐标X, y: 新坐标Y, floorId: 当前楼层ID]` | +| `afterBattle` | 战斗结算完成后 | `[enemy: 敌人数据对象, x?: 战斗坐标X, y?: 战斗坐标Y]` | +| `changingFloor` | 楼层切换过程中(动画播放时) | `[floorId: 目标楼层ID, heroLoc: 玩家位置对象]` | +| `setBlock` | 地图图块被修改时 | `[x: 坐标X, y: 坐标Y, floorId: 楼层ID, newBlock: 新图块值, oldBlock: 旧图块值]` | +| `enemyExtract` | 解析敌人数据时 | `[col: 敌人集合对象]` | +| `restart` | 从游戏返回标题界面时 | 无 | +| `setBgFgBlock` | 设置背景/前景图块时 | `[name: 图层名称, number: 图块值, x: 坐标X, y: 坐标Y, floorId: 楼层ID]` | +| `replayStatus` | 录像播放状态切换时 | `[replaying: 是否正在回放]` | +| `loadData` | 加载存档时 | 无 | + +--- + +### 使用示例 + +```typescript +// 监听玩家移动事件 +hook.on('moveOneStep', (x, y, floorId) => { + console.log(x, y, floorId); +}); + +// 监听战斗结束事件 +hook.on('afterBattle', (enemy, x, y) => { + console.log(enemy, x, y); +}); + +// 监听存档加载事件 +hook.once('loadData', () => { + console.log('读档成功!'); +}); +``` + +--- + +## 弃用说明 + +```typescript +/** + * @deprecated 自 v2.B 起废弃的 GameListener + * 计划在 v2.C 移除,请使用新的 UI 交互系统代替 + */ +export const gameListener = new GameListener(); +``` diff --git a/docs/api/user-data-fallback/index.md b/docs/api/user-data-fallback/index.md new file mode 100644 index 0000000..259983b --- /dev/null +++ b/docs/api/user-data-fallback/index.md @@ -0,0 +1,3 @@ +# @user/data-fallback + +目录: diff --git a/docs/api/user-data-state/ObjectMoverBase.md b/docs/api/user-data-state/ObjectMoverBase.md new file mode 100644 index 0000000..09400bd --- /dev/null +++ b/docs/api/user-data-state/ObjectMoverBase.md @@ -0,0 +1,424 @@ +# ObjectMoverBase API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 类描述 + +游戏中可移动对象的基类控制器,提供面向方向、移动队列管理和动画协调的通用移动能力。继承自 EventEmitter3,用于实现图块、角色等元素的移动控制。 + +```mermaid +graph LR + ObjectMoverBase --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +--- + +## 核心属性 + +| 属性名 | 类型 | 说明 | +| ------------ | ----------------- | ------------------------ | +| `moveSpeed` | `number` | 当前移动速度(毫秒/格) | +| `moveDir` | `Dir2` | 当前移动方向(八方向) | +| `moving` | `boolean` | 是否处于移动状态 | +| `faceDir` | `Dir2` | 当前面朝方向(八方向) | +| `controller` | `IMoveController` | 当前移动控制实例(只读) | + +--- + +## 事件说明 + +| 事件名 | 参数 | 触发时机 | +| ----------- | ------------- | ------------------ | +| `stepEnd` | `MoveStepDir` | 单步移动完成时 | +| `moveEnd` | - | 整个移动队列完成时 | +| `moveStart` | `MoveStep[]` | 移动队列开始执行时 | + +--- + +## 方法说明 + +### `startMove` + +```typescript +function startMove(): IMoveController | null; +``` + +**功能** +启动移动队列执行 + +**返回值** +`IMoveController`:移动控制器实例(可追加指令) +`null`:队列为空或已在移动中时返回 + +**示例** + +```typescript +const controller = mover.startMove(); +if (controller) { + controller.push({ type: 'dir', value: 'right' }); +} +``` + +--- + +### `insertMove` + +```typescript +function insertMove(...move: MoveStep[]): void; +``` + +| 参数 | 类型 | 说明 | +| ------ | ------------ | ------------ | +| `move` | `MoveStep[]` | 移动指令序列 | + +**功能** +向队列末尾插入移动指令 + +**示例** + +```typescript +// 添加转向+加速指令 +mover.insertMove({ type: 'dir', value: 'left' }, { type: 'speed', value: 200 }); +``` + +--- + +### `clearMoveQueue` + +```typescript +function clearMoveQueue(): void; +``` + +**功能** +清空所有待执行移动指令 + +**注意** +不影响已开始的移动步骤 + +--- + +### `oneStep` + +```typescript +function oneStep(step: Move2): void; +``` + +| 参数 | 类型 | 说明 | +| ------ | ------- | --------------------------------- | +| `step` | `Move2` | 移动方向(支持八向/前后相对方向) | + +**功能** +添加单步方向移动指令 + +**示例** + +```typescript +// 添加面朝方向移动指令 +mover.oneStep('forward'); +``` + +--- + +### `moveAs` + +```typescript +function moveAs(steps: MoveStep[]): void; +``` + +| 参数 | 类型 | 说明 | +| ------- | ------------ | ------------------ | +| `steps` | `MoveStep[]` | 结构化移动指令序列 | + +**功能** +批量加载复杂移动路径 + +**示例** + +```typescript +mover.moveAs([ + { type: 'dir', value: 'up' }, // 向上移动 + { type: 'speed', value: 150 }, // 修改速度为每 150ms 移动一格 + { type: 'dir', value: 'rightup' } // 右上45度移动 +]); +``` + +--- + +### `setFaceDir` + +```typescript +function setFaceDir(dir: Dir2): void; +``` + +| 参数 | 类型 | 说明 | +| ----- | ------ | -------------- | +| `dir` | `Dir2` | 八方向面朝方向 | + +**限制** +仅在非移动状态生效 + +**示例** + +```typescript +// 设置角色面朝左上方 +mover.setFaceDir('leftup'); +``` + +--- + +### `setMoveDir` + +```typescript +function setMoveDir(dir: Dir2): void; +``` + +| 参数 | 类型 | 说明 | +| ----- | ------ | ------------ | +| `dir` | `Dir2` | 基础移动方向 | + +**注意** +影响`forward/backward`指令的实际方向 + +--- + +## 抽象方法 + +### `abstract onMoveStart` + +```typescript +function onMoveStart(controller: IMoveController): Promise; +``` + +**触发时机** +移动队列开始执行时 + +--- + +### `abstract onMoveEnd` + +```typescript +function onMoveEnd(controller: IMoveController): Promise; +``` + +**触发时机** +移动队列完成或被中断时 + +--- + +### `abstract onStepStart` + +```typescript +function onStepStart( + step: MoveStepDir, + controller: IMoveController +): Promise; +``` + +| 参数 | 类型 | 说明 | +| ------------ | ----------------- | ------------ | +| `step` | `MoveStepDir` | 当前移动步骤 | +| `controller` | `IMoveController` | 移动控制器 | + +**返回值** +`Promise`:步骤执行标识码(用于后续传递) + +--- + +### `abstract onStepEnd` + +```typescript +function onStepEnd( + step: MoveStepDir, + code: number, + controller: IMoveController +): Promise; +``` + +| 参数 | 类型 | 说明 | +| ------------ | ----------------- | -------------------------- | +| `code` | `number` | `onStepStart` 返回的标识码 | +| `controller` | `IMoveController` | 移动控制器 | + +--- + +### `abstract onSetMoveSpeed` + +```typescript +function onSetMoveSpeed(speed: number, controller: IMoveController): void; +``` + +| 参数 | 类型 | 说明 | +| ------------ | ----------------- | -------------- | +| `speed` | `number` | 新的移动速度值 | +| `controller` | `IMoveController` | 移动控制器 | + +--- + +## BlockMover + +`BlockMover` 是基于 `ObjectMoverBase` 的内置类,用于实现图块移动。 + +```mermaid +graph LR + BlockMover --> ObjectMoverBase + ObjectMoverBase --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +### 新增方法 + +```typescript +function bind( + x: number, + y: number, + floorId: FloorIds, + layer: FloorLayer, + dir: Dir = 'down' +): boolean; +``` + +| 参数 | 类型 | 说明 | +| --------- | ------------ | -------------------- | +| `x` | `number` | 图块 X 坐标 | +| `y` | `number` | 图块 Y 坐标 | +| `floorId` | `FloorIds` | 所在楼层 ID | +| `layer` | `FloorLayer` | 图层类型(bg/fg 等) | +| `dir` | `Dir` | 初始方向 | + +**返回值**:绑定成功返回 `true`,若目标正在移动则返回 `false` + +**示例** + +```typescript +if (blockMover.bind(5, 8, 'floor1', 'bg', 'up')) { + blockMover.insertMove({ type: 'dir', value: 'right' }); +} +``` + +--- + +## HeroMover + +`HeroMover` 是基于 `ObjectMoverBase` 的内置类,用于实现勇士移动。 + +```mermaid +graph LR + HeroMover --> ObjectMoverBase + ObjectMoverBase --> EventEmitter + + click EventEmitter "https://nodejs.org/api/events.html#class-eventemitter" +``` + +### 覆盖方法 + +```ts +function startMove( + ignoreTerrain: boolean = false, + noRoute: boolean = false, + inLockControl: boolean = false, + autoSave: boolean = false +): IMoveController | null; +``` + +| 参数 | 说明 | +| --------------- | ---------------------------------------- | +| `ignoreTerrain` | 是否忽略地形,即是否穿墙 | +| `noRoute` | 是否不计入录像 | +| `inLockControl` | 是否是在锁定控制中移动的,例如事件中移动 | +| `autoSave` | 在必要时刻是否自动存档 | + +其余用法与基类相同。 + +--- + +## 使用示例 + +### 勇士移动控制 + +```typescript +import { heroMoverCollection } from '@user/data-state'; + +// 获取勇士移动控制器单例 +const heroMover = heroMoveCollection.mover; + +// 设置面朝方向为右侧 +heroMover.setFaceDir('right'); + +// 添加移动指令:前进三步 +heroMover.insertMove( + { type: 'dir', value: 'forward' }, + { type: 'dir', value: 'forward' }, + { type: 'dir', value: 'forward' } +); + +// 启动移动并获取控制器 +const controller = heroMover.startMove( + false, // 不允许穿墙 + true, // 不计入录像 + false, // 不在录像锁定中触发 + false // 不进行自动存档 +); + +if (controller) { + // 动态追加移动指令 + controller.push({ type: 'dir', value: 'leftup' }); + // 监听移动完成事件 + controller.onEnd.then(() => { + console.log('勇士移动完成'); + }); +} +``` + +### 图块移动控制 + +```typescript +import { BlockMover } from '@user/data-state'; + +// 创建图块移动器实例 +const blockMover = new BlockMover(); + +// 绑定到(5,8)位置的背景图块 +if (blockMover.bind(5, 8, 'floor1', 'bg', 'up')) { + // 添加螺旋移动路径 + blockMover.moveAs([ + { type: 'dir', value: 'right' }, + { type: 'dir', value: 'down' }, + { type: 'dir', value: 'left' }, + { type: 'dir', value: 'up' } + ]); + + // 设置移动速度为200像素/秒 + blockMover.insertMove({ type: 'speed', value: 200 }); + + // 启动移动 + const ctrl = blockMover.startMove(); +} +``` + +--- + +## 移动指令类型 + +```typescript +type MoveStep = + | { type: 'dir'; value: Move2 } // 方向指令 + | { type: 'speed'; value: number }; // 速度指令 +``` + +--- + +## 注意事项 + +1. **方向优先级** + `forward/backward` 基于当前面朝方向计算,修改 faceDir 会影响实际移动方向 + +2. **速度叠加规则** + 多个 speed 指令按队列顺序覆盖,最终生效最后一个速度值 + +3. **移动中断处理** + 调用 controller.stop() 会立即中断移动并触发 moveEnd 事件 diff --git a/docs/api/user-data-state/index.md b/docs/api/user-data-state/index.md new file mode 100644 index 0000000..6360999 --- /dev/null +++ b/docs/api/user-data-state/index.md @@ -0,0 +1,3 @@ +# @user/data-state + +目录: diff --git a/docs/api/user-data-utils/index.md b/docs/api/user-data-utils/index.md new file mode 100644 index 0000000..bfaa99e --- /dev/null +++ b/docs/api/user-data-utils/index.md @@ -0,0 +1,3 @@ +# @user/data-utils + +目录: diff --git a/docs/api/user-entry-client/index.md b/docs/api/user-entry-client/index.md new file mode 100644 index 0000000..6579b3d --- /dev/null +++ b/docs/api/user-entry-client/index.md @@ -0,0 +1,3 @@ +# @user/entry-client + +目录: diff --git a/docs/api/user-entry-data/Mota.md b/docs/api/user-entry-data/Mota.md new file mode 100644 index 0000000..ad02971 --- /dev/null +++ b/docs/api/user-entry-data/Mota.md @@ -0,0 +1,251 @@ +# Mota API 文档 + +本文档由 `DeepSeek R1` 模型生成并微调。 + +--- + +## 核心功能 + +模块化管理系统,提供跨进程模块注册与获取能力,支持数据端与渲染端分离架构。用于解决服务端录像验证与客户端渲染的模块隔离问题。 + +--- + +## 全局访问 + +```typescript +// 浏览器环境 +Mota.require('@motajs/client'); + +// ESM 环境 +import { Mota } from '@motajs/core'; +``` + +--- + +## 核心方法 + +### `require` + +```typescript +function require(key: K): ModuleInterface[K]; +function require(key: string): T; +``` + +**功能** +获取已注册的模块实例 + +| 参数 | 类型 | 说明 | +| ----- | -------- | -------------------------- | +| `key` | `string` | 模块标识符或自定义命名空间 | + +**返回值** +对应模块的导出对象 + +**预定义模块列表**: + +```typescript +interface ModuleInterface { + // ---------- 样板库 + '@motajs/client': typeof Client; + '@motajs/client-base': typeof ClientBase; + '@motajs/common': typeof Common; + '@motajs/legacy-client': typeof LegacyClient; + '@motajs/legacy-common': typeof LegacyCommon; + '@motajs/legacy-system': typeof LegacySystem; + '@motajs/legacy-ui': typeof LegacyUI; + '@motajs/render': typeof Render; + '@motajs/render-core': typeof RenderCore; + '@motajs/render-elements': typeof RenderElements; + '@motajs/render-style': typeof RenderStyle; + '@motajs/render-vue': typeof RenderVue; + '@motajs/system': typeof System; + '@motajs/system-action': typeof SystemAction; + '@motajs/system-ui': typeof SystemUI; + // ---------- 用户扩展 + '@user/client-modules': typeof ClientModules; + '@user/data-base': typeof DataBase; + '@user/data-fallback': typeof DataFallback; + '@user/data-state': typeof DataState; + '@user/data-utils': typeof DataUtils; + '@user/legacy-plugin-client': typeof LegacyPluginClient; + '@user/legacy-plugin-data': typeof LegacyPluginData; + // ---------- 必要的第三方库 + MutateAnimate: typeof MutateAnimate; + Vue: typeof Vue; + Lodash: typeof Lodash; +} +``` + +**示例**: + +```typescript +// 获取动画引擎 +const Animate = Mota.require('MutateAnimate'); + +// 获取Vue实例 +const Vue = Mota.require('Vue'); + +// 获取旧版UI系统 +const LegacyUI = Mota.require('@motajs/legacy-ui'); +``` + +--- + +### `register` + +```typescript +function register( + key: K, + data: ModuleInterface[K] +): void; +function register(key: string, data: unknown): void; +``` + +**功能** +注册模块到全局系统 + +| 参数 | 类型 | 说明 | +| ------ | -------- | ------------ | +| `key` | `string` | 模块标识符 | +| `data` | `any` | 模块导出对象 | + +**注意事项** + +- 重复注册会触发控制台警告 +- 推荐在游戏初始化阶段注册 + +**示例**: + +```typescript +// 注册自定义模块 +class MyCustomModule { + static version = '1.0.0'; +} +Mota.register('@user/custom-module', MyCustomModule); + +// 使用自定义模块 +const custom = Mota.require('@user/custom-module'); +console.log(custom.version); // 输出 1.0.0 +``` + +--- + +## 渲染进程控制 + +### `r` + +```typescript +function r(fn: (this: T) => void, thisArg?: T): void; +``` + +**功能** +包裹只在渲染进程执行的代码 + +| 参数 | 类型 | 说明 | +| --------- | ---------- | -------------------- | +| `fn` | `Function` | 需要渲染端执行的函数 | +| `thisArg` | `any` | 函数执行上下文 | + +**特性** + +- 在录像验证和服务端环境下不会执行 +- 无返回值设计 + +**示例**: + +```typescript +// 播放仅客户端可见的特效 +Mota.r(() => { + const animate = Mota.require('MutateAnimate'); + animate(heroSprite).shake(5, 1000); +}); +``` + +--- + +### `rf` + +```typescript +function rf any, T>( + fn: F, + thisArg?: T +): (...params: Parameters) => ReturnType | undefined; +``` + +**功能** +生成渲染进程安全函数 + +| 参数 | 类型 | 说明 | +| --------- | ---------- | ---------------- | +| `fn` | `Function` | 需要包装的原函数 | +| `thisArg` | `any` | 函数执行上下文 | + +**返回值** +经过安全包裹的函数,在非渲染环境调用返回 `undefined` + +**示例**: + +```typescript +// 创建安全渲染函数 +const safeAlert = Mota.rf((msg: string) => { + alert(`客户端提示: ${msg}`); +}); + +// 调用时自动判断执行环境 +safeAlert('仅在客户端显示'); // 服务端返回 undefined +``` + +--- + +## 架构示意图 + +```mermaid +graph TD + subgraph 数据端 + Validator[录像验证系统] + CoreLogic[核心逻辑] + end + + subgraph 渲染端 + UI[用户界面] + Effects[特效系统] + Render[渲染引擎] + end + + MotaSystem -->|require/register| Validator + MotaSystem -->|r/rf| Render + CoreLogic -->|跨进程通信| Effects +``` + +--- + +## 注意事项 + +1. **模块隔离** + 数据端模块与渲染端模块物理隔离,数据端不可直接引用渲染端,而渲染端是可以直接引用数据端的 + +2. **版本兼容** + 遗留系统模块(legacy-\*)将在未来版本逐步废弃,这些模块也不再提供 API 文档,如果需要自行阅读源码。 + +3. **性能优化** + 高频调用模块建议缓存引用: + + ```typescript + // 推荐 + const Animate = Mota.require('MutateAnimate'); + + // 不推荐 + function update() { + const Animate = Mota.require('MutateAnimate'); // 每次调用都查找 + } + ``` + +4. **错误处理** + 使用 try-catch 包裹高风险模块获取: + ```typescript + try { + const LegacyUI = Mota.require('@motajs/legacy-ui'); + } catch (e) { + fallbackUI(); + } + ``` diff --git a/docs/api/user-entry-data/index.md b/docs/api/user-entry-data/index.md new file mode 100644 index 0000000..e41a4ff --- /dev/null +++ b/docs/api/user-entry-data/index.md @@ -0,0 +1,3 @@ +# @user/entry-data + +目录: diff --git a/docs/api/user-legacy-plugin-client/index.md b/docs/api/user-legacy-plugin-client/index.md new file mode 100644 index 0000000..b1780c5 --- /dev/null +++ b/docs/api/user-legacy-plugin-client/index.md @@ -0,0 +1,3 @@ +# @user/legacy-plugin-client + +目录: diff --git a/docs/api/user-legacy-plugin-data/index.md b/docs/api/user-legacy-plugin-data/index.md new file mode 100644 index 0000000..6da78f1 --- /dev/null +++ b/docs/api/user-legacy-plugin-data/index.md @@ -0,0 +1,3 @@ +# @user/legacy-plugin-data + +目录: diff --git a/docs/guide/audio.md b/docs/guide/audio.md new file mode 100644 index 0000000..e7f5254 --- /dev/null +++ b/docs/guide/audio.md @@ -0,0 +1,393 @@ +# 音频系统 + +2.B 有了与 2.A 完全不同的音频系统,新的音频系统更加自由,功能更加丰富,可以创建多种自定义效果器。本文将讲解如何使用音频系统。 + +:::tip +多数情况下,你应该不需要使用本文所介绍的内容,因为样板已经将音效、背景音乐等处理完善。如果你想实现高级效果,例如混响效果等,才需要阅读本文。 +::: + +## 获取音频播放器 + +音频播放器在 `@user/client-modules` 模块中,直接引入即可: + +```ts +// 在其他模块中使用模块化语法引入 +import { audioPlayer } from '@user/client-modules'; +// 在 client-modules 模块中使用模块化语法引入 +import { audioPlayer } from '../audio'; // 改为你自己的相对路径 + +// 使用 Mota 全局变量引入 +const { audioPlayer } = Mota.require('@user/client-modules'); +``` + +## 音频系统工作流程 + +音频播放流程如下: + +```mermaid +graph LR; + A(音频源) --> B(效果器) --> C(目的地(扬声器、耳机)) +``` + +## 创建音频源 + +:::tip +本小节的内容极大概率用不到,如果不是需要非常底层的音频接口,可以不看本小节。 +::: + +样板内置了几种音频源,它们包括: + +| 类型 | 适用场景 | 创建方法 | +| --------------- | ----------------------- | ----------------------- | +| `BufferSource` | 预加载的完整音频文件 | `createBufferSource()` | +| `ElementSource` | 通过 `