particle-modifier
Cocos Creator 2.4.xで、粒子の位置や色、速度などを細かく調整し、複雑な表現を可能にするカスタム粒子修飾器を開発・デバッグするSkill。
📜 元の英語説明(参考)
Cocos Creator 2.4.x 粒子系统修饰器开发框架。用于创建、使用和调试自定义粒子修饰器,支持修改粒子位置、颜色、大小、旋转、速度等属性。当需要在 Cocos Creator 中实现复杂的粒子效果控制时使用此技能。
🇯🇵 日本人クリエイター向け解説
Cocos Creator 2.4.xで、粒子の位置や色、速度などを細かく調整し、複雑な表現を可能にするカスタム粒子修飾器を開発・デバッグするSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-17
- 取得日時
- 2026-05-17
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
[Skill 名] particle-modifier
粒子修飾器システム開発ガイド
概要
このスキルは、Cocos Creator 2.4.x 粒子システムのカスタム修飾器開発フレームワークを提供します。修飾器クラスを記述することで、各粒子の挙動を正確に制御し、複雑な視覚効果を実現できます。
コアファイル構造
プロジェクトルートディレクトリ/
├── ParticleModifier.ts # 粒子修飾器接着剤コンポーネント(粒子システム更新をインターセプト)
├── ParticleModifierBase.ts # 修飾器基底クラス(フックメソッドを提供)
├── SKILL.md # このスキルに関するドキュメント
├── js/ # エンジンコアソースコード(Cocos Creator 2.4.13)
│ ├── CCParticleAsset.js # 粒子リソースクラス
│ ├── CCParticleSystem.js # 粒子システムコンポーネント(メインコンポーネント)
│ ├── particle-simulator.js # 粒子シミュレーター(コアロジック)
│ └── particle-system-assembler.js # レンダリングアセンブラー
└── examples/
├── ColorFadeModifier.ts # 色フェード修飾器の例
├── GravityModifier.ts # 重力修飾器の例
└── LeafRotationModifier.ts # 葉の回転修飾器の例
クイックスタート
ステップ 1:コアファイルのコピー
ParticleModifier.ts と ParticleModifierBase.ts をプロジェクトの任意のディレクトリ(assets/scripts/ 下に置くことを推奨します)にコピーします。
ステップ 2:カスタム修飾器の作成
ParticleModifierBase を継承する新しいクラスを作成し、onParticleUpdate メソッドを実装します。
ステップ 3:エディターでの設定
- 粒子システムノードに
ParticleModifierコンポーネントを追加します。 - カスタム修飾器コンポーネントを追加します。
- パラメータを設定して実行します。
修飾器開発テンプレート
基本テンプレート
import { IParticle } from "./ParticleModifier";
import ParticleModifierBase from "./ParticleModifierBase";
const { ccclass, property } = cc._decorator;
@ccclass
export class MyCustomModifier extends ParticleModifierBase {
@property({ tooltip: '実行優先度(数値が小さいほど先に実行されます)' })
priority: number = 0;
@property({ tooltip: 'プロパティの説明' })
myProperty: number = 1.0;
onParticleEmit(particle: IParticle, system: cc.ParticleSystem): void {
// 粒子が放出されるときに呼び出されます(オプション)
// 粒子のカスタムデータを初期化します
}
onParticleUpdate(particle: IParticle, dt: number, system: cc.ParticleSystem): void {
// 粒子が毎フレーム更新されるときに呼び出されます(必須)
// 粒子の状態を更新します
}
}
IParticle インターフェース
interface IParticle {
// 位置
pos: cc.Vec2; // 現在の位置(エミッターに対する相対位置)
startPos: cc.Vec2; // 開始位置
drawPos: cc.Vec2; // 描画位置
// 色
color: cc.Color; // 現在の色
deltaColor: { r, g, b, a }; // 色の変化率
preciseColor: { r, g, b, a }; // 正確な色(浮動小数点)
// サイズ
size: number; // 現在のサイズ
deltaSize: number; // サイズの変化率
aspectRatio: number; // アスペクト比
// 回転
rotation: number; // 現在の回転角度(度)
deltaRotation: number; // 回転変化率(度/秒)
// ライフサイクル
timeToLive: number; // 残りのライフサイクル(秒)
// Mode A: 重力モード
dir: cc.Vec2; // 速度ベクトル
radialAccel: number; // 径方向加速度
tangentialAccel: number; // 接線方向加速度
// Mode B: 半径モード
angle: number; // 現在の角度(ラジアン)
degreesPerSecond: number; // 角速度
radius: number; // 現在の半径
deltaRadius: number; // 半径変化率
}
注意:IParticle インターフェースはカスタムデータを格納するために拡張できますが、onParticleEmit で初期化する必要があります。
技術原理
粒子修飾器のインターセプトメカニズム
粒子修飾器システムは、以下の方法で粒子の更新をインターセプトします。
-
粒子システム参照の取得
const simulator = (system as any)._simulator; -
元の関数の保存
this._originalEmitParticle = simulator.emitParticle; this._originalStep = simulator.step; -
主要関数のオーバーライド
simulator.emitParticle = (pos: cc.Vec2) => { this._originalEmitParticle.call(simulator, pos); this._onParticleEmit(particle); }; simulator.step = (dt: number) => { this._originalStep.call(simulator, dt); this._onParticleUpdate(particle, dt); };
aspectRatio 処理ロジック
エンジン下層の updateParticleBuffer 関数(js/particle-simulator.js:257):
let aspectRatio = particle.aspectRatio;
aspectRatio > 1 ? (height = width / aspectRatio) : (width = height * aspectRatio);
これが長方形画像の回転ジャンプの根本原因です!aspectRatio が >1 から <1 に変化すると、エンジンはアンカーポイントを切り替えます。
よくある修飾器パターン
1. 位置の変更
onParticleUpdate(particle: IParticle, dt: number, system: cc.ParticleSystem): void {
// X軸の揺れ
particle.pos.x += Math.sin(Date.now() / 1000) * 10 * dt;
}
2. 色のグラデーション
// まず拡張インターフェースを定義する必要があります
interface IColorFadeOptions extends IParticle {
maxTimeToLive: number; // 初期ライフサイクルを記録
}
onParticleEmit(particle: IColorFadeOptions, system: cc.ParticleSystem): void {
particle.maxTimeToLive = particle.timeToLive;
}
onParticleUpdate(particle: IColorFadeOptions, dt: number, system: cc.ParticleSystem): void {
const lifeRatio = 1 - (particle.timeToLive / particle.maxTimeToLive);
particle.color.r = Math.floor(255 * lifeRatio);
particle.color.g = Math.floor(255 * (1 - lifeRatio));
}
3. サイズの呼吸効果
// 粒子のライフサイクルに基づいて呼吸効果を計算
interface IBreathingSizeOptions extends IParticle {
maxTimeToLive: number; // 初期ライフサイクルを記録
baseSize: number; // 初期サイズを記録
}
onParticleEmit(particle: IBreathingSizeOptions, system: cc.ParticleSystem): void {
particle.maxTimeToLive = particle.timeToLive;
particle.baseSize = particle.size;
}
onParticleUpdate(particle: IBreathingSizeOptions, dt: number, system: cc.ParticleSystem): void {
const lifeRatio = 1 - (particle.timeToLive / particle.maxTimeToLive);
// ライフサイクルに基づく呼吸効果、各粒子は独立した位相を持ちます
particle.size = particle.baseSize + Math.sin(lifeRatio * Math.PI * 4) * 20;
}
4. 3D 回転(重要)
⚠️ 重要:aspectRatio のジャンプ問題
長方形の画像を回転させると視覚的なジャンプが発生します。これは、エンジン下層がアンカーポイントを強制的に切り替えるためです。
aspectRatio > 1:幅がparticle.sizeに固定されます。aspectRatio < 1:高さがparticle.sizeに固定されます。
解決策:長方形の画像(AR > 1)は X 軸回転のみを使用します。
interface ILeafRotationOptions extends IParticle {
maxTimeToLive: number; // カスタム:初期ライフサイクルを記録
originalAspectRatio: number; // カスタム:初期アスペクト比を記録
rotationAngle: number; // カスタム:現在の回転角度
rotationSpeed: number; // カスタム:回転速度
randomOffset: number; // カスタム:ランダムオフセット
}
@ccclass
export class LeafRotationModifier extends ParticleModifierBase {
@property({ tooltip: '最小回転速度(周/秒)' })
minRotationSpeed: number = 0.5;
@property({ tooltip: '最大回転速度(周/秒)' })
maxRotationSpeed: number = 2.0;
@property({ tooltip: '回転軸(X=上下反転、Y=左右反転)' })
rotationAxis: 'X' | 'Y' = 'X';
onParticleEmit(particle: ILeafRotationOptions, system: cc.ParticleSystem): void {
// ⚠️ 重要:カスタムデータは onParticleEmit で初期化する必要があります
particle.maxTimeToLive = par 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
粒子修饰器系统开发指南
概述
本技能提供 Cocos Creator 2.4.x 粒子系统的自定义修饰器开发框架。通过编写修饰器类,可以精确控制每个粒子的行为,实现复杂的视觉效果。
核心文件结构
项目根目录/
├── ParticleModifier.ts # 粒子修饰器胶水组件(拦截粒子系统更新)
├── ParticleModifierBase.ts # 修饰器基类(提供钩子方法)
├── SKILL.md # 本技能文档
├── js/ # 引擎核心源码(Cocos Creator 2.4.13)
│ ├── CCParticleAsset.js # 粒子资源类
│ ├── CCParticleSystem.js # 粒子系统组件(主组件)
│ ├── particle-simulator.js # 粒子模拟器(核心逻辑)
│ └── particle-system-assembler.js # 渲染汇编器
└── examples/
├── ColorFadeModifier.ts # 颜色渐变修饰器示例
├── GravityModifier.ts # 重力修饰器示例
└── LeafRotationModifier.ts # 叶子旋转修饰器示例
快速开始
步骤 1:复制核心文件
将 ParticleModifier.ts 和 ParticleModifierBase.ts 复制到项目的任意目录(建议放在 assets/scripts/ 下)
步骤 2:创建自定义修饰器
创建继承自 ParticleModifierBase 的新类,实现 onParticleUpdate 方法
步骤 3:在编辑器中配置
- 在粒子系统节点上添加
ParticleModifier组件 - 添加自定义修饰器组件
- 配置参数并运行
修饰器开发模板
基础模板
import { IParticle } from "./ParticleModifier";
import ParticleModifierBase from "./ParticleModifierBase";
const { ccclass, property } = cc._decorator;
@ccclass
export class MyCustomModifier extends ParticleModifierBase {
@property({ tooltip: '执行优先级(数值越小越先执行)' })
priority: number = 0;
@property({ tooltip: '属性说明' })
myProperty: number = 1.0;
onParticleEmit(particle: IParticle, system: cc.ParticleSystem): void {
// 粒子发射时调用(可选)
// 初始化粒子自定义数据
}
onParticleUpdate(particle: IParticle, dt: number, system: cc.ParticleSystem): void {
// 粒子每帧更新时调用(必需)
// 更新粒子状态
}
}
IParticle 接口
interface IParticle {
// 位置
pos: cc.Vec2; // 当前位置(相对于发射器)
startPos: cc.Vec2; // 起始位置
drawPos: cc.Vec2; // 绘制位置
// 颜色
color: cc.Color; // 当前颜色
deltaColor: { r, g, b, a }; // 颜色变化率
preciseColor: { r, g, b, a }; // 精确颜色(浮点)
// 大小
size: number; // 当前大小
deltaSize: number; // 大小变化率
aspectRatio: number; // 宽高比
// 旋转
rotation: number; // 当前旋转角度(度)
deltaRotation: number; // 旋转变化率(度/秒)
// 生命周期
timeToLive: number; // 剩余生命周期(秒)
// Mode A: 重力模式
dir: cc.Vec2; // 速度向量
radialAccel: number; // 径向加速度
tangentialAccel: number; // 切向加速度
// Mode B: 半径模式
angle: number; // 当前角度(弧度)
degreesPerSecond: number; // 角速度
radius: number; // 当前半径
deltaRadius: number; // 半径变化率
}
注意:IParticle 接口可以被扩展以存储自定义数据,但必须在 onParticleEmit 中初始化。
技术原理
粒子修饰器拦截机制
粒子修饰器系统通过以下方式拦截粒子更新:
-
获取粒子系统引用
const simulator = (system as any)._simulator; -
保存原始函数
this._originalEmitParticle = simulator.emitParticle; this._originalStep = simulator.step; -
覆盖关键函数
simulator.emitParticle = (pos: cc.Vec2) => { this._originalEmitParticle.call(simulator, pos); this._onParticleEmit(particle); }; simulator.step = (dt: number) => { this._originalStep.call(simulator, dt); this._onParticleUpdate(particle, dt); };
aspectRatio 处理逻辑
引擎底层的 updateParticleBuffer 函数(js/particle-simulator.js:257):
let aspectRatio = particle.aspectRatio;
aspectRatio > 1 ? (height = width / aspectRatio) : (width = height * aspectRatio);
这就是长方形图片旋转跳变的根本原因!当 aspectRatio 从 >1 变到 <1 时,引擎会切换锚点。
常见修饰器模式
1. 位置修改
onParticleUpdate(particle: IParticle, dt: number, system: cc.ParticleSystem): void {
// X 轴摆动
particle.pos.x += Math.sin(Date.now() / 1000) * 10 * dt;
}
2. 颜色渐变
// 需要先定义扩展接口
interface IColorFadeOptions extends IParticle {
maxTimeToLive: number; // 记录初始生命周期
}
onParticleEmit(particle: IColorFadeOptions, system: cc.ParticleSystem): void {
particle.maxTimeToLive = particle.timeToLive;
}
onParticleUpdate(particle: IColorFadeOptions, dt: number, system: cc.ParticleSystem): void {
const lifeRatio = 1 - (particle.timeToLive / particle.maxTimeToLive);
particle.color.r = Math.floor(255 * lifeRatio);
particle.color.g = Math.floor(255 * (1 - lifeRatio));
}
3. 大小呼吸
// 基于粒子生命周期计算呼吸效果
interface IBreathingSizeOptions extends IParticle {
maxTimeToLive: number; // 记录初始生命周期
baseSize: number; // 记录初始大小
}
onParticleEmit(particle: IBreathingSizeOptions, system: cc.ParticleSystem): void {
particle.maxTimeToLive = particle.timeToLive;
particle.baseSize = particle.size;
}
onParticleUpdate(particle: IBreathingSizeOptions, dt: number, system: cc.ParticleSystem): void {
const lifeRatio = 1 - (particle.timeToLive / particle.maxTimeToLive);
// 基于生命周期的呼吸效果,每个粒子有独立相位
particle.size = particle.baseSize + Math.sin(lifeRatio * Math.PI * 4) * 20;
}
4. 3D 旋转(关键)
⚠️ 重要:aspectRatio 跳变问题
长方形图片旋转时会出现视觉跳变,因为引擎底层硬切换锚点:
aspectRatio > 1:宽度固定为particle.sizeaspectRatio < 1:高度固定为particle.size
解决方案:长方形图片(AR > 1)只使用 X 轴旋转
interface ILeafRotationOptions extends IParticle {
maxTimeToLive: number; // 自定义:记录初始生命周期
originalAspectRatio: number; // 自定义:记录初始宽高比
rotationAngle: number; // 自定义:当前旋转角度
rotationSpeed: number; // 自定义:旋转速度
randomOffset: number; // 自定义:随机偏移
}
@ccclass
export class LeafRotationModifier extends ParticleModifierBase {
@property({ tooltip: '最小旋转速度(圈/秒)' })
minRotationSpeed: number = 0.5;
@property({ tooltip: '最大旋转速度(圈/秒)' })
maxRotationSpeed: number = 2.0;
@property({ tooltip: '旋转轴(X=上下翻转,Y=左右翻转)' })
rotationAxis: 'X' | 'Y' = 'X';
onParticleEmit(particle: ILeafRotationOptions, system: cc.ParticleSystem): void {
// ⚠️ 重要:必须在 onParticleEmit 中初始化自定义数据
particle.maxTimeToLive = particle.timeToLive;
particle.originalAspectRatio = particle.aspectRatio || 1.0;
particle.rotationAngle = 0;
const randomSpeed = this.minRotationSpeed + Math.random() * (this.maxRotationSpeed - this.minRotationSpeed);
particle.rotationSpeed = Math.PI * 2 * randomSpeed;
particle.randomOffset = Math.random() * Math.PI * 2;
}
onParticleUpdate(particle: ILeafRotationOptions, dt: number, system: cc.ParticleSystem): void {
particle.rotationAngle += particle.rotationSpeed * dt;
const currentAngle = particle.rotationAngle + particle.randomOffset;
const cosValue = Math.abs(Math.cos(currentAngle));
const safeCos = Math.max(0.01, cosValue);
if (this.rotationAxis === 'X') {
// X 轴旋转:宽度不变,高度缩放
particle.aspectRatio = particle.originalAspectRatio / safeCos;
} else {
// Y 轴旋转:⚠️ 长方形图片会跳变
particle.aspectRatio = particle.originalAspectRatio * safeCos;
}
}
}
使用建议:
- 长方形图片(AR > 1):使用
rotationAxis = 'X' - 正方形图片(AR ≈ 1):可以使用任意轴
- 配合粒子 Z 轴旋转:只做 X 轴 3D 翻转 + 粒子
rotation属性
高级功能
访问顶点缓冲区
⚠️ 警告:此功能需要深入了解引擎顶点格式,仅用于高级场景
onParticleUpdate(particle: IParticle, dt: number, system: cc.ParticleSystem): void {
const simulator = (system as any)._simulator;
const buffer = system._assembler.getBuffer();
const vbuf = buffer._vData;
const particleIndex = simulator.particles.indexOf(particle);
// vfmtPosUvColor 格式:每顶点 8 floats (pos:2 + uv:2 + color:4),每粒子 4 顶点 = 32 floats
const FLOAT_PER_PARTICLE = 32;
const offset = particleIndex * FLOAT_PER_PARTICLE;
// 修改第一个顶点的 UV 坐标(offset + 8, offset + 9)
// 第二个顶点:offset + 16, offset + 17
// 第三个顶点:offset + 24, offset + 25
// 第四个顶点:offset + 32, offset + 33
vbuf[offset + 8] = 0.0;
vbuf[offset + 9] = 0.0;
// step 函数会自动上传数据,无需手动调用 uploadData
}
多修饰器协同
在编辑器中添加多个修饰器,按 priority 顺序执行(数值越小越先执行):
ParticleSystem
├── ParticleModifier (胶水组件,自动收集并排序子修饰器)
├── GravityModifier (priority: 0) # 先应用重力
├── LeafRotationModifier (priority: 1) # 再应用 3D 旋转
└── ColorFadeModifier (priority: 2) # 最后应用颜色渐变
执行顺序影响:
- 如果先应用颜色渐变,再应用 3D 旋转,旋转不会影响颜色
- 优先级决定了修饰器的应用顺序,可能影响最终效果
调试技巧
查看粒子系统状态
⚠️ 性能警告:以下调试方法会产生大量日志,仅在开发环境使用,生产环境务必移除
onParticleUpdate(particle: IParticle, dt: number, system: cc.ParticleSystem): void {
// 仅在每 100 帧输出一次,避免日志爆炸
if (Date.now() % 100 < 16) { // 约 6fps
const simulator = (system as any)._simulator;
console.log('粒子数量:', simulator.particles.length);
console.log('激活状态:', simulator.active);
}
}
监控 aspectRatio
if (particle.aspectRatio > 1.1 || particle.aspectRatio < 0.9) {
console.log('aspectRatio 异常:', particle.aspectRatio);
}
性能分析
const startTime = Date.now();
// ... 修饰器逻辑
const endTime = Date.now();
if (endTime - startTime > 1) {
console.warn('执行时间过长:', endTime - startTime, 'ms');
}
质量校验清单
在创建修饰器时,请确保满足以下标准:
- [ ] 性能检查:避免在
onParticleUpdate中创建新对象 - [ ] 初始化检查:粒子自定义数据在
onParticleEmit中初始化 - [ ] 生命周期检查:不修改粒子数组,只修改单个粒子属性
- [ ] 兼容性检查:确认粒子系统模式(Gravity 或 Radius)
- [ ] aspectRatio 检查:长方形图片使用 X 轴旋转避免跳变
- [ ] priority 设置:合理设置优先级控制执行顺序
常见问题与解决方案
问题 1:修饰器未生效
检查清单:
- [ ] 是否添加了
ParticleModifier组件? - [ ] 修饰器是否已添加到粒子系统节点?
- [ ]
priority是否正确(按顺序执行)?
问题 2:性能问题
优化建议:
- 减少粒子数量(建议 < 1000)
- 简化修饰器逻辑
- 避免复杂的数学运算
问题 3:长方形图片旋转跳变
解决方案:
- 使用
rotationAxis = 'X' - 公式:
aspectRatio = originalAspectRatio / cos
问题 4:粒子间交互需求
实现方法:
- 在修饰器中维护粒子列表
- 在
onParticleUpdate中遍历计算
问题 5:自定义数据丢失
解决方案:
- 必须在
onParticleEmit中初始化自定义数据 - 使用 TypeScript 接口扩展 IParticle
参考资源
示例文件(位于本技能包的 examples/ 目录)
examples/ColorFadeModifier.ts- 颜色渐变examples/GravityModifier.ts- 重力修改examples/LeafRotationModifier.ts- 3D 旋转
注意:这些示例文件位于粒子修饰器技能包中,可参考实现方式
引擎源码(位于本技能包的 js/ 目录,供理解原理使用)
js/particle-simulator.js - 粒子模拟器
- Particle 类定义:粒子对象结构,包含位置、颜色、大小、旋转、生命周期等属性
- emitParticle 函数:发射新粒子,初始化粒子属性
- step 函数:每帧更新所有粒子,包括发射、更新、回收
- updateParticleBuffer 函数:更新顶点缓冲区,包含 aspectRatio 处理的关键逻辑(根据 aspectRatio 切换宽高锚点)
- 对象池:粒子对象池管理,避免频繁创建销毁
js/CCParticleSystem.js - 粒子系统组件
- 属性定义:粒子系统所有可配置属性(totalParticles、duration、emissionRate、life、startColor、endColor、gravity、speed 等)
- _simulator 初始化:创建粒子模拟器实例
- lateUpdate 函数:每帧调用模拟器的 step 方法
- emitterMode:GRAVITY(重力模式)和 RADIUS(半径模式)
- positionType:FREE(自由模式)、RELATIVE(相对模式)、GROUPED(整组模式)
js/particle-system-assembler.js - 渲染汇编器
- getBuffer 函数:获取顶点缓冲区(QuadBuffer)
- fillBuffers 函数:提交渲染数据到 GPU
- 顶点格式:vfmtPosUvColor(位置 + UV + 颜色)
- 每粒子顶点数:4 个顶点,6 个索引(2 个三角形)
js/CCParticleAsset.js - 粒子资源
- spriteFrame 属性:粒子贴图资源
- 支持格式:plist 格式的粒子配置文件
注意:这些是 Cocos Creator 引擎源码,位于技能包中供理解原理使用
最佳实践
- 优先使用 X 轴旋转:长方形图片避免跳变
- 避免对象创建:在
onParticleUpdate中不创建新对象 - 合理控制粒子数:建议 < 1000 个粒子
- 使用 priority 控制顺序:修饰器按
priority从小到大执行 - 在 onParticleEmit 初始化:粒子自定义数据在发射时初始化
- 扩展 IParticle 接口:使用 TypeScript 接口扩展自定义数据类型