mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-09-02 21:31:47 +08:00
docs: 组件使用指南 & 部分文档微调
This commit is contained in:
parent
d39e2c2159
commit
1169db5dfd
@ -20,7 +20,7 @@ export default defineConfig({
|
||||
outline: [2, 3],
|
||||
nav: [
|
||||
{ text: '主页', link: '/' },
|
||||
{ text: '指南', link: '/guide/diff' },
|
||||
{ text: '指南', link: '/guide/quick-start' },
|
||||
{ text: 'API', link: '/api/' },
|
||||
{ text: '错误代码', link: '/logger/' }
|
||||
],
|
||||
@ -39,12 +39,17 @@ export default defineConfig({
|
||||
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/ui-future' }
|
||||
{ text: '快速浏览', link: '/guide/ui/' },
|
||||
{ text: '编写 UI', link: '/guide/ui/ui' },
|
||||
{ text: 'UI 元素', link: '/guide/ui/elements' },
|
||||
{
|
||||
text: '组件使用指南',
|
||||
link: '/guide/ui/component'
|
||||
},
|
||||
{ text: '优化性能', link: '/guide/ui/perf' },
|
||||
{ text: 'UI 系统', link: '/guide/ui/system' },
|
||||
{ text: '常见问题', link: '/guide/ui/faq' },
|
||||
{ text: '未来规划', link: '/guide/ui/future' }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -7,7 +7,22 @@
|
||||
## 接口定义
|
||||
|
||||
```typescript
|
||||
interface GraphicBaseProps extends BaseProps {
|
||||
interface ILineProperty {
|
||||
/** 线宽 */
|
||||
lineWidth: number;
|
||||
/** 线的虚线设置 */
|
||||
lineDash?: number[];
|
||||
/** 虚线偏移量 */
|
||||
lineDashOffset?: number;
|
||||
/** 线的连接样式 */
|
||||
lineJoin: CanvasLineJoin;
|
||||
/** 线的顶端样式 */
|
||||
lineCap: CanvasLineCap;
|
||||
/** 线的斜接限制,当连接为miter类型时可填,默认为10 */
|
||||
miterLimit: number;
|
||||
}
|
||||
|
||||
interface GraphicBaseProps extends BaseProps, Partial<ILineProperty> {
|
||||
/** 是否填充(默认 false) */
|
||||
fill?: boolean;
|
||||
/** 是否描边(默认 false) */
|
||||
@ -29,15 +44,21 @@ interface GraphicBaseProps extends BaseProps {
|
||||
|
||||
## 核心属性说明
|
||||
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
| --------------- | ----------------------------------------------- | ----------- | -------------------------------------------------------------- |
|
||||
| `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` 使用) |
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
| ---------------- | ----------------------------------------------- | ----------- | -------------------------------------------------------------- |
|
||||
| `fill` | `boolean` | `false` | 启用填充 |
|
||||
| `stroke` | `boolean` | `false` | 启用描边 |
|
||||
| `strokeAndFill` | `boolean` | `false` | 先描边后填充 |
|
||||
| `fillRule` | `'nonzero'` \| `'evenodd'` | `'evenodd'` | 填充路径环绕原则 |
|
||||
| `fillStyle` | `string` \| `CanvasGradient` \| `CanvasPattern` | - | 填充样式 |
|
||||
| `strokeStyle` | `string` \| `CanvasGradient` \| `CanvasPattern` | - | 描边样式 |
|
||||
| `actionStroke` | `boolean` | `false` | 设为 `true` 时,交互事件仅响应描边区域(需配合 `stroke` 使用) |
|
||||
| `lineWidth` | `number` | `2` | 设置描边的线宽 |
|
||||
| `lineDash` | `number[]` | `[]` | 设置虚线样式 |
|
||||
| `lineDashOffset` | `number` | `0` | 虚线样式偏移量 |
|
||||
| `lineJoin` | `string` | `bevel` | 线的连接方式 |
|
||||
| `lineCap` | `string` | `butt` | 线的末端样式 |
|
||||
| `miterLimit` | `number` | `10` | 当使用 `miter` 连接方式时,其最大斜接限制 |
|
||||
|
||||
---
|
||||
|
||||
@ -55,8 +76,8 @@ interface GraphicBaseProps extends BaseProps {
|
||||
|
||||
**效果**:
|
||||
|
||||
- 200x150 矩形
|
||||
- 无描边效果
|
||||
- 200x150 矩形
|
||||
- 无描边效果
|
||||
|
||||
---
|
||||
|
||||
@ -67,15 +88,15 @@ interface GraphicBaseProps extends BaseProps {
|
||||
loc={[400, 200, 180, 120]}
|
||||
stroke
|
||||
strokeStyle="rgba(0,0,0,0.8)"
|
||||
strokeWidth={4}
|
||||
lineWidth={4}
|
||||
actionStroke // 点击时仅描边区域响应
|
||||
/>
|
||||
```
|
||||
|
||||
**交互特性**:
|
||||
|
||||
- 4px 黑色半透明描边
|
||||
- 鼠标悬停在描边区域才会触发事件
|
||||
- 4px 黑色半透明描边
|
||||
- 鼠标悬停在描边区域才会触发事件
|
||||
|
||||
---
|
||||
|
||||
@ -88,7 +109,7 @@ interface GraphicBaseProps extends BaseProps {
|
||||
stroke
|
||||
fillStyle="#ffe66d"
|
||||
strokeStyle="#2d3436"
|
||||
strokeWidth={2}
|
||||
lineWidth={2}
|
||||
/>
|
||||
```
|
||||
|
||||
@ -99,7 +120,7 @@ interface GraphicBaseProps extends BaseProps {
|
||||
|
||||
---
|
||||
|
||||
### 示例 4:强制先描边后填充
|
||||
### 示例 4:先描边后填充
|
||||
|
||||
```tsx
|
||||
<g-rect
|
||||
@ -107,7 +128,7 @@ interface GraphicBaseProps extends BaseProps {
|
||||
strokeAndFill
|
||||
fillStyle="#a29bfe"
|
||||
strokeStyle="#6c5ce7"
|
||||
strokeWidth={8}
|
||||
lineWidth={8}
|
||||
/>
|
||||
```
|
||||
|
||||
@ -138,7 +159,7 @@ const leave = () => void (hovered.value = false);
|
||||
fillStyle="#ffffff"
|
||||
stroke={hovered.value}
|
||||
strokeStyle="#e84393"
|
||||
strokeWidth={3}
|
||||
lineWidth={3}
|
||||
onEnter={enter}
|
||||
onLeave={leave}
|
||||
/>;
|
||||
|
@ -8,18 +8,27 @@
|
||||
|
||||
图标比例固定,会自动根据传入的长宽缩放。
|
||||
|
||||
图标继承所有图形参数,参考[此文档](../motajs-render-vue/GraphicBaseProps.md)
|
||||
|
||||
## 图标列表
|
||||
|
||||
- `RollbackIcon`: 回退图标
|
||||
- `RetweenIcon`: 回收图标
|
||||
- `ViewMapIcon`: 浏览地图图标
|
||||
- `DanmakuIcon`: 弹幕图标
|
||||
- `ReplayIcon`: 回放图标
|
||||
- `numpadIcon`: 数字键盘图标
|
||||
- `PlayIcon`: 开始播放图标
|
||||
- `PauseIcon`: 暂停播放图标
|
||||
- `DoubleArrow`: 双箭头图标(向右)
|
||||
- `StepForward`: 单步向前图标
|
||||
- `RollbackIcon`: 回退图标
|
||||
- `RetweenIcon`: 回收图标
|
||||
- `ViewMapIcon`: 浏览地图图标
|
||||
- `DanmakuIcon`: 弹幕图标
|
||||
- `ReplayIcon`: 回放图标
|
||||
- `numpadIcon`: 数字键盘图标
|
||||
- `PlayIcon`: 开始播放图标
|
||||
- `PauseIcon`: 暂停播放图标
|
||||
- `DoubleArrow`: 双箭头图标(向右)
|
||||
- `StepForward`: 单步向前图标
|
||||
- `SoundVolume`: 音量图标
|
||||
- `Fullscreen`: 全屏图标
|
||||
- `ExitFullscreen`: 退出全屏图标
|
||||
- `ArrowLeftTailless`: 无尾巴左箭头图标
|
||||
- `ArrowRightTailless`: 无尾巴右箭头图标
|
||||
- `ArrowUpTailless`: 无尾巴上箭头图标
|
||||
- `ArrowDownTailless`: 无尾巴下箭头图标
|
||||
|
||||
## 使用示例
|
||||
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
## 组件特性
|
||||
|
||||
- **虚拟滚动**:自动裁剪可视区域外元素
|
||||
- **双模式支持**:垂直/水平滚动(默认垂直)
|
||||
- **性能优化**:动态计算可视区域,支持万级元素流畅滚动
|
||||
- **编程控制**:支持精准定位滚动位置
|
||||
- **虚拟滚动**:自动裁剪可视区域外元素
|
||||
- **双模式支持**:垂直/水平滚动(默认垂直)
|
||||
- **性能优化**:动态计算可视区域,支持万级元素流畅滚动
|
||||
- **编程控制**:支持精准定位滚动位置
|
||||
|
||||
---
|
||||
|
||||
@ -116,3 +116,14 @@ export const MyCom = defineComponent(() => {
|
||||
{page => renderChunk(data.slice(page * 50, (page + 1) * 50))}
|
||||
</Page>
|
||||
```
|
||||
|
||||
### 2. 缓存建议
|
||||
|
||||
如果子元素数量较多,建议给 `Scroll` 组件的所有子元素添加 `nocache` 标记:
|
||||
|
||||
```tsx {2}
|
||||
<Scroll>
|
||||
<item nocache />
|
||||
{/* 更多内容 */}
|
||||
</Scroll>
|
||||
```
|
||||
|
@ -18,17 +18,17 @@ lang: zh-CN
|
||||
|
||||
## 主要差异
|
||||
|
||||
- 开发语言换为 TypeScript,可以享受到完整的类型支持
|
||||
- 使用全新的 UI 编写方式,速度快,效率高
|
||||
- 模块化,可以使用 ES6 模块化语法
|
||||
- 移除插件系统,可以自定义代码目录结构,更加自由
|
||||
- 优化渲染端(client 端)与数据端(data 端)的通讯,渲染端现在可以直接引用数据端,不过数据端还不能直接引用渲染端
|
||||
- 开发语言换为 TypeScript,可以享受到完整的类型支持
|
||||
- 使用全新的 UI 编写方式,速度快,效率高
|
||||
- 模块化,可以使用 ES6 模块化语法
|
||||
- 移除插件系统,可以自定义代码目录结构,更加自由
|
||||
- 优化渲染端(client 端)与数据端(data 端)的通讯,渲染端现在可以直接引用数据端,不过数据端还不能直接引用渲染端
|
||||
|
||||
## 差异内容
|
||||
|
||||
相比于 2.10.3 及 2.A,有如下改动:
|
||||
|
||||
- [系统说明](./system)
|
||||
- [UI 编写](./ui)
|
||||
- [UI 系统](./ui-system)
|
||||
- [音频系统](./audio)
|
||||
- [系统说明](./system)
|
||||
- [UI 编写](./ui)
|
||||
- [UI 系统](./ui/system)
|
||||
- [音频系统](./audio)
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
2.B 提供了专门的动画接口,允许你用短短几行就可以做出一个效果不错的动画。本节主要讲述的是 UI 中的动画。
|
||||
|
||||
:::warning
|
||||
`mutate-animate` 库在未来会重构,可能会修改引入方式,但整体逻辑不会怎么变。
|
||||
:::
|
||||
|
||||
## 定义动画属性
|
||||
|
||||
我们以一个自定义 UI 为例,来讲述如何编写一段动画。自定义 UI 参考[此指南](./new-ui.md)和[此教程](../../guide/ui.md)。
|
||||
|
@ -179,6 +179,98 @@ export const MyCom = defineComponent(props => {
|
||||
});
|
||||
```
|
||||
|
||||
## 拓展-输入框
|
||||
|
||||
与选择框、确认框类似,只不过允许玩家输入一段内容,然后返回给程序。使用 `getInput` 来让玩家输入字符串,使用 `getInputNumber` 来让玩家输入数字。
|
||||
|
||||
输入框包含一个确认键和取消键,玩家点击确认键时会将输入结果返回,而如果点击了取消,那么会返回空字符串或 `NaN`。
|
||||
|
||||
### 输入字符串
|
||||
|
||||
使用 `getInput` 接口:
|
||||
|
||||
```tsx
|
||||
import { getInput } from '../components';
|
||||
|
||||
// UI 模板及如何编写 UI 参考 “新增 UI” 需求指南,这里只给出必要的修改部分,模板部分不再给出
|
||||
export const MyCom = defineComponent(props => {
|
||||
const click = async () => {
|
||||
// 调用接口,并等待执行完毕,获取异步返回值
|
||||
const inputData = await getInput(
|
||||
props.controller, // UI 控制器
|
||||
'请输入一句话', // 显示的文字
|
||||
[240, 240, void 0, void 0, 0.5, 0.5], // 输入框位置
|
||||
240, // 输入框宽度
|
||||
// 其他参数配置,参考 API 文档
|
||||
{
|
||||
// 例如设置一个占位符
|
||||
input: {
|
||||
placeholder: '输入一句话'
|
||||
}
|
||||
}
|
||||
);
|
||||
if (inputData.length === 0) {
|
||||
// 如果用户没有输入任何内容或点了取消
|
||||
} else {
|
||||
// 如果用户输入了内容
|
||||
}
|
||||
};
|
||||
|
||||
return () => (
|
||||
<container>
|
||||
<text
|
||||
text="这是一个按钮"
|
||||
// 监听 click 事件
|
||||
onClick={click}
|
||||
/>
|
||||
</container>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### 输入数字
|
||||
|
||||
与 `getInput` 类似,不过要用 `getInputNumber` 接口:
|
||||
|
||||
```tsx
|
||||
import { getInputNumber } from '../components';
|
||||
|
||||
// UI 模板及如何编写 UI 参考 “新增 UI” 需求指南,这里只给出必要的修改部分,模板部分不再给出
|
||||
export const MyCom = defineComponent(props => {
|
||||
const click = async () => {
|
||||
// 调用接口,并等待执行完毕,获取异步返回值
|
||||
const num = await getInputNumber(
|
||||
props.controller, // UI 控制器
|
||||
'请输入一个数字', // 显示的文字
|
||||
[240, 240, void 0, void 0, 0.5, 0.5], // 输入框位置
|
||||
240, // 输入框宽度
|
||||
// 其他参数配置,参考 API 文档
|
||||
{
|
||||
// 例如设置一个占位符
|
||||
input: {
|
||||
placeholder: '输入数字'
|
||||
}
|
||||
}
|
||||
);
|
||||
if (isNaN(num)) {
|
||||
// 如果用户输入的不是数字或点了取消
|
||||
} else {
|
||||
// 如果用户输入了数字
|
||||
}
|
||||
};
|
||||
|
||||
return () => (
|
||||
<container>
|
||||
<text
|
||||
text="这是一个按钮"
|
||||
// 监听 click 事件
|
||||
onClick={click}
|
||||
/>
|
||||
</container>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
## 拓展-API参考
|
||||
|
||||
- [ConfirmBox](../../api/user-client-modules/组件%20ConfirmBox.md)
|
||||
|
@ -7,13 +7,37 @@
|
||||
|
||||
## 客户端内容
|
||||
|
||||
以下内容中,一级列表是基础需求指南,二级列表是拓展需求指南。
|
||||
|
||||
- [修改状态栏显示](./status-bar.md)
|
||||
- [可交互按钮](./status-bar.md#拓展-可交互按钮)
|
||||
- [新增勇士属性](./status-bar.md#拓展-新增勇士属性) (既包含客户端,也包含数据端)
|
||||
- [编写新 UI](./new-ui.md)
|
||||
- [自定义按键](./hotkey.md)
|
||||
- [UI 与组件的区别](./new-ui.md#拓展-ui-与组件的区别)
|
||||
- [UI 编写参考](../ui.md)
|
||||
- [新增按键](./hotkey.md)
|
||||
- [添加辅助按键](./hotkey.md#拓展-添加辅助按键)
|
||||
- [在 UI 内实现按键](./hotkey.md#拓展-在-ui-内实现按键)
|
||||
- [单功能多按键](./hotkey.md#拓展-单功能多按键)
|
||||
- [按下时触发](./hotkey.md#拓展-按下时触发)
|
||||
- [动画效果](./animate.md)
|
||||
- [颜色动画](./animate.md#拓展-颜色动画)
|
||||
- [配合交互](./animate.md#拓展-配合交互)
|
||||
- [选择框与确认框](./choice.md)
|
||||
- [使用枚举定义选择框](./choice.md#拓展-使用枚举定义选择框)
|
||||
- [等待框](./choice.md#拓展-等待框)
|
||||
- [输入框](./choice.md#拓展-输入框)
|
||||
|
||||
## 数据端内容
|
||||
|
||||
- [怪物伤害计算](./damage.md)
|
||||
以下内容中,一级列表是基础需求指南,二级列表是拓展需求指南。
|
||||
|
||||
- [怪物特殊属性](./special.md)
|
||||
- [用函数声明属性](./special.md#拓展-用函数声明属性)
|
||||
- [地图伤害](./special.md#拓展-地图伤害)
|
||||
- [光环属性](./special.md#拓展-光环属性)
|
||||
- [输出回合数](./special.md#拓展-输出回合数)
|
||||
- [主动技能](./skill.md)
|
||||
- [多技能设计思路](./skill.md#拓展-多技能设计思路)
|
||||
- [战后自动关闭技能](./skill.md#拓展-战后自动关闭技能)
|
||||
- [在开启或关闭技能时执行内容](./skill.md#拓展-在开启或关闭技能时执行内容)
|
||||
|
@ -265,7 +265,7 @@ col.applyHalo(
|
||||
|
||||
## 拓展-输出回合数
|
||||
|
||||
样板默认的 `calDamageWith` 函数只允许输出伤害值,而有时候我们可能会需要战斗的回合数,这时候我们需要修改一下这部分内容,将伤害计算逻辑单独提出来,然后在 `calDamageWith` 中调用它。在需要回合数的时候,我们调用提出了的函数即可,如下例所示:
|
||||
样板默认的 `calDamageWith` 函数只允许输出伤害值,而有时候我们可能会需要战斗的回合数,这时候我们需要修改一下这部分内容,将伤害计算逻辑单独提出来,命名为 `calDamageWithTurn`,然后在 `calDamageWith` 中调用它。在需要回合数的时候,我们调用 `calDamageWithTurn` 函数即可,如下例所示:
|
||||
|
||||
```ts
|
||||
/** 包含回合数的伤害计算 */
|
||||
|
@ -181,6 +181,47 @@ leftStatus.def = getHeroStatusOn('def');
|
||||
leftStatus.atkSpeed = getHeroStatusOn('atkSpeed');
|
||||
```
|
||||
|
||||
状态栏组件中:
|
||||
|
||||
```tsx
|
||||
// 使用模板字符串,显示百分比
|
||||
<text text={`${s.atkSpeed * 100}%`} />
|
||||
```
|
||||
|
||||
### 属性实现
|
||||
|
||||
为了实现勇士属性,我们需要修改伤害计算逻辑。我们打开 `packages-user/data-state/src/enemy/damage.ts`,翻到最后找到 `calDamageWith` 函数,在它上面有一个名为 `realStatus` 的数组,我们在这里新增一项 `atkSpeed`:
|
||||
|
||||
```ts
|
||||
/**
|
||||
* 计算伤害时会用到的勇士属性,攻击防御,其余的不会有buff加成,直接从core.status.hero取
|
||||
*/
|
||||
const realStatus: (keyof HeroStatus)[] = [
|
||||
'atk',
|
||||
'def',
|
||||
// ... 原有内容
|
||||
|
||||
// 新增 atkSpeed 属性
|
||||
'atkSpeed' // [!code ++]
|
||||
];
|
||||
```
|
||||
|
||||
然后在 `calDamageWith` 伤害计算中修改伤害计算,给勇士每回合造成的伤害乘以攻速,注意放置的位置:
|
||||
|
||||
```ts
|
||||
export function calDamageWith(
|
||||
info: UserEnemyInfo,
|
||||
hero: Partial<HeroStatus>
|
||||
): number {
|
||||
// ... 原有逻辑
|
||||
|
||||
// 乘以攻速
|
||||
heroPerDamage *= hero.atkSpeed ?? 1;
|
||||
|
||||
// ... 原有逻辑
|
||||
}
|
||||
```
|
||||
|
||||
## 拓展-了解 UI 编写的基本逻辑
|
||||
|
||||
参考[此文档](./ui.md),此文档将会教你如何从头开始编写一个 UI,并解释 UI 运行与渲染的基本逻辑。
|
||||
|
@ -6,11 +6,15 @@
|
||||
|
||||
参考[此文档](./implements.md)
|
||||
|
||||
## 热重载
|
||||
|
||||
2.B 样板支持热重载,允许一些内容在不刷新页面的情况下就可以直接更新,包括 UI、怪物数据、道具数据等。例如,你在编辑器里面修改了一个怪物的攻击并保存,这时候进入游戏界面,可以直接看到地图上的怪物伤害变化了(怪物手册等 UI 中的怪物数据需要重新打开一次 UI 才会更新)。
|
||||
|
||||
## 启动游戏与编辑器
|
||||
|
||||
在造塔群中的群文件中找到 `启动服务->2.B+ 启动服务`,根据自己设备的系统下载对应的启动服务(此版本不支持移动端造塔),下载后运行安装到自己的设备,可以选择安装路径。
|
||||
|
||||
安装完毕后,打开软件,在左侧点击选择文件夹,然后打开 2.B 样板文件夹,即包含 `package.json` `packages` `packages-user` 这些目录的文件,打开错了会提示打开错误。
|
||||
安装完毕后,打开软件,在左侧点击选择文件夹,然后打开 2.B 样板文件夹,即包含 `package.json` `packages` `packages-user` 这些目录的文件夹,打开错了会提示打开错误。
|
||||
|
||||
然后点击右侧的安装依赖,耐心等待一段时间,等待依赖安装完毕。
|
||||
|
||||
@ -82,7 +86,9 @@ graph TD
|
||||
|
||||
### 协议问题
|
||||
|
||||
2.B 样板换用了 `GPL3.0` 开源协议,这要求所有以此为基础开发的项目也必须完全开源,但考虑到很多作者不了解其中的细节,因此样板将会针对此问题自动处理,处理方案为:**将源码原封不动地打包为压缩包,放到构建完成的游戏中**,届时,只要在网站上下载游戏,就可以解压压缩包查看源码。
|
||||
2.B 样板换用了 `GPL3.0` 开源协议,这要求所有以此为基础开发的项目也必须完全开源,但考虑到很多作者不了解其中的细节,因此样板将会针对此问题自动处理,处理方案为:**将源码原封不动地打包为压缩包,放到构建完成的游戏中**,届时,只要在网站上下载游戏,就可以解压压缩包查看源码及开源协议。
|
||||
|
||||
同时,这也意味着,如果你使用本样板开发游戏,其他任何人都可以以你的游戏为基础进行二次开发,而不需要你本人同意。如果不想让素材也能被别人使用,可以单独针对素材使用其他协议(如 `CC` 协议,可以上网查询具体信息),而不使用 `GPL3.0` 协议,但代码必须遵循 `GPL3.0` 协议。
|
||||
|
||||
## 学会查阅此文档
|
||||
|
||||
|
556
docs/guide/ui/component.md
Normal file
556
docs/guide/ui/component.md
Normal file
@ -0,0 +1,556 @@
|
||||
# 组件使用指南
|
||||
|
||||
2.B 内置了很多实用的组件,本节将会介绍一些常用组件的使用方式。
|
||||
|
||||
## 组件引入
|
||||
|
||||
组件都在 `packages-user/client-modules/src/render/components` 文件夹中,如果在 `ui` 文件夹下引用,注意路径关系,应该如下引入:
|
||||
|
||||
```ts
|
||||
// 从 components 文件夹引入,注意路径关系
|
||||
import { TextContent } from '../components';
|
||||
```
|
||||
|
||||
## 组件与元素
|
||||
|
||||
一般情况下,组件会包含所有元素拥有的参数,例如 `loc` `alpha` `zIndex`,甚至是 `noevent` `cache` 等,也可以监听 `onClick` `onEnter` 这些交互事件。
|
||||
|
||||
除了元素的参数,组件自身可能还会包含一些参数和事件。
|
||||
|
||||
有些组件还提供了暴露接口,可以使用这些接口直接控制组件内部。
|
||||
|
||||
## 多行文本 TextContent
|
||||
|
||||
类似于 2.x 的 `drawTextContent`,可以用于多行文本,包含打字机功能。相比于 `drawTextContent` 的主要优势是支持了英文以及更好的性能表现。
|
||||
|
||||
### 显示文字
|
||||
|
||||
直接调用组件即可:
|
||||
|
||||
```tsx
|
||||
import { TextContent } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
// 显示一段长文字
|
||||
const toShow = 'man what can i say '.repeat(10);
|
||||
|
||||
return () => (
|
||||
<container>
|
||||
{/* 直接调用组件,其中宽度 width 必填,而 loc 中设定的宽度是无效的 */}
|
||||
<TextContent loc={[0, 0, 240, 200]} width={240} text={toShow} />
|
||||
</container>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### 常用配置
|
||||
|
||||
| 配置 | 数据类型 | 说明 |
|
||||
| ------------- | --------- | ------------------------------------------ |
|
||||
| `font` | `Font` | 文字字体 |
|
||||
| `interval` | `number` | 打字机效果每两个字之间的时间间隔,单位毫秒 |
|
||||
| `lineHeight` | `number` | 行间距,单位像素 |
|
||||
| `fill` | `boolean` | 是否填充文字,默认填充 |
|
||||
| `stroke` | `boolean` | 是否描边文字,默认不描边 |
|
||||
| `fillStyle` | `string` | 文字填充样式 |
|
||||
| `strokeStyle` | `string` | 文字描边样式 |
|
||||
|
||||
使用示例:
|
||||
|
||||
:::code-group
|
||||
|
||||
```tsx [自定义字体]
|
||||
import { Font } from '@motajs/style'; // [!code ++]
|
||||
import { TextContent } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
// 显示一段长文字
|
||||
const toShow = 'man what can i say '.repeat(10);
|
||||
// 24px 大小的 Arial 字体
|
||||
const myFont = new Font('Arial', 24); // [!code ++]
|
||||
|
||||
return () => (
|
||||
<container>
|
||||
<TextContent
|
||||
loc={[0, 0, 240, 200]}
|
||||
width={240}
|
||||
text={toShow}
|
||||
font={myFont} // 使用自定义字体 [!code ++]
|
||||
/>
|
||||
</container>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
```tsx [修改字体颜色]
|
||||
import { TextContent } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
// 显示一段长文字
|
||||
const toShow = 'man what can i say '.repeat(10);
|
||||
|
||||
return () => (
|
||||
<container>
|
||||
<TextContent
|
||||
loc={[0, 0, 240, 200]}
|
||||
width={240}
|
||||
text={toShow}
|
||||
fill // 文字填充 [!code ++]
|
||||
stroke // 文字描边 [!code ++]
|
||||
fillStyle="yellow" // 文字填充为黄色 [!code ++]
|
||||
strokeStyle="cyan" // 文字描边为青色 [!code ++]
|
||||
/>
|
||||
</container>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
```tsx [修改行间距]
|
||||
import { TextContent } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
// 显示一段长文字
|
||||
const toShow = 'man what can i say '.repeat(10);
|
||||
|
||||
return () => (
|
||||
<container>
|
||||
<TextContent
|
||||
loc={[0, 0, 240, 200]}
|
||||
width={240}
|
||||
text={toShow}
|
||||
lineHeight={8} // 行间距为 8px [!code ++]
|
||||
/>
|
||||
</container>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### 自动调整高度
|
||||
|
||||
如果我们不知道这些文字显示的时候会有多高,那么我们可以使用 `autoHeight` 来让组件自动确定自身的高度,可以用于滚动条等场景。
|
||||
|
||||
```tsx
|
||||
import { TextContent } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
// 显示一段长文字
|
||||
const toShow = 'man what can i say '.repeat(10);
|
||||
|
||||
return () => (
|
||||
<container>
|
||||
<TextContent
|
||||
loc={[0, 0, 240, 200]}
|
||||
width={240}
|
||||
text={toShow}
|
||||
autoHeight // 使用 autoHeight,让组件自动确定自己的高度 [!code ++]
|
||||
/>
|
||||
</container>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### 转义字符
|
||||
|
||||
与 2.x 类似,2.B 的 `TextContent` 也允许转义字符。具体请参考[此文档](../../api/user-client-modules/TextContentParser.md#转义字符语法说明)。
|
||||
|
||||
### API 参考
|
||||
|
||||
`TextContent` 还有很多功能和特性,这里只做最基础的教学,如果需要其他功能,请参考[API 文档](../../api/user-client-modules/组件%20TextContent.md)
|
||||
|
||||
## 滚动条 Scroll
|
||||
|
||||
`Scroll` 是滚动条组件,如果内容在一个界面大小内显示不下,可以使用滚动条组件,这样玩家可以使用鼠标滚轮或点击拖动来滚动内容。
|
||||
|
||||
### 基本使用
|
||||
|
||||
直接调用组件,然后填写组件内容即可:
|
||||
|
||||
```tsx {7-10}
|
||||
import { Scroll } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
return () => (
|
||||
// loc 必填,表示组件位置
|
||||
<Scroll loc={[0, 0, 416, 416]}>
|
||||
<text text="text1" />
|
||||
{/* 省略更多内容 */}
|
||||
</Scroll>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### 平铺布局
|
||||
|
||||
在使用 `Scroll` 组件时,我们推荐使用平铺式布局,即所有内容平铺在 `Scroll` 组件中,而不是将整体用一个 `container` 将它包起来,这非常有助于提高滚动条组件的性能。
|
||||
|
||||
例如下面这种格式就是**好的写法**:
|
||||
|
||||
```tsx {8-10}
|
||||
import { Scroll } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
return () => (
|
||||
<Scroll loc={[0, 0, 416, 416]}>
|
||||
{/* 平铺内容,性能表现更好 */}
|
||||
<text text="text1" />
|
||||
<text text="text2" />
|
||||
<text text="text3" />
|
||||
{/* 省略更多内容 */}
|
||||
</Scroll>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
而下面这种就是**不好的写法**:
|
||||
|
||||
```tsx {8-12}
|
||||
import { Scroll } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
return () => (
|
||||
<Scroll loc={[0, 0, 416, 416]}>
|
||||
{/* 用一个 container 包裹,性能表现不好 */}
|
||||
<container>
|
||||
<text text="text1" />
|
||||
<text text="text2" />
|
||||
<text text="text3" />
|
||||
</container>
|
||||
</Scroll>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### 横向滚动条
|
||||
|
||||
添加 `hor` 标记,即可使滚动条变为横向。暂时没有既可以横向又可以纵向的滚动条。
|
||||
|
||||
```tsx {7}
|
||||
import { Scroll } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
return () => (
|
||||
// 添加 hor 标记,变为横向
|
||||
<Scroll loc={[0, 0, 416, 416]} hor>
|
||||
<text text="text1" />
|
||||
{/* 省略更多内容 */}
|
||||
</Scroll>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### 隐藏滚动条
|
||||
|
||||
有时候可能需要隐藏滚动条(例如样板的浏览地图界面中左侧的楼层列表),可以使用 `noscroll` 标记实现:
|
||||
|
||||
```tsx {7}
|
||||
import { Scroll } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
return () => (
|
||||
// 添加 noscroll 标记,隐藏滚动条
|
||||
<Scroll loc={[0, 0, 416, 416]} noscroll>
|
||||
<text text="text1" />
|
||||
{/* 省略更多内容 */}
|
||||
</Scroll>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### 布局补偿
|
||||
|
||||
有时候我们需要在滚动条滚动到最后时填充一些空白内容,可以使用 `padEnd` 来实现:
|
||||
|
||||
```tsx {7}
|
||||
import { Scroll } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
return () => (
|
||||
// 使用 padEnd 在滚动条最后填充空白内容,单位像素
|
||||
<Scroll loc={[0, 0, 416, 416]} padEnd={120}>
|
||||
<text text="text1" />
|
||||
{/* 省略更多内容 */}
|
||||
</Scroll>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### 代码控制滚动条
|
||||
|
||||
可以使用 `Scroll` 提供的接口来用代码控制滚动条:
|
||||
|
||||
```tsx {5-12,15-16}
|
||||
import { Scroll, ScrollExpose } from '../components'; // [!code ++]
|
||||
import { vue } from 'vue'; // [!code ++]
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
// 使用响应式变量定义 scroll 引用
|
||||
const scrollRef = ref<ScrollExpose>();
|
||||
|
||||
onMounted(() => {
|
||||
// 滚动至 100 像素的位置,动画时长 500ms
|
||||
scrollRef.value?.scrollTo(100, 500);
|
||||
});
|
||||
|
||||
return () => (
|
||||
// 将 ref 属性设为 scrollRef 来获取 Scroll 的接口
|
||||
<Scroll loc={[0, 0, 416, 416]} ref={scrollRef}>
|
||||
<text text="text1" />
|
||||
{/* 省略更多内容 */}
|
||||
</Scroll>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### API 参考
|
||||
|
||||
API 参考[此文档](../../api/user-client-modules/组件%20Scroll.md)。
|
||||
|
||||
## 图标组件
|
||||
|
||||
在 `components/icons.tsx` 中内置了一些图标,可以直接使用。
|
||||
|
||||
### 基本使用
|
||||
|
||||
以箭头图标为例:
|
||||
|
||||
```tsx {8}
|
||||
import { ArrowDownTailless } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
return () => (
|
||||
<container>
|
||||
{/* 调用图标组件 */}
|
||||
<ArrowDownTailless loc={[0, 0, 48, 48]} />
|
||||
</container>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
所有图标都可以填写图形元素的参数,例如 `fill` `stroke` `strokeStyle` `lineWidth` 等。大部分图标默认都是描边样式,如果使用填充可能会导致效果不好。例如修改描边样式和线宽:
|
||||
|
||||
```tsx {8}
|
||||
import { ArrowDownTailless } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
return () => (
|
||||
<container>
|
||||
<ArrowDownTailless
|
||||
loc={[0, 0, 48, 48]}
|
||||
strokeStyle="cyan" // 描边使用青色
|
||||
lineWidth={2} // 线宽为 2px
|
||||
/>
|
||||
</container>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### 图标列表
|
||||
|
||||
目前样板包含这些图标:
|
||||
|
||||
- `RollbackIcon`: 回退图标
|
||||
- `RetweenIcon`: 回收图标
|
||||
- `ViewMapIcon`: 浏览地图图标
|
||||
- `DanmakuIcon`: 弹幕图标
|
||||
- `ReplayIcon`: 回放图标
|
||||
- `numpadIcon`: 数字键盘图标
|
||||
- `PlayIcon`: 开始播放图标
|
||||
- `PauseIcon`: 暂停播放图标
|
||||
- `DoubleArrow`: 双箭头图标(向右)
|
||||
- `StepForward`: 单步向前图标
|
||||
- `SoundVolume`: 音量图标
|
||||
- `Fullscreen`: 全屏图标
|
||||
- `ExitFullscreen`: 退出全屏图标
|
||||
- `ArrowLeftTailless`: 无尾巴左箭头图标
|
||||
- `ArrowRightTailless`: 无尾巴右箭头图标
|
||||
- `ArrowUpTailless`: 无尾巴上箭头图标
|
||||
- `ArrowDownTailless`: 无尾巴下箭头图标
|
||||
|
||||
### API 及参数参考
|
||||
|
||||
参数参考[此文档](../../api/motajs-render-vue/GraphicBaseProps.md)。
|
||||
|
||||
API 参考[此文档](../../api/user-client-modules/图标组件.md)
|
||||
|
||||
## 分页 Page
|
||||
|
||||
分页可以用来展示大量内容,在极端情况下,其性能要比 `Scroll` 更好,但交互手感与易用性不如滚动条。
|
||||
|
||||
### 基本使用
|
||||
|
||||
`Page` 组件需要传入两个必填参数 `pages` 和 `loc`,`pages` 代表总页数,`loc` 代表位置。
|
||||
|
||||
每个页面的内容使用插槽形式传入,接收 `page` 作为参数,代表当前是第几页。你可能不理解这句话,用代码写的话就是这样:
|
||||
|
||||
```tsx {6-17}
|
||||
import { Page } from '../components';
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
return () => (
|
||||
<Page
|
||||
loc={[0, 0, 416, 416]} // 位置
|
||||
pages={10} // 总页码数
|
||||
>
|
||||
{/* 插槽内容,传入一个函数,参数代表当前是第几页 */}
|
||||
{(page: number) => (
|
||||
<container>
|
||||
{/* 这里面填写当前页显示的内容,例如添加一个文字显示当前第几页 */}
|
||||
<text text={page.toString()} />
|
||||
</container>
|
||||
)}
|
||||
</Page>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### 第一种设置与获取当前页
|
||||
|
||||
可以通过 `v-model` 指令来创建双向数据绑定,从而达到设置与获取当前页码的功能。
|
||||
|
||||
这种方式一般情况下相对来说没有下一节提到的方式更好,因此相对不推荐。使用示例如下:
|
||||
|
||||
```tsx {7-13}
|
||||
import { Page } from '../components';
|
||||
// 从 vue 引入 ref 响应式函数
|
||||
import { ref, watch } from 'vue'; // [!code ++]
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
// 定义响应式变量
|
||||
const nowPage = ref(0);
|
||||
|
||||
// 监听当且页码的变化,需要的时候直接用 nowPage.value 获取也可
|
||||
watch(nowPage, value => core.drawTip(`切换至${value}页!`));
|
||||
/** 设置当前页码 */
|
||||
const changePage = (value: number) => void (nowPage.value = value);
|
||||
|
||||
return () => (
|
||||
<Page
|
||||
loc={[0, 0, 416, 416]}
|
||||
pages={10}
|
||||
// 使用 v-model 指令创建双向数据绑定
|
||||
v-model:page={nowPage.value} // [!code ++]
|
||||
>
|
||||
{(page: number) => (
|
||||
<container>
|
||||
<text text={page.toString()} />
|
||||
</container>
|
||||
)}
|
||||
</Page>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
### 第二种设置与获取当前页方式
|
||||
|
||||
相比于上一种方式,我们更推荐使用下面这种方式来设置与获取当前页。
|
||||
|
||||
可以使用 `Page` 组件提供的 `changePage` 和 `movePage` 来切换页码,其中前者是直接切换至某一页,后者是在当前页的基础上移动页码数。
|
||||
|
||||
可以使用 `now` 来获取当前页。
|
||||
|
||||
二者的示例如下:
|
||||
|
||||
:::code-group
|
||||
|
||||
```tsx [切换页码] {6-16,19-20}
|
||||
import { Page, PageExpose } from '../components'; // [!code ++]
|
||||
import { vue } from 'vue'; // [!code ++]
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
// 使用响应式变量定义 Page 引用
|
||||
const pageRef = ref<PageExpose>();
|
||||
|
||||
onMounted(() => {
|
||||
// 切换至第五页
|
||||
pageRef.value?.changePage(5);
|
||||
// 在当前页的基础上增加两页,也就是切换到第七页
|
||||
pageRef.value?.movePage(2);
|
||||
// 在当前页的基础上减少两页,也就是切换回第五页
|
||||
pageRef.value?.movePage(-2);
|
||||
});
|
||||
|
||||
return () => (
|
||||
// 将 ref 属性赋值为 pageRef 来获取其接口
|
||||
<Page loc={[0, 0, 416, 416]} pages={10} ref={pageRef}>
|
||||
{(page: number) => (
|
||||
<container>
|
||||
<text text={page.toString()} />
|
||||
</container>
|
||||
)}
|
||||
</Page>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
```tsx [获取页码] {6-12,15-16}
|
||||
import { Page, PageExpose } from '../components'; // [!code ++]
|
||||
import { vue } from 'vue'; // [!code ++]
|
||||
|
||||
// 不再展示完整 UI 模板,只展示核心部分
|
||||
export const MyCom = defineComponent(() => {
|
||||
// 使用响应式变量定义 Page 引用
|
||||
const pageRef = ref<PageExpose>();
|
||||
|
||||
onMounted(() => {
|
||||
const page = pageRef.value?.now();
|
||||
core.drawTip(`当前是第${page}页!`);
|
||||
});
|
||||
|
||||
return () => (
|
||||
// 将 ref 属性赋值为 pageRef 来获取其接口
|
||||
<Page loc={[0, 0, 416, 416]} pages={10} ref={pageRef}>
|
||||
{(page: number) => (
|
||||
<container>
|
||||
<text text={page.toString()} />
|
||||
</container>
|
||||
)}
|
||||
</Page>
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## 更多组件
|
||||
|
||||
本文只简单讲解了部分常用的组件,样板还有很多内置的组件。以下是所有内置组件的 API 参考:
|
||||
|
||||
- [ConfirmBox](../../api/user-client-modules/组件%20ConfirmBox.md):确认框,一般使用 `getConfirm` 接口,不直接使用组件。
|
||||
- [Choices](../../api/user-client-modules/组件%20Choices.md):选择框,一般使用 `getChoice` 接口,不直接使用组件。
|
||||
- [FloorSelector](../../api/user-client-modules/组件%20FloorSelector.md):楼层选择组件,浏览地图左侧的楼层选择就是使用的本组件。
|
||||
- [图标组件](../../api/user-client-modules/图标组件.md):一些常用图标。
|
||||
- [Input](../../api/user-client-modules/组件%20Input.md):输入组件,可以放到组件内部,可以用于搜索栏等。
|
||||
- [InputBox](../../api/user-client-modules/组件%20InputBox.md):输入框组件,类似于确认框,一般使用 `getInput` 或 `getInputNumber` 接口,不使用本组件。
|
||||
- [List](../../api/user-client-modules/组件%20List.md):列表组件,可以用于展示一列内容。
|
||||
- [ListPage](../../api/user-client-modules/组件%20ListPage.md):左侧是列表,右侧是当前选项对应的详情页,可以用于游戏机制说明等。
|
||||
- [Progress](../../api/user-client-modules/组件%20Progress.md):进度条组件,播放录像时右下角的进度条就是本组件。
|
||||
- [Arrow](../../api/user-client-modules/组件%20Arrow.md):箭头组件,画一个箭头。
|
||||
- [ScrollText](../../api/user-client-modules/组件%20ScrollText.md):滚动文本组件,可以用于长剧情或是 staff 表等。
|
||||
- [Selection](../../api/user-client-modules/组件%20Selection.md):选择光标,列表组件的选择光标就是使用的本组件。
|
||||
- [Background](../../api/user-client-modules/组件%20Background.md):背景组件,可以设置为纯色或 `winskin`。
|
||||
- [WaitBox](../../api/user-client-modules/组件%20WaitBox.md):等待框,一般使用 `waitbox` 接口,不直接使用组件。
|
||||
- [Page](../../api/user-client-modules/组件%20Page.md):分页组件,本文已经详细讲解。
|
||||
- [Scroll](../../api/user-client-modules/组件%20Scroll.md):滚动条组件,本文已经详细讲解。
|
||||
- [TextContent](../../api/user-client-modules/组件%20TextContent.md):多行文本组件,本文已经详细讲解。
|
||||
- [Textbox](../../api/user-client-modules/组件%20Textbox.md):文本框组件,就是事件的显示文字,一般不会直接用。
|
||||
- [Thumbnail](../../api/user-client-modules/组件%20Thumbnail.md):缩略图组件,用于展示某个地图的缩略图。
|
||||
- [Tip](../../api/user-client-modules/组件%20Tip.md):提示组件,就是左上角的提示,一般不会直接使用。
|
@ -349,7 +349,7 @@ type RenderFn = (canvas: MotaOffscreenCanvas2D, transform: Transform) => void;
|
||||
- `canvas`: 要渲染至的画布,一般直接将内容渲染至这个画布上
|
||||
- `transform`: 当前元素的变换矩阵,相对于父元素,不常用
|
||||
|
||||
多数情况下,我们只会使用到第一个参数,`MotaOffscreenCanvas2D` 接口请参考 [API 文档](../api/motajs-render-core/index.md)。下面是一个典型案例:
|
||||
多数情况下,我们只会使用到第一个参数,`MotaOffscreenCanvas2D` 接口请参考 [API 文档](../../api/motajs-render-core/index.md)。下面是一个典型案例:
|
||||
|
||||
```tsx
|
||||
const render = (canvas: MotaOffscreenCanvas2D) => {
|
||||
@ -753,4 +753,4 @@ const themeStyle = {
|
||||
|
||||
## API 参考
|
||||
|
||||
参考[API 文档](../api/motajs-render-vue/index.md),这里有更细致的 API 介绍。
|
||||
参考[API 文档](../../api/motajs-render-vue/index.md),这里有更细致的 API 介绍。
|
@ -31,7 +31,7 @@ watch(data, () => mySprite.value?.update());
|
||||
|
||||
## 我的 UI 很卡
|
||||
|
||||
可能使用了平铺式布局,建议使用 `Scroll` 组件或者 `Page` 组件来对平铺内容分割,从而提高渲染效率。可以参考对应的 [API 文档](../api/user-client-modules/组件%20Scroll.md)。
|
||||
可能使用了平铺式布局,建议使用 `Scroll` 组件或者 `Page` 组件来对平铺内容分割,从而提高渲染效率。可以参考对应的 [API 文档](../../api/user-client-modules/组件%20Scroll.md)。
|
||||
|
||||
## 玩着玩着突然黑屏了一下,然后画面就不显示了
|
||||
|
17
docs/guide/ui/index.md
Normal file
17
docs/guide/ui/index.md
Normal file
@ -0,0 +1,17 @@
|
||||
# UI 系统指南
|
||||
|
||||
2.B 提供了强大的 UI 系统,可以让你更快地做出更好看的 UI。
|
||||
|
||||
## 热重载
|
||||
|
||||
2.B 对 UI 有热重载支持,当你修改了代码时,你可以不刷新游戏画面就看到 UI 的变化,可以省去大量时间。
|
||||
|
||||
## 指南目录
|
||||
|
||||
- [UI 编写](./ui.md):教你如何从头开始编写一个 UI,包括界面显示、交互等。
|
||||
- [UI 元素](./elements.md):讲述所有常用的 UI 元素(标签),包括图片、图形、文字等。
|
||||
- [组件使用指南](./component.md):教你如何使用一些常用组件。
|
||||
- [优化性能](./perf.md):教你如何优化一个 UI 的性能表现。
|
||||
- [UI 系统](./system.md):解释 UI 系统中 UI 控制器的工作原理,重点在于 UI 的打开与关闭。
|
||||
- [常见问题](./faq.md):编写 UI 时的常见问题解答。
|
||||
- [未来规划](./future.md):UI 系统的未来规划。
|
@ -45,7 +45,7 @@ lang: zh-CN
|
||||
|
||||
## 使用 `Scroll` 或 `Page` 组件优化平铺性能
|
||||
|
||||
在一些特殊情况下,我们不得不使用平铺布局,例如上一节提到的怪物手册,或是展示一个列表等,这时候必须平铺元素。这时候我们可以使用 `Scroll` 组件或 `Page` 组件来优化性能表现。`Scroll` 组件中,只有在画面内的元素会被渲染,而画面外的不会被渲染,这会大大提高渲染效率;`Page` 组件允许你把列表拆分成多个部分,然后把内容放在不同页中,从而提高渲染性能。极端情况下,`Page` 组件的渲染效率要明显高于 `Scroll` 组件,但是滚动条对于交互更友好,我们推荐在简单场景下使用 `Scroll` 组件,而对于复杂场景,换为 `Page` 组件。两个组件的使用方式可以参考 [API 文档](../api/motajs-render-elements/)。
|
||||
在一些特殊情况下,我们不得不使用平铺布局,例如上一节提到的怪物手册,或是展示一个列表等,这时候必须平铺元素。这时候我们可以使用 `Scroll` 组件或 `Page` 组件来优化性能表现。`Scroll` 组件中,只有在画面内的元素会被渲染,而画面外的不会被渲染,这会大大提高渲染效率;`Page` 组件允许你把列表拆分成多个部分,然后把内容放在不同页中,从而提高渲染性能。极端情况下,`Page` 组件的渲染效率要明显高于 `Scroll` 组件,但是滚动条对于交互更友好,我们推荐在简单场景下使用 `Scroll` 组件,而对于复杂场景,换为 `Page` 组件。两个组件的使用方式可以参考 [API 文档](../../api/motajs-render-elements/)。
|
||||
|
||||
我们建议:
|
||||
|
@ -3,7 +3,52 @@
|
||||
本节将会讲解 2.B 的渲染树与 UI 系统的工作原理,以及一些常用 API。
|
||||
|
||||
:::info
|
||||
**这部分可以选择性阅读,多数功能一般场景下用不到。**
|
||||
**这部分可以选择性阅读,只有打开和关闭较为重要,其他功能一般场景下用不到。**
|
||||
:::
|
||||
|
||||
## 打开与关闭 UI
|
||||
|
||||
在 UI 编写章节已经提到了打开和关闭 UI 使用 `open` 和 `close` 方法,现在我们更细致地讲解一下如何打开与关闭 UI。打开 UI 使用 `open` 方法,定义如下:
|
||||
|
||||
```ts
|
||||
function open<T extends UIComponent>(
|
||||
ui: IGameUI<T>,
|
||||
props: UIProps<T>,
|
||||
alwaysShow?: boolean
|
||||
): IUIInstance;
|
||||
```
|
||||
|
||||
其中第一个参数表示要打开的 UI,第二个表示传给 UI 的参数,第三个表示 UI 是否永远保持显示状态(除非被关闭),不受到显示模式的影响。同种 UI 可以打开多个,也可以在不同的控制器上同时打开多个相同的 UI。例如,如果我们想在主 UI 控制器中添加一个常量的返回游戏按钮,就可以这么写:
|
||||
|
||||
```ts
|
||||
// BackToGame 是自定义 UI,第三个参数传 true 来保证它一直显示在画面上
|
||||
mainUIController.open(BackToGame, {}, true);
|
||||
```
|
||||
|
||||
关闭 UI 使用 `close` 方法,传入 UI 实例,即 `open` 方法的返回值,没有其他参数。例如:
|
||||
|
||||
```ts
|
||||
const MyUI = defineComponent(props => {
|
||||
// 所有通过 UI 控制器打开的,同时按照 UI 模板填写了 props 的 UI 都包含 controller 和 instance 属性
|
||||
props.controller.close(props.instance);
|
||||
}, myUIProps);
|
||||
```
|
||||
|
||||
除此之外,还提供了一个关闭所有 UI 的:
|
||||
|
||||
```ts
|
||||
function closeAll(ui?: IGameUI): void;
|
||||
```
|
||||
|
||||
其中参数表示要关闭的 UI 类型,不填时表示关闭所有 UI,填写时表示关闭所有指定类型的 UI。例如我想关闭所有 `EnemyInfo` UI,可以这么写:
|
||||
|
||||
```ts
|
||||
// EnemyInfo 是自定义 UI
|
||||
mainUIController.closeAll(EnemyInfo);
|
||||
```
|
||||
|
||||
:::warning
|
||||
以下内容属于进阶内容,没有高级需求不需要理解。
|
||||
:::
|
||||
|
||||
## 创建一个自己的 UI 管理器
|
||||
@ -149,47 +194,6 @@ keep.safelyUnload();
|
||||
keep.unload();
|
||||
```
|
||||
|
||||
## 打开与关闭 UI
|
||||
|
||||
在 UI 编写章节已经提到了打开和关闭 UI 使用 `open` 和 `close` 方法,现在我们更细致地讲解一下如何打开与关闭 UI。打开 UI 使用 `open` 方法,定义如下:
|
||||
|
||||
```ts
|
||||
function open<T extends UIComponent>(
|
||||
ui: IGameUI<T>,
|
||||
props: UIProps<T>,
|
||||
alwaysShow?: boolean
|
||||
): IUIInstance;
|
||||
```
|
||||
|
||||
其中第一个参数表示要打开的 UI,第二个表示传给 UI 的参数,第三个表示 UI 是否永远保持显示状态(除非被关闭),不受到显示模式的影响。同种 UI 可以打开多个,也可以在不同的控制器上同时打开多个相同的 UI。例如,如果我们想在主 UI 控制器中添加一个常量的返回游戏按钮,就可以这么写:
|
||||
|
||||
```ts
|
||||
// BackToGame 是自定义 UI,第三个参数传 true 来保证它一直显示在画面上
|
||||
myController.open(BackToGame, {}, true);
|
||||
```
|
||||
|
||||
关闭 UI 使用 `close` 方法,传入 UI 实例,即 `open` 方法的返回值,没有其他参数。例如:
|
||||
|
||||
```ts
|
||||
const MyUI = defineComponent(props => {
|
||||
// 所有通过 UI 控制器打开的,同时按照 UI 模板填写了 props 的 UI 都包含 controller 和 instance 属性
|
||||
props.controller.close(props.instance);
|
||||
}, myUIProps);
|
||||
```
|
||||
|
||||
除此之外,还提供了一个关闭所有 UI 的:
|
||||
|
||||
```ts
|
||||
function closeAll(ui?: IGameUI): void;
|
||||
```
|
||||
|
||||
其中参数表示要关闭的 UI 类型,不填时表示关闭所有 UI,填写时表示关闭所有指定类型的 UI。例如我想关闭所有 `EnemyInfo` UI,可以这么写:
|
||||
|
||||
```ts
|
||||
// EnemyInfo 是自定义 UI
|
||||
myController.closeAll(EnemyInfo);
|
||||
```
|
||||
|
||||
## 渲染系统的树结构
|
||||
|
||||
接下来我们来讲解一下渲染系统的一些工作原理。下面的部分由 `DeepSeek R1` 模型生成并稍作修改。
|
@ -58,7 +58,7 @@ return () => (
|
||||
|
||||
## 显示 UI
|
||||
|
||||
我们编写完 UI 之后,这个 UI 并不会自己显示,需要手动打开。我们找到 `ui/main.tsx`,在 `MainScene` 这个根组件中添加一句话:
|
||||
我们编写完 UI 之后,这个 UI 并不会自己显示,需要手动打开。我们找到 `ui/main.tsx`,在 `MainScene` 这个根组件中调用 `mainUIController.open`:
|
||||
|
||||
```ts
|
||||
// 在这添加引入
|
||||
@ -68,7 +68,7 @@ const MainScene = defineComponent(() => {
|
||||
// ... 其他内容
|
||||
// 在这添加一句话,打开 UI,第二个参数为传入 UI 的参数,后面会有讲解
|
||||
// 纵深设为 100 以保证可以显示出来,纵深越大,元素越靠上,会覆盖纵深低的元素
|
||||
mainUIController.open(MyBookUI, { zIndex: 100 });
|
||||
mainUIController.open(MyBookUI, { zIndex: 100 }); // [!code ++]
|
||||
return () => (
|
||||
// ... 其他内容
|
||||
);
|
||||
@ -80,7 +80,7 @@ const MainScene = defineComponent(() => {
|
||||
```tsx
|
||||
export const MyBook = defineComponent<MyBookProps>(props => {
|
||||
// 例如,我们可以让它在打开 10 秒钟后关闭:
|
||||
setTimeout(() => props.controller.close(props.instance), 10000);
|
||||
setTimeout(() => props.controller.close(props.instance), 10000); // [!code ++]
|
||||
return () => (
|
||||
// ... UI 内容
|
||||
);
|
||||
@ -119,7 +119,9 @@ import { UIController } from '@motajs/system-ui';
|
||||
const mainUIController = UIController.getController('main-ui');
|
||||
```
|
||||
|
||||
更多的 UI 控制功能可以参考后续文档以及相关的 [UI 系统指南](./ui-system.md) 或 [API 文档](../api/motajs-system-ui/UIController)。
|
||||
关于 UI 打开与关闭的细节参考[此文档](./system.md#打开与关闭-ui)
|
||||
|
||||
更多的 UI 控制功能可以参考后续文档以及相关的 [UI 系统指南](./system.md) 或 [API 文档](../../api/motajs-system-ui/UIController)。
|
||||
|
||||
## 添加更多内容
|
||||
|
||||
@ -169,7 +171,7 @@ return () => (
|
||||
);
|
||||
```
|
||||
|
||||
更多的字体使用方法可以参考 [API 文档](../api/motajs-render-style/Font)
|
||||
更多的字体使用方法可以参考 [API 文档](../../api/motajs-render-style/Font)
|
||||
|
||||
### 圆角矩形
|
||||
|
||||
@ -820,7 +822,7 @@ watch(selected, () => {
|
||||
|
||||
## 修改 UI 参数
|
||||
|
||||
在打开 UI 时,我们可以传入参数,默认情况下,可以传入所有的 `BaseProps`,也就是所有元素通用属性,以及自己定义的 UI 参数。`BaseProps` 内容较多,可以参考 [API 文档](../api/motajs-render-core/RenderItem.md)。除此之外,我们还为这个自定义怪物手册添加了 `floorId` 参数,它也可以在打开 UI 时传入。如果需要打开的 UI 参数具有响应式,例如可以动态修改楼层 id,可以使用 `reactive` 方法。示例如下:
|
||||
在打开 UI 时,我们可以传入参数,默认情况下,可以传入所有的 `BaseProps`,也就是所有元素通用属性,以及自己定义的 UI 参数。`BaseProps` 内容较多,可以参考 [API 文档](../../api/motajs-render-core/RenderItem.md)。除此之外,我们还为这个自定义怪物手册添加了 `floorId` 参数,它也可以在打开 UI 时传入。如果需要打开的 UI 参数具有响应式,例如可以动态修改楼层 id,可以使用 `reactive` 方法。示例如下:
|
||||
|
||||
```ts
|
||||
import { MyBookProps, MyBookUI } from './myUI';
|
@ -1,4 +1,5 @@
|
||||
export * from './choices';
|
||||
export * from './floorSelect';
|
||||
export * from './icons';
|
||||
export * from './input';
|
||||
export * from './list';
|
||||
|
@ -517,4 +517,12 @@ export async function getInputNumber(
|
||||
return parseFloat(value);
|
||||
}
|
||||
|
||||
export async function routedInput() {
|
||||
// todo
|
||||
}
|
||||
|
||||
export async function routedInputNumber() {
|
||||
// todo
|
||||
}
|
||||
|
||||
export const InputBoxUI = new GameUI('input-box', InputBox);
|
||||
|
@ -230,12 +230,13 @@ export const Page = defineComponent<
|
||||
<container loc={contentLoc.value}>
|
||||
{slots.default?.(nowPage.value)}
|
||||
</container>
|
||||
<container loc={pageLoc.value} hidden={hide.value}>
|
||||
<container loc={pageLoc.value} hidden={hide.value} nocache>
|
||||
<container
|
||||
key={1}
|
||||
loc={leftLoc.value}
|
||||
onClick={lastPage}
|
||||
cursor="pointer"
|
||||
nocache
|
||||
>
|
||||
<g-rectr
|
||||
loc={rectLoc.value}
|
||||
@ -257,6 +258,7 @@ export const Page = defineComponent<
|
||||
loc={leftPageLoc.value}
|
||||
onClick={lastPage}
|
||||
cursor="pointer"
|
||||
nocache
|
||||
>
|
||||
<g-rectr
|
||||
loc={rectLoc.value}
|
||||
@ -272,7 +274,7 @@ export const Page = defineComponent<
|
||||
></text>
|
||||
</container>
|
||||
)}
|
||||
<container loc={nowPageLoc.value} key={3}>
|
||||
<container loc={nowPageLoc.value} key={3} nocache>
|
||||
<g-rectr
|
||||
loc={rectLoc.value}
|
||||
circle={[round.value]}
|
||||
@ -295,6 +297,7 @@ export const Page = defineComponent<
|
||||
loc={rightPageLoc.value}
|
||||
onClick={nextPage}
|
||||
cursor="pointer"
|
||||
nocache
|
||||
>
|
||||
<g-rectr
|
||||
loc={rectLoc.value}
|
||||
@ -315,6 +318,7 @@ export const Page = defineComponent<
|
||||
loc={rightLoc.value}
|
||||
onClick={nextPage}
|
||||
cursor="pointer"
|
||||
nocache
|
||||
>
|
||||
<g-rectr
|
||||
loc={rectLoc.value}
|
||||
|
Loading…
Reference in New Issue
Block a user