msw-combat-system

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

msw-combat-system

msw-combat-system

MSW 전투 파이프라인 전체. 2D 장르 불문 공통 전투 레이어 중 MSW 네이티브 API 지원 항목만 정리. 수식·이론 제외. 전부
default-local-workspace/Environment/NativeScripts/**/*.d.mlua
원본 재검증 완료 (2026-04-21).
의심/예외는
docs/engine-source-index.md
캐시 먼저 확인.

MSW完整战斗流水线。仅整理所有2D品类通用战斗层中MSW原生API支持的内容,不包含公式与理论。所有内容均已通过
default-local-workspace/Environment/NativeScripts/**/*.d.mlua
原文件重新验证(2026-04-21)。
如有疑问或例外情况,请先查看
docs/engine-source-index.md
缓存。

0. 커버리지 매트릭스

0. 覆盖范围矩阵

#레이어네이티브커스텀 필요
1Attack Resolution
AttackComponent
+
HitComponent
(Box/Circle/Polygon)
Capsule/Cone/Ray, 관통 카운트
2Damage Model
CalcDamage
/
CalcCritical
/
GetCriticalDamageRate
/
GetDisplayHitCount
훅 +
HitEvent.Extra:any
속성 상성, 복합 공식
3Hit ReactionBody별 넉백 API,
IsHitTarget
기반 i-frame
경직 레벨, 상태이상
4Game Feel6개 전부 네이티브 (Hit Stop, Shake, Zoom, Flash, VFX, SFX)
5Combat State
StateComponent
+
DeadEvent
/
ReviveEvent
,
PlayerComponent
HP/부활
MP/Stamina/Rage, 어그로
6Event Bus
HitEvent
/
AttackEvent
/
StateChangeEvent
/
PlayerActionEvent
+ 커스텀
@Event
OnKill/OnBlocked
7AI
StateComponent
(FSM) +
AIComponent
(BT, Composite 4종 네이티브) +
AIChaseComponent
/
AIWanderComponent
,
_UserService.UserEntities
Decorator/Memory(Blackboard), Threat Table
+Damage Skin
DamageSkin*
3종 +
DamageSkinService
+Hit Effect
HitEffectSpawnerComponent
(auto)
+Avatar Motion
AvatarStateAnimationComponent
(State→MapleAvatarBodyActionState)

#层级原生支持需自定义
1攻击判定(Attack Resolution)
AttackComponent
+
HitComponent
(Box/Circle/Polygon)
Capsule/Cone/Ray、穿透计数
2伤害模型(Damage Model)
CalcDamage
/
CalcCritical
/
GetCriticalDamageRate
/
GetDisplayHitCount
钩子 +
HitEvent.Extra:any
属性克制、复合公式
3受击反应(Hit Reaction)按部位击退API、基于
IsHitTarget
的无敌帧
僵直等级、异常状态
4游戏手感(Game Feel)6项全部原生支持(Hit Stop、震动、缩放、闪屏、VFX、SFX)
5战斗状态(Combat State)
StateComponent
+
DeadEvent
/
ReviveEvent
PlayerComponent
HP/复活
MP/耐力/怒气、仇恨值
6事件总线(Event Bus)
HitEvent
/
AttackEvent
/
StateChangeEvent
/
PlayerActionEvent
+ 自定义
@Event
OnKill/OnBlocked
7AI
StateComponent
(FSM) +
AIComponent
(BT、4种原生复合节点) +
AIChaseComponent
/
AIWanderComponent
_UserService.UserEntities
Decorator/记忆(Blackboard)、威胁表
+伤害皮肤(Damage Skin)
DamageSkin*
3种 +
DamageSkinService
+击中特效(Hit Effect)
HitEffectSpawnerComponent
(自动触发)
+角色动作(Avatar Motion)
AvatarStateAnimationComponent
(State→MapleAvatarBodyActionState)

0.5 References — 어디로 가야 하나

0.5 参考文档 — 去哪里查找

본 SKILL.md는 시스템 흐름과 네이티브 API 표면만 다룬다. 실제 모델 JSON·스크립트 전체 코드·변형 패턴은 아래 references/* 에서 직접 Read한다.
파일다루는 범위언제 읽나
references/monster-setup.md
몬스터
.model
컴포넌트 조립 + ActionSheet + AI 선택 + MonsterAI 부착
전투 가능한 몬스터 만들 때
references/hp-gauge.md
PixelRendererComponent
기반 머리 위 체력바 전체 구현
머리 위 HP 바 붙일 때
references/projectile.md
투사체 (Body 없는 엔티티 +
OnUpdate Translate
) + 추적/관통/스플래시 변형
화살·총알·마법탄 등 원거리 공격 만들 때
references/ai-bt.md
BehaviourTree —
AIComponent
+ Composite 4종 +
@BTNode
+ Decorator/Memory/Threat 자작
BT 기반 몬스터·보스 AI, 다층 의사결정 필요할 때
우선순위: *본 SKILL.md (개념·API 표) → 해당 references/ (구현 전체) →
mod/*.cs
검증 (의심 시)**.

本SKILL.md仅涵盖系统流程与原生API表面。实际模型JSON、完整脚本代码、变形模式请直接阅读下方references/*文档。
文件覆盖范围阅读时机
references/monster-setup.md
怪物
.model
组件组装 + ActionSheet + AI选择 + MonsterAI挂载
创建可战斗的怪物时
references/hp-gauge.md
基于
PixelRendererComponent
的头顶HP条完整实现
需要添加头顶HP条时
references/projectile.md
投射物(无Body实体 +
OnUpdate Translate
) + 追踪/穿透/溅射变形
创建弓箭、子弹、魔法弹等远程攻击时
references/ai-bt.md
行为树(BehaviourTree)——
AIComponent
+ 4种复合节点 +
@BTNode
+ 自定义Decorator/记忆/威胁表
需要基于BT的怪物/BOSS AI、多层决策时
优先级:本SKILL.md(概念·API表)→ 对应references/*(完整实现)→
mod/*.cs
验证(有疑问时)
.

1. Attack Resolution

1. 攻击判定(Attack Resolution)

1-1. Shape & Attack 발동

1-1. 形状与攻击触发

HitComponent.ColliderType
= Box / Circle / Polygon 만 지원. 기타 형태는 조합으로 근사.
AttackComponent:
  Attack(Vector2 size, Vector2 offset, string attackInfo, CollisionGroup? cg)    → table<Component>
  Attack(Shape shape, string attackInfo, CollisionGroup? cg)                     → table<Component>
  AttackFast(Shape shape, string attackInfo, CollisionGroup? cg)                 → void   (대량 판정용, 탄막)
  AttackFrom(Vector2 size, Vector2 position, string attackInfo, CollisionGroup? cg) → table<Component>
  emitter EmitAttackEvent(AttackEvent)
  • Shape:
    RectangleShape(center, size)
    /
    CircleShape(center, radius)
    /
    BoxShape(pos, size, angle)
  • Polygon 피격면:
    HitComponent.PolygonPoints: SyncList<Vector2>
  • AttackFast
    는 히트 테이블 미생성 → 탄막·대량 판정 성능 유리
HitComponent.ColliderType
仅支持Box / Circle / Polygon。其他形状需通过组合近似实现。
AttackComponent:
  Attack(Vector2 size, Vector2 offset, string attackInfo, CollisionGroup? cg)    → table<Component>
  Attack(Shape shape, string attackInfo, CollisionGroup? cg)                     → table<Component>
  AttackFast(Shape shape, string attackInfo, CollisionGroup? cg)                 → void   (用于大量判定,如弹幕)
  AttackFrom(Vector2 size, Vector2 position, string attackInfo, CollisionGroup? cg) → table<Component>
  emitter EmitAttackEvent(AttackEvent)
  • Shape:
    RectangleShape(center, size)
    /
    CircleShape(center, radius)
    /
    BoxShape(pos, size, angle)
  • 多边形受击面:
    HitComponent.PolygonPoints: SyncList<Vector2>
  • AttackFast
    不生成命中表 → 弹幕、大量判定场景性能更优

1-2. 타겟 필터

1-2. 目标过滤

지점오버라이드용도
공격자
AttackComponent:IsAttackTarget(defender, attackInfo) → boolean
진영·거리·상태
피격자
HitComponent:IsHitTarget(attackInfo) → boolean
무적·면역
한쪽이라도 false → 히트 제외. super 호출은
__base:IsAttackTarget(...)
(mlua 고유).
  • HitComponent.CollisionGroup
    기본
    CollisionGroups.HitBox
    .
    Attack(..., cg)
    마지막 인자로 타겟 그룹 지정
  • 중복 히트 방지 / 관통 / 최대 히트 수: 네이티브 없음.
    Attack
    반환 테이블 +
    table<Entity, boolean>
    캐시로 스크립트 관리
判定点可重写用途
攻击者
AttackComponent:IsAttackTarget(defender, attackInfo) → boolean
阵营、距离、状态
受击者
HitComponent:IsHitTarget(attackInfo) → boolean
无敌、免疫
任意一方返回false则排除命中。父类调用需使用**
__base:IsAttackTarget(...)
**(mlua特有语法)。
  • HitComponent.CollisionGroup
    默认值为
    CollisionGroups.HitBox
    。可通过
    Attack(..., cg)
    最后一个参数指定目标分组
  • 重复命中防止 / 穿透 / 最大命中数:无原生支持,需通过
    Attack
    返回表 +
    table<Entity, boolean>
    缓存实现脚本管理

1-3.
attackInfo
태깅

1-3.
attackInfo
标记

CalcDamage
/
IsHitTarget
/
GetDisplayHitCount
로 전파되는 string 확장 지점. 값 규약은 프로젝트 자율.
"melee.light"
,
"dot.poison"
식 네임스페이스 권장.
attackInfo
是可扩展的字符串,会传递至
CalcDamage
/
IsHitTarget
/
GetDisplayHitCount
。值的规则由项目自行定义,推荐使用
"melee.light"
"dot.poison"
这类命名空间格式。

1-4. ⚠️ IsLegacy

1-4. ⚠️ IsLegacy

HitComponent.IsLegacy = false
에서만
ColliderType
/
ColliderOffset
/
PolygonPoints
유효.
BoxOffset
/
ColliderName
deprecated.
仅当
HitComponent.IsLegacy = false
时,
ColliderType
/
ColliderOffset
/
PolygonPoints
才有效。
BoxOffset
/
ColliderName
已废弃。

1-5. 공격 형태별 Shape 매핑

1-5. 攻击形态对应Shape映射

형태Shape 구성
근접 전방 Box
BoxShape(pos + LookDirectionX*offset, size, 0)
— DefaultPlayer
PlayerAttack
참조
원형 AoE
CircleShape(self.WorldPos, radius)
투사체Body 없는 모델(Sprite+Transform만) 스폰 +
OnUpdate(delta)
에서
TransformComponent:Translate(speed*delta, 0)
+ 거리 기반 적중 판정 +
_EntityService:Destroy
. 이동 규칙 §1-6, 전체 구현 →
references/projectile.md
MSW 전용 투사체 시스템 없음 — 엔티티 +
AttackComponent
조합으로 구현.
形态Shape构成
近战前方Box
BoxShape(pos + LookDirectionX*offset, size, 0)
— 参考DefaultPlayer的
PlayerAttack
圆形AoE
CircleShape(self.WorldPos, radius)
投射物无Body模型(仅Sprite+Transform)生成 + 在
OnUpdate(delta)
中调用
TransformComponent:Translate(speed*delta, 0)
+ 基于距离的命中判定 +
_EntityService:Destroy
。移动规则见§1-6,完整实现→
references/projectile.md
MSW无专属投射物系统 — 需通过实体 +
AttackComponent
组合实现。

1-6. 연속 이동 — 투사체·몬스터·AI 공통 규칙

1-6. 连续移动 — 投射物·怪物·AI通用规则

연속 이동(추적·비행·자동 이동)은 매 프레임
OnUpdate(delta)
기반
. 타이머(
SetTimerRepeat(0.1~0.15s)
)로 이동시키면 6~10Hz 순간이동으로 보여 끊긴다.
连续移动(追踪、飞行、自动移动)需基于**每帧
OnUpdate(delta)
**实现。若用定时器(
SetTimerRepeat(0.1~0.15s)
)移动,会呈现6~10Hz的瞬移效果,导致动作卡顿。

대상별 권장 API

各对象推荐API

대상Body 유무이동 API근거
몬스터 / NPC / AI있음 (맵 타입 Body +
MovementComponent
)
MovementComponent:MoveToDirection(dir, 0)
+
MovementComponent.InputSpeed
MovementComponent.d.mlua:1
— Rigid/Kinematic/Sideview 셋 다 제어.
InputSpeed
는 MovementComponent 소속(
.d.mlua:7
)으로 Player 전용 아님. 두 번째 인자
0
— deltaTime은 사다리에서만 적용(
.d.mlua:32
). BT 공식 예제
ActionFollow
/
ActionMoveRandom
0
사용
투사체 / 젬 / 드롭 아이템 / 이펙트없음 (Sprite+Transform+Trigger)
self.Entity.TransformComponent:Translate(speed*delta, 0)
매 프레임
Body 없으면 Transform 직접 조작 안전. 공식 "Create a Long-Range Projectile" 튜토리얼 패턴
Rigidbody 엔티티 직접 제어 (고급)있음
body:AddForce(...)
— 지속 가속/임펄스
RigidbodyComponent.d.mlua:71
MoveVelocity
는 "mainly controlled by MovementComponent" 이므로 직접 쓰기보다 MovementComponent 경유 권장
MovementComponent.InputSpeed
맵 타입별 실제 velocity 환산은
msw-general/references/platform.md
§10
참조 (MapleTile=×1, RectTile=÷1.2, SideView=×1.5).
对象是否有Body移动API依据
怪物 / NPC / AI(对应地图类型的Body +
MovementComponent
MovementComponent:MoveToDirection(dir, 0)
+
MovementComponent.InputSpeed
MovementComponent.d.mlua:1
— 支持Rigid/Kinematic/Sideview三种类型控制。
InputSpeed
属于
MovementComponent
.d.mlua:7
),并非仅玩家可用。第二个参数
0
— deltaTime仅在梯子场景生效(
.d.mlua:32
)。官方BT示例
ActionFollow
/
ActionMoveRandom
也使用
0
投射物 / 宝石 / 掉落物品 / 特效(Sprite+Transform+Trigger)每帧调用
self.Entity.TransformComponent:Translate(speed*delta, 0)
无Body时直接操作Transform更安全。符合官方「Create a Long-Range Projectile」教程模式
直接控制Rigidbody实体(高级)
body:AddForce(...)
— 持续加速/冲量
RigidbodyComponent.d.mlua:71
MoveVelocity
主要由
MovementComponent
控制,因此推荐通过
MovementComponent
间接调用,而非直接使用
MovementComponent.InputSpeed
在不同地图类型下的实际速度换算,请参考
msw-general/references/platform.md
§10
(MapleTile=×1, RectTile=÷1.2, SideView=×1.5)。

금지 패턴

禁止模式

사유
_TimerService:SetTimerRepeat(move, 0.1~0.15)
이동
6~10Hz teleport, 프레임 보간 없음 → 뚝뚝 끊김
OnUpdate
body:SetPosition(...)
/
MovementComponent:SetPosition(...)
둘 다 텔레포트 메서드 (
MovementComponent.d.mlua:37
, 각 Body
.d.mlua
SetPosition
). 연속 이동에 쓰면 끊김. 1회성 스폰·리스폰·스냅에만
self.Entity.TransformComponent.Position = newPos
(Body 활성 엔티티)
다음 프레임 물리엔진이 덮어쓰고 네트워크 동기화 차단
Translate(0.009, 0)
같이 delta 없이 상수 이동
프레임률 의존. 60FPS·30FPS에서 속도 다름
原因
使用
_TimerService:SetTimerRepeat(move, 0.1~0.15)
移动
6~10Hz瞬移,无帧间插值 → 动作卡顿
OnUpdate
内调用
body:SetPosition(...)
/
MovementComponent:SetPosition(...)
两者均为瞬移方法
MovementComponent.d.mlua:37
,各Body的
.d.mlua
SetPosition
)。用于连续移动会导致卡顿,仅可用于一次性生成、重生、对齐操作
(有Body激活的实体)直接赋值
self.Entity.TransformComponent.Position = newPos
下一帧物理引擎会覆盖该值,且会阻断网络同步
不使用delta,直接以常量值移动(如
Translate(0.009, 0)
速度依赖帧率,60FPS与30FPS下速度不同

⚠ 공식 msw-search 안티패턴 주의

⚠ 官方msw-search反模式注意

mlua_Document_Retriever
에 "Entity Movement Control Using MovementComponent" 문서가 높은 점수로 잡히지만, 본문은
OnUpdate
안에서
MovementComponent:SetPosition(...)
으로 매 프레임 이동하는 안티패턴이다 — 이 문서는 무시하고 위 표의
MoveToDirection
/
Translate
로.
FlappyFish Remake
·
Stopping the Taxi
·
Making a Moving Foothold
도 delta 누락 또는
Position
직접 대입을 보여주므로 참조 시 주의.
mlua_Document_Retriever
中「Entity Movement Control Using MovementComponent」文档评分较高,但文档内容是在
OnUpdate
内通过
MovementComponent:SetPosition(...)
每帧移动的反模式 — 请忽略该文档,使用上表中的
MoveToDirection
/
Translate
FlappyFish Remake
Stopping the Taxi
Making a Moving Foothold
等示例也存在delta缺失或直接赋值
Position
的问题,参考时需注意。

MovementComponent 부착 — 몬스터/NPC

挂载MovementComponent — 怪物/NPC

몬스터 모델에 기본 포함 안 됨.
.model
에 다음 컴포넌트가 모두 있어야 한다.
컴포넌트비고
MOD.Core.TransformComponent
기본
MOD.Core.SpriteRendererComponent
렌더
Body (맵 타입)
RigidbodyComponent
(MapleTile) /
KinematicbodyComponent
(RectTile) /
SideviewbodyComponent
(SideViewRectTile)
MOD.Core.MovementComponent
InputSpeed = 2.0
등 — 이동 API용
怪物模型默认不包含该组件
.model
需同时包含以下组件:
组件备注
MOD.Core.TransformComponent
默认组件
MOD.Core.SpriteRendererComponent
渲染组件
Body(对应地图类型)
RigidbodyComponent
(MapleTile) /
KinematicbodyComponent
(RectTile) /
SideviewbodyComponent
(SideViewRectTile)
MOD.Core.MovementComponent
设置
InputSpeed = 2.0
等参数 — 用于移动API

교차 참조

交叉参考

  • **넉백(1-shot 임펄스)**은 연속 이동이 아니므로 §3-1 그대로 사용
  • 맵 타입별 Body 선택 / InputSpeed 환산식:
    msw-general/references/platform.md
    §4·§10

  • **击退(单次冲量)**不属于连续移动,直接使用§3-1中的方法即可
  • 地图类型对应Body选择 / InputSpeed换算公式:
    msw-general/references/platform.md
    §4·§10

2. Damage Model

2. 伤害模型(Damage Model)

AttackComponent:
  method integer CalcDamage(attacker, defender, attackInfo)        -- default 1
  method boolean CalcCritical(attacker, defender, attackInfo)      -- default false
  method float   GetCriticalDamageRate()                           -- default 2.0
  method int32   GetDisplayHitCount(attackInfo)                    -- default 1
  method void    OnAttack(defender)

HitComponent:
  method void OnHit(Entity attacker, integer damage, boolean isCritical, string attackInfo, int32 hitCount)
  emitter EmitHitEvent(HitEvent)
AttackComponent:
  method integer CalcDamage(attacker, defender, attackInfo)        -- 默认值1
  method boolean CalcCritical(attacker, defender, attackInfo)      -- 默认值false
  method float   GetCriticalDamageRate()                           -- 默认值2.0
  method int32   GetDisplayHitCount(attackInfo)                    -- 默认值1
  method void    OnAttack(defender)

HitComponent:
  method void OnHit(Entity attacker, integer damage, boolean isCritical, string attackInfo, int32 hitCount)
  emitter EmitHitEvent(HitEvent)

2-1.
HitEvent
페이로드

2-1.
HitEvent
负载

AttackCenter:   Vector2
AttackerEntity: Entity (nilable)
Damages:        List<integer>    -- 멀티히트 분할
Extra:          any              -- ★ 확장 슬롯 (knockback/stun/element/tags)
IsCritical:     boolean
TotalDamage:    integer
FeedbackAction: HitFeedbackAction  -- ⚠ 전체 enum deprecated
부가 정보(넉백 벡터·경직 시간·속성)는
Extra
테이블로 실어 전달.
AttackCenter:   Vector2
AttackerEntity: Entity (可空)
Damages:        List<integer>    -- 多段伤害拆分
Extra:          any              -- ★ 扩展字段(击退/僵直/属性/标签)
IsCritical:     boolean
TotalDamage:    integer
FeedbackAction: HitFeedbackAction  -- ⚠ 整个枚举已废弃
附加信息(击退向量、僵直时间、属性)需通过
Extra
表传递。

2-2.
AttackEvent
페이로드

2-2.
AttackEvent
负载

DefenderEntity: Entity
하나. 공격자는 핸들러
self
.
包含
DefenderEntity: Entity
。攻击者为事件处理者
self

2-3. ⚠️ 직접 HP 차감 안티패턴 —
HitEvent
우회 금지

2-3. ⚠️ 直接扣减HP反模式 — 禁止绕过
HitEvent

monster.Hp -= damage
/
target.MonsterAI.HP -= damage
처럼 피격자 HP를 직접 깎으면
HitEvent
가 발행되지 않는다

若直接修改受击者HP(如
monster.Hp -= damage
/
target.MonsterAI.HP -= damage
),则不会触发
HitEvent

3. Hit Reaction

3. 受击反应(Hit Reaction)

3-1. 넉백 — Body별 API

3-1. 击退 — 按Body类型对应API

Body (맵 타입)구현
Rigidbody (MapleTile)
body:AddForce(Vector2(dir*5, 3))
★권장 ·
SetForce
·
JustJump(Vector2(0, 4))
(수직)
Kinematicbody (RectTile/탑다운)
body.MoveVelocity = Vector2(dir*5, 0)
— AddForce 없음
Sideviewbody (SideViewRectTile)
body.MoveVelocity
+
body.JumpSpeed
  • Rigidbody 는 엔진이 자동 감쇠. Kinematic/Sideview 는
    OnUpdate
    에서 수동 감쇠 (
    MoveVelocity *= 0.9
    )
  • 벽 튕김:
    FootholdCollisionEvent
    구독 후 velocity 반전
  • 넉백은 1-shot 임펄스 — 연속 이동(추적·비행)과 혼동 금지. 연속 이동은 §1-6
  • ⚠ 금지: Body 활성 엔티티에
    TransformComponent.Position
    직접 대입 → 네트워크 동기화 차단.
    body:SetPosition(...)
    은 텔레포트 메서드이므로
    OnUpdate
    루프에서 호출 금지 (§1-6)
Body(地图类型)实现方式
Rigidbody(MapleTile)
body:AddForce(Vector2(dir*5, 3))
★推荐 ·
SetForce
·
JustJump(Vector2(0, 4))
(垂直方向)
Kinematicbody(RectTile/俯视角)
body.MoveVelocity = Vector2(dir*5, 0)
— 无AddForce方法
Sideviewbody(SideViewRectTile)
body.MoveVelocity
+
body.JumpSpeed
  • Rigidbody由引擎自动衰减速度。Kinematic/Sideview需在
    OnUpdate
    中手动衰减(
    MoveVelocity *= 0.9
  • 墙壁反弹:订阅
    FootholdCollisionEvent
    后反转velocity
  • 击退为单次冲量 — 请勿与连续移动(追踪、飞行)混淆。连续移动规则见§1-6
  • ⚠ 禁止:对有Body激活的实体直接赋值
    TransformComponent.Position
    → 阻断网络同步。
    body:SetPosition(...)
    是瞬移方法,禁止在
    OnUpdate
    循环中调用(§1-6)

3-2. i-frame

3-2. 无敌帧(i-frame)

표준 패턴:
_UtilLogic.ElapsedSeconds
기반 deadline 체크 +
HitComponent:IsHitTarget
에서 false.
DefaultPlayer
기본
PlayerHit.mlua
가 이 패턴을 그대로 제공 (§9-4).
대안: 무적 중
HitComponent.CollisionGroup
을 별도 그룹으로 교체 → 판정 자체 제외. 프레임 단위 정확도에 유리.
标准模式:基于
_UtilLogic.ElapsedSeconds
的截止时间检查 + 在
HitComponent:IsHitTarget
中返回false。DefaultPlayer默认的
PlayerHit.mlua
已实现该模式(§9-4)。
替代方案:无敌期间将
HitComponent.CollisionGroup
切换为单独分组 → 直接排除判定。帧级精度更优。

3-3. 상태이상 (Buff/Debuff)

3-3. 异常状态(Buff/Debuff)

네이티브 부재.
@Component BuffComponent
직접 구현 +
_TimerService:SetTimerRepeat
틱 + 커스텀
StatusAppliedEvent
/
StatusExpiredEvent
브로드캐스트.
단순 스턴 1종이면
StateComponent:ChangeState("STUN")
+ 입력/AI 차단 플래그로 충분.

无原生支持。需自行实现
@Component BuffComponent
+
_TimerService:SetTimerRepeat
Tick + 自定义
StatusAppliedEvent
/
StatusExpiredEvent
广播。
若仅需简单眩晕,使用
StateComponent:ChangeState("STUN")
+ 输入/AI阻断标记即可。

4. Game Feel — 전부 네이티브

4. 游戏手感(Game Feel)— 全部原生支持

요소APIExecSpace
Hit Stop (전역)
_UtilLogic:SetClientTimeScale(float)
— 0~100
ClientOnly
Hit Stop (개별)
renderer.PlayRate = 0
(Sprite/Skeleton/Avatar)
@Sync
Slow Motion
_UtilLogic:SetClientTimeScale(0.3)
+ 타이머 복귀
ClientOnly
Camera Shake
cameraComp:ShakeCamera(intensity, duration, targetUserId?)
Client
Camera Zoom
cameraComp:SetZoomTo(percent, duration, targetUserId?)
· 단
IsAllowZoomInOut=true
선행
Client
Hit Flash
spriteRenderer.Color = Color(r,g,b,a)
→ 타이머 복귀
@Sync
Color HDR 오버브라이트
Color.HSVToRGB(h, s, v, hdr=true)
— 1.0 초과 허용
VFX 고정
_EffectService:PlayEffect(clipRUID, instigator, pos, zRot, scale, isLoop?, options?)
→ serial
VFX 부착
_EffectService:PlayEffectAttached(clipRUID, parent, localPos, localZRot, localScale, isLoop?, options?)
VFX 제거
_EffectService:RemoveEffect(serial)
SFX 2D
_SoundService:PlaySound(id, volume, targetUserId?)
Client
SFX 3D
_SoundService:PlaySoundAtPos(id, pos, listener, volume)
Client
SFX 루프
PlayLoopSound
/
PlayLoopSoundAtPos
Client
SFX 부착
SoundComponent:Play()
· 피치 랜덤은
Pitch
0~3
Client
BGM
_SoundService:PlayBGM(id, volume)
/
StopBGM(immediately)
Client
프리로드
_SoundService:LoadSound(id)
ClientOnly
PlayEffect
options 키:
FlipX, FlipY, SortingLayer, OrderInLayer, Alpha, StartFrameIndex, EndFrameIndex, PlayRate, SyncFlip, Color, MaterialID, IgnoreMapLayerCheck, LitMode
현재 카메라 획득:
_CameraService:GetCurrentCameraComponent()
.
要素API执行空间
Hit Stop(全局)
_UtilLogic:SetClientTimeScale(float)
— 取值0~100
ClientOnly
Hit Stop(单个对象)
renderer.PlayRate = 0
(Sprite/Skeleton/Avatar)
@Sync
慢动作
_UtilLogic:SetClientTimeScale(0.3)
+ 定时器恢复
ClientOnly
相机震动
cameraComp:ShakeCamera(intensity, duration, targetUserId?)
Client
相机缩放
cameraComp:SetZoomTo(percent, duration, targetUserId?)
· 需先设置
IsAllowZoomInOut=true
Client
击中闪屏
spriteRenderer.Color = Color(r,g,b,a)
→ 定时器恢复颜色
@Sync
Color HDR叠加
Color.HSVToRGB(h, s, v, hdr=true)
— 允许v值超过1.0
固定位置VFX
_EffectService:PlayEffect(clipRUID, instigator, pos, zRot, scale, isLoop?, options?)
→ 返回serial
挂载VFX
_EffectService:PlayEffectAttached(clipRUID, parent, localPos, localZRot, localScale, isLoop?, options?)
移除VFX
_EffectService:RemoveEffect(serial)
2D SFX
_SoundService:PlaySound(id, volume, targetUserId?)
Client
3D SFX
_SoundService:PlaySoundAtPos(id, pos, listener, volume)
Client
循环SFX
PlayLoopSound
/
PlayLoopSoundAtPos
Client
挂载SFX
SoundComponent:Play()
· 音调随机可设置
Pitch
为0~3
Client
BGM
_SoundService:PlayBGM(id, volume)
/
StopBGM(immediately)
Client
预加载
_SoundService:LoadSound(id)
ClientOnly
PlayEffect
的options参数键:
FlipX, FlipY, SortingLayer, OrderInLayer, Alpha, StartFrameIndex, EndFrameIndex, PlayRate, SyncFlip, Color, MaterialID, IgnoreMapLayerCheck, LitMode
获取当前相机:
_CameraService:GetCurrentCameraComponent()
.

ParticleService — 내장 파티클

ParticleService — 内置粒子

RUID 없이 enum 값만으로 범용 파티클 연출. 3종류:
-- BasicParticle: 범용 프리셋 (RUID 불필요)
integer _ParticleService:PlayBasicParticle(BasicParticleType, Entity instigator, Vector3 pos, number zRot, Vector3 scale, boolean isLoop, Dictionary options)
integer _ParticleService:PlayBasicParticleAttached(BasicParticleType, Entity parent, Vector3 localPos, number localZRot, Vector3 localScale, boolean isLoop, Dictionary options)

-- SpriteParticle: 커스텀 스프라이트를 파티클로 (spriteRUID 필요)
integer _ParticleService:PlaySpriteParticle(SpriteParticleType, string spriteRUID, Entity instigator, Vector3 pos, number zRot, Vector3 scale, boolean isLoop, Dictionary options)
integer _ParticleService:PlaySpriteParticleAttached(SpriteParticleType, string spriteRUID, Entity parent, Vector3 localPos, number localZRot, Vector3 localScale, boolean isLoop, Dictionary options)

-- AreaParticle: 넓은 영역 환경 파티클 (areaSize 추가)
integer _ParticleService:PlayAreaParticle(AreaParticleType, Vector2 areaSize, Entity instigator, Vector3 pos, number zRot, Vector3 scale, boolean isLoop, Dictionary options)

void _ParticleService:RemoveParticle(integer serial)
options 키:
Color, SortingLayer, OrderInLayer, ParticleSize, ParticleCount
루프 파티클(
isLoop=true
)은 반드시
RemoveParticle(serial)
로 정리. serial을
self._T
에 저장해두어야 나중에 제거 가능.
无需RUID,仅通过枚举值即可实现通用粒子效果。包含3种类型:
-- BasicParticle: 通用预设(无需RUID)
integer _ParticleService:PlayBasicParticle(BasicParticleType, Entity instigator, Vector3 pos, number zRot, Vector3 scale, boolean isLoop, Dictionary options)
integer _ParticleService:PlayBasicParticleAttached(BasicParticleType, Entity parent, Vector3 localPos, number localZRot, Vector3 localScale, boolean isLoop, Dictionary options)

-- SpriteParticle: 将自定义Sprite作为粒子(需spriteRUID)
integer _ParticleService:PlaySpriteParticle(SpriteParticleType, string spriteRUID, Entity instigator, Vector3 pos, number zRot, Vector3 scale, boolean isLoop, Dictionary options)
integer _ParticleService:PlaySpriteParticleAttached(SpriteParticleType, string spriteRUID, Entity parent, Vector3 localPos, number localZRot, Vector3 localScale, boolean isLoop, Dictionary options)

-- AreaParticle: 大范围环境粒子(需添加areaSize)
integer _ParticleService:PlayAreaParticle(AreaParticleType, Vector2 areaSize, Entity instigator, Vector3 pos, number zRot, Vector3 scale, boolean isLoop, Dictionary options)

void _ParticleService:RemoveParticle(integer serial)
options参数键:
Color, SortingLayer, OrderInLayer, ParticleSize, ParticleCount
循环粒子(
isLoop=true
)必须通过
RemoveParticle(serial)
清理。需将serial存储在
self._T
中以便后续移除。

BasicParticleType 전체 목록

BasicParticleType完整列表

계열이름설명
폭발/충격
SparkExplosion
스파크 (1회) — 범용 피격
SparkLoop
연속 스파크
SparkRadialExplosion
원형으로 튀는 스파크
SmallExplosion
작은 폭발 + 연기
BigExplosion
큰 폭발 + 연기
TinyExplosion
아주 작은 폭발 (Color 옵션 무효)
DustExplosion
원형 파동 + 연기 (Color 옵션 무효)
EnergyExplosion
원형 파동 후 중심 수렴
CircleBurst
원형 빛 폭발
PillarBurst
원형 빛 폭발 + 방향성 빛
불/화염
FireField
만화풍 불꽃
FireFieldIntense
강한 만화풍 불꽃
FireBall
한 곳에 화염 생성
FlameThrower
화염 방출
LargeFlames
바닥에서 큰 화염
MediumFlames
바닥에서 중간 화염
TinyFlames
바닥에서 작은 화염
WildFire
거대한 화염 기둥 (Color 옵션 무효)
번개/전기
LightningOrbSharp
구형 전기 파티클
LightningStrikeSharp
번개
LightningStrikeSharpTall
긴 번개
LightningOrbSoft
전기파 방출
LightningBlast
주기적 전기파
LightningStrike
주기적 번개
LightningStrikeTall
주기적 긴 번개
버프/마법
Aura
바닥에서 오로라 빛
Buff
바닥에서 강한 빛 상승
Charge
큰 파티클이 한 점으로 수렴
ChargeOrb
파티클이 한 점으로 수렴
Enchant
큰 빛 주변에 빛과 파티클
SpinField
회전하는 원 주변에 파티클
StarVortex
별빛이 중심으로 수렴
Nova
넓은 원형 파동
UpperCylinder
바닥에서 기둥 형태 상승
기타
Firework
불꽃놀이
FireworkCluster
여러 폭죽 동시
FireFlies
반딧불이
GoopSpray
옆으로 액체 분출
GoopSprayEffect
바닥으로 액체 분출
DustStorm
넓은 모래 폭풍
RisingSteam
바닥에서 흰 안개 상승
BigSplash
큰 물보라
Shower
한 곳에 물 뿌림
系列名称说明
爆炸/冲击
SparkExplosion
火花(单次)— 通用击中效果
SparkLoop
连续火花
SparkRadialExplosion
呈圆形散射的火花
SmallExplosion
小型爆炸 + 烟雾
BigExplosion
大型爆炸 + 烟雾
TinyExplosion
微型爆炸(Color选项无效)
DustExplosion
圆形冲击波 + 烟雾(Color选项无效)
EnergyExplosion
圆形冲击波后向中心收敛
CircleBurst
圆形光效爆炸
PillarBurst
圆形光效爆炸 + 方向性光线
火/火焰
FireField
卡通风格火焰
FireFieldIntense
强烈卡通风格火焰
FireBall
在指定位置生成火焰
FlameThrower
喷射火焰
LargeFlames
从地面升起的大型火焰
MediumFlames
从地面升起的中型火焰
TinyFlames
从地面升起的小型火焰
WildFire
巨型火焰柱(Color选项无效)
闪电/电
LightningOrbSharp
球形电粒子
LightningStrikeSharp
闪电
LightningStrikeSharpTall
长闪电
LightningOrbSoft
释放电波
LightningBlast
周期性电波
LightningStrike
周期性闪电
LightningStrikeTall
周期性长闪电
Buff/魔法
Aura
从地面升起的极光
Buff
从地面升起的强光
Charge
大型粒子向单点收敛
ChargeOrb
粒子向单点收敛
Enchant
强光周围伴随光线与粒子
SpinField
旋转圆形周围伴随粒子
StarVortex
星光向中心收敛
Nova
大范围圆形冲击波
UpperCylinder
从地面升起的柱状光效
其他
Firework
烟花
FireworkCluster
多枚烟花同时绽放
FireFlies
萤火虫
GoopSpray
向侧面喷射液体
GoopSprayEffect
向地面喷射液体
DustStorm
大范围沙尘暴
RisingSteam
从地面升起的白色雾气
BigSplash
大型水花
Shower
向指定位置喷水

SpriteParticleType 전체 목록 (8종)

SpriteParticleType完整列表(8种)

이름설명
BurstBig
스프라이트가 원형으로 퍼지며 등장
SpawnField
파티클+스프라이트가 원형 영역에 등장
BurstNova
파티클+스프라이트가 원형으로 폭발
SimpleSpawn
파티클+스프라이트 단순 등장
Burst
파티클+스프라이트가 퍼짐
Stream
특정 방향으로 이동하며 생성
StreamSharp
가느다란 선으로 특정 방향 이동
AdditiveColor
스프라이트에 색상 효과 적용
名称说明
BurstBig
Sprite呈圆形扩散出现
SpawnField
粒子+Sprite在圆形区域出现
BurstNova
粒子+Sprite呈圆形爆炸
SimpleSpawn
粒子+Sprite简单出现
Burst
粒子+Sprite扩散
Stream
沿指定方向移动并生成
StreamSharp
以细直线沿指定方向移动
AdditiveColor
为Sprite添加颜色效果

AreaParticleType 전체 목록 (12종)

AreaParticleType完整列表(12种)

이름설명
Rain
Snow
FogCalm
안개
FogHeavy
짙은 내려오는 안개
FogLively
올라오는 안개
CalmStarField
올라오는 별 무리
StarFieldSimple
반짝이는 별 무리
StarFog
별+성운 파티클 (제자리)
StarFogFlow
별+성운 파티클 (상승)
Windlines
가는 선
WindlinesBig
가는 선 + 굵은 선
WindlinesSpeedy
빠른 직선
名称说明
Rain
Snow
FogCalm
FogHeavy
厚重下落雾
FogLively
上升雾
CalmStarField
上升星群
StarFieldSimple
闪烁星群
StarFog
星+星云粒子(静止)
StarFogFlow
星+星云粒子(上升)
Windlines
细线
WindlinesBig
细线 + 粗线
WindlinesSpeedy
快速直线

EffectService vs ParticleService 선택

EffectService vs ParticleService选择

상황권장
메이플스토리 스킬/피격 애니메이션 (구체적 이미지)
EffectService
(RUID 지정)
범용 피격·폭발 (빠른 구현)
ParticleService.BasicParticle
커스텀 이미지를 파티클로 흩뿌리기
ParticleService.SpriteParticle
비·눈·안개 등 환경 연출
ParticleService.AreaParticle
버프 오라 등 지속 효과둘 다
isLoop=true
가능
풍성한 연출EffectService + ParticleService 동시 조합
서버 이벤트 → 클라이언트 이펙트 표준 패턴:
@Sync
프로퍼티 변경 →
OnSyncProperty(ClientOnly)
감지 → EffectService/ParticleService 호출.

场景推荐
冒险岛风格技能/击中动画(具体图像)
EffectService
(指定RUID)
通用击中·爆炸(快速实现)
ParticleService.BasicParticle
将自定义图像作为粒子散射
ParticleService.SpriteParticle
雨·雪·雾等环境效果
ParticleService.AreaParticle
Buff光环等持续效果两者均支持
isLoop=true
丰富效果同时组合EffectService + ParticleService
服务器事件→客户端效果标准模式:修改
@Sync
属性 → 在
OnSyncProperty(ClientOnly)
中检测 → 调用EffectService/ParticleService.

5. 사망 / 부활

5. 死亡 / 复活

이벤트발행 조건페이로드
DeadEvent
StateComponent:ChangeState("DEAD")
시 자동
없음
ReviveEvent
PlayerComponent:Respawn()
시 자동 (플레이어 한정)
없음
StateChangeEvent
모든 상태 전환 시 자동
CurrentStateName
,
PrevStateName
,
IsInitial
킬러 추적: DeadEvent 페이로드 없음 →
HandleHitEvent
에서
self.LastAttacker = event.AttackerEntity
캐시 후
HandleDeadEvent
에서 사용.
플레이어 전용 사망·부활은 §9-1
PlayerComponent.Respawn/ProcessDead/ProcessRevive
우선 사용.

事件触发条件负载
DeadEvent
调用
StateComponent:ChangeState("DEAD")
时自动触发
ReviveEvent
调用
PlayerComponent:Respawn()
时自动触发(仅玩家)
StateChangeEvent
所有状态切换时自动触发
CurrentStateName
,
PrevStateName
,
IsInitial
追踪击杀者
DeadEvent
无负载 → 在
HandleHitEvent
中缓存
self.LastAttacker = event.AttackerEntity
,然后在
HandleDeadEvent
中使用。
玩家专属死亡·复活优先使用§9-1中的
PlayerComponent.Respawn/ProcessDead/ProcessRevive

6. Event Bus

6. 事件总线(Event Bus)

논리 이벤트MSW 구현
OnAttackStart
OnAttack
훅 또는 커스텀
AttackStartEvent
OnAttackHit / OnDamageTaken네이티브
HitEvent
OnAttackMiss커스텀 —
IsAttackTarget
false 시 SendEvent
OnCriticalHit
HitEvent.IsCritical
플래그로 커버
OnDeath / OnRevive네이티브
DeadEvent
/
ReviveEvent
OnStateChange네이티브
StateChangeEvent
OnKill / OnBlocked / OnParry / OnStatusApplied커스텀
@Event
逻辑事件MSW实现方式
OnAttackStart
OnAttack
钩子或自定义
AttackStartEvent
OnAttackHit / OnDamageTaken原生
HitEvent
OnAttackMiss自定义 —
IsAttackTarget
返回false时发送事件
OnCriticalHit通过
HitEvent.IsCritical
标志覆盖
OnDeath / OnRevive原生
DeadEvent
/
ReviveEvent
OnStateChange原生
StateChangeEvent
OnKill / OnBlocked / OnParry / OnStatusApplied自定义
@Event

6-1. 커스텀 이벤트 규칙

6-1. 自定义事件规则

  • 정의:
    @Event script XxxEvent extends EventType
    +
    property
  • 수신:
    handler
    키워드 (method 아님),
    @EventSender("Self" | "Service","XxxService" | "Logic","XxxLogic")
  • 연결/해제:
    entity:ConnectEvent(XxxEvent, self.Handler)
    /
    OnEndPlay
    에서 반드시
    DisconnectEvent
    (엔진 자동 해제 없음)
  • 전역:
    @Logic CombatEventBusLogic
    싱글턴 +
    @EventSender("Logic","CombatEventBusLogic")

  • 定义:
    @Event script XxxEvent extends EventType
    + 相关
    property
  • 接收:使用
    handler
    关键字(非method),搭配
    @EventSender("Self" | "Service","XxxService" | "Logic","XxxLogic")
  • 连接/断开:
    entity:ConnectEvent(XxxEvent, self.Handler)
    / 必须在
    OnEndPlay
    中调用
    DisconnectEvent
    (引擎不会自动断开)
  • 全局事件:
    @Logic CombatEventBusLogic
    单例 +
    @EventSender("Logic","CombatEventBusLogic")

7. AI — FSM(StateComponent) + BT(AIComponent) 둘 다 네이티브

7. AI — FSM(StateComponent) + BT(AIComponent)均原生支持

패턴적합참조
FSM (
StateComponent
+
@State
)
단순 적 (3~5상태), 플레이어 IDLE/HIT/DEAD, 보스 페이즈, 애니메이션 동기 (
AvatarStateAnimationComponent
자동 매핑 §10)
references/fsm-state.md
BT (
AIComponent
+ Composite 4종 +
@BTNode
)
패트롤+추적+공격 조합, 다양한 보스 패턴, Composite/Decorator 재사용, 확률 가중 행동
references/ai-bt.md
模式适用场景参考文档
FSM
StateComponent
+
@State
简单敌人(3~5种状态)、玩家IDLE/HIT/DEAD、BOSS阶段、动画同步(
AvatarStateAnimationComponent
自动映射§10)
references/fsm-state.md
BT
AIComponent
+ 4种复合节点 +
@BTNode
巡逻+追踪+攻击组合、多样BOSS模式、Composite/Decorator复用、带权重随机行为
references/ai-bt.md

7-1. FSM —
StateComponent
(요약)

7-1. FSM —
StateComponent
(摘要)

StateComponent
+
@State script XxxStateType extends StateType
(라이프사이클
OnEnter
/
OnUpdate
/
OnExit
/
OnConditionCheck
). 자동 등록 상태는
IDLE
/
DEAD
(+
HitComponent
있으면
HIT
,
AIChase
/
AIWander
있으면
MOVE
) 뿐 —
ATTACK
/
PATROL
/
STUN
/
PHASE2
등은 모두
OnBeginPlay
에서
AddState("이름", XxxStateType)
사전 등록 필수. 자동 전이는
AddCondition(from, to)
+
OnConditionCheck()
매 프레임 검사.
상태 이름은 UPPERCASE 강제, 미등록 이름은 즉시
[LEA-3005] InvalidArgument : 'stateName'
.
AvatarStateAnimationComponent.StateToAvatarBodyActionSheet
키를 등록해도
StateComponent
엔 자동 등록되지 않음 — 둘은 별개.
전체 구현 →
references/fsm-state.md
StateComponent
+
@State script XxxStateType extends StateType
(生命周期
OnEnter
/
OnUpdate
/
OnExit
/
OnConditionCheck
)。自动注册的状态仅为
IDLE
/
DEAD
(+ 存在
HitComponent
时自动注册
HIT
,存在
AIChase
/
AIWander
时自动注册
MOVE
) —
ATTACK
/
PATROL
/
STUN
/
PHASE2
等状态必须在
OnBeginPlay
中通过
AddState("名称", XxxStateType)
提前注册。自动状态切换需通过
AddCondition(from, to)
+ 每帧调用
OnConditionCheck()
检测。
状态名称必须为大写,未注册名称会立即触发
[LEA-3005] InvalidArgument : 'stateName'
。即使注册了
AvatarStateAnimationComponent.StateToAvatarBodyActionSheet
的键,也不会自动注册到
StateComponent
— 两者相互独立。
完整实现→
references/fsm-state.md

7-2. BT —
AIComponent
(요약)

7-2. BT —
AIComponent
(摘要)

AIComponent
+
SequenceNode
/
SelectorNode
/
RandomSelectorNode
/
ParallelNode
+
@BTNode
Action Node + 네이티브
AIChaseComponent
/
AIWanderComponent
. Composite 4종은 모두 네이티브, Decorator/Memory(Blackboard)/Threat Table은 자작.
⚠ 커스텀 BT 사용 시
.model
에서
AIChaseComponent
/
AIWanderComponent
제거
전체 구현 →
references/ai-bt.md
몬스터 엔티티 전체 구성 →
references/monster-setup.md
본 SKILL.md는 전투 특화(ATTACK/HIT/DEAD + DeadEvent/ReviveEvent + BT 진입점)만 다룬다. 일반 mlua 상태 머신/스크립팅 패턴은
msw-scripting
참조.

AIComponent
+
SequenceNode
/
SelectorNode
/
RandomSelectorNode
/
ParallelNode
+
@BTNode
动作节点 + 原生
AIChaseComponent
/
AIWanderComponent
4种复合节点均为原生支持,Decorator/记忆(Blackboard)/威胁表需自行实现。
⚠ 使用自定义BT时,需在
.model
中移除
AIChaseComponent
/
AIWanderComponent
完整实现→
references/ai-bt.md
怪物实体完整构成→
references/monster-setup.md
本SKILL.md仅专注于战斗特化内容(ATTACK/HIT/DEAD + DeadEvent/ReviveEvent + BT入口)。通用mlua状态机/脚本模式请参考
msw-scripting

8. UI 네이티브

8. 原生UI

UIAPI
HP 바 (화면 고정)
SliderComponent
(
MinValue
/
MaxValue
/
Value
/
FillRectColor
/
FillRectImageRUID
/
Direction
/
UseHandle
) +
SliderValueChangedEvent
. ⚠ UI 엔티티 전용
데미지 숫자
DamageSkin*
3종 +
DamageSkinService
— §11
크로스헤어
.ui
SpriteGUIRendererComponent
콤보 카운터 / 버프 아이콘
TextComponent
+
SpriteGUIRendererComponent
월드스페이스 HP바 (머리 위): 네이티브 부재. 두 가지 구현 옵션:
옵션방식적합 상황
간이형자식 엔티티
SpriteRendererComponent
LocalScale.x = hp/maxHp
또는
TiledSize.x
조정 (
SpriteDrawMode.Tiled
전제)
임시 프로토타입, 단순 게이지
완성형
PixelRendererComponent
기반 — 전체 구현
references/hp-gauge.md
양산용, 다중 몬스터 동시 표시

UIAPI
HP条(屏幕固定)
SliderComponent
MinValue
/
MaxValue
/
Value
/
FillRectColor
/
FillRectImageRUID
/
Direction
/
UseHandle
) +
SliderValueChangedEvent
⚠ 仅UI实体可用
伤害数字
DamageSkin*
3种 +
DamageSkinService
— §11
准星
.ui
中添加
SpriteGUIRendererComponent
连招计数器 / Buff图标
TextComponent
+
SpriteGUIRendererComponent
世界空间HP条(头顶):无原生支持。有两种实现方案:
方案方式适用场景
简易版子实体
SpriteRendererComponent
通过
LocalScale.x = hp/maxHp
或调整
TiledSize.x
实现(需先设置
SpriteDrawMode.Tiled
临时原型、简单进度条
完整版基于
PixelRendererComponent
实现 — 完整实现参考
references/hp-gauge.md
量产项目、多怪物同时显示

9. DefaultPlayer 전투 네이티브

9. DefaultPlayer原生战斗功能

플레이어 엔티티는 HP·부활·입력을 네이티브로 갖는다. 커스텀
Hp
/
MaxHp
프로퍼티 만들지 말 것
PlayerComponent
사용.
PlayerComponent
/
PlayerControllerComponent
전체 프로퍼티·메서드 표는
msw-defaultplayer/SKILL.md
참조. 여기서는 전투 핵심만.
玩家实体原生支持HP、复活、输入功能。请勿创建自定义
Hp
/
MaxHp
属性
— 使用
PlayerComponent
PlayerComponent
/
PlayerControllerComponent
完整属性·方法表请参考
msw-defaultplayer/SKILL.md
。此处仅列出战斗核心内容。

9-1. 전투 핵심 API

9-1. 战斗核心API

항목사용법
HP 감소
self.Entity.PlayerComponent.Hp -= event.TotalDamage
사망 판정
PlayerComponent:IsDead()
부활
PlayerComponent:Respawn()
RespawnPosition → SpawnLocation → 맵 진입점
.
DeadEvent
/
ReviveEvent
자동 발행
클라 전용 사망 처리
@ExecSpace("Client") ProcessDead(targetUserId?)
/
ProcessRevive(targetUserId?)
방향 판정 ★
PlayerControllerComponent.LookDirectionX
(+1 우, -1 좌).
TransformComponent.Scale.x
사용 금지
액션 훅 오버라이드
ActionAttack
/
ActionJump
/
ActionInteraction(key, isKeyDown)
액션 이벤트 수신
EmitPlayerActionEvent(PlayerActionEvent)
→ §9-3
项目使用方法
HP减少
self.Entity.PlayerComponent.Hp -= event.TotalDamage
死亡判定
PlayerComponent:IsDead()
复活
PlayerComponent:Respawn()
— 优先级:
RespawnPosition → SpawnLocation → 地图入口点
。自动触发
DeadEvent
/
ReviveEvent
客户端专属死亡处理
@ExecSpace("Client") ProcessDead(targetUserId?)
/
ProcessRevive(targetUserId?)
方向判定 ★
PlayerControllerComponent.LookDirectionX
(+1向右,-1向左)。禁止使用
TransformComponent.Scale.x
动作钩子重写
ActionAttack
/
ActionJump
/
ActionInteraction(key, isKeyDown)
动作事件接收
EmitPlayerActionEvent(PlayerActionEvent)
→ §9-3

9-3.
PlayerActionEvent

9-3.
PlayerActionEvent

property string ActionName       -- "Attack" / "Jump" / "Crouch" / ...
property Entity PlayerEntity
PlayerAttack extends AttackComponent
에서
@EventSender("Self") handler HandlePlayerActionEvent(...)
로 수신 후
event.ActionName == "Attack"
분기가 기본 패턴.
property string ActionName       -- "Attack" / "Jump" / "Crouch" / ...
property Entity PlayerEntity
PlayerAttack extends AttackComponent
中默认模式为:通过
@EventSender("Self") handler HandlePlayerActionEvent(...)
接收事件,然后判断
event.ActionName == "Attack"

9-4. 기본 제공 템플릿 (
RootDesk/MyDesk/
)

9-4. 官方提供模板(
RootDesk/MyDesk/

수정 없이 복붙 가능. 필요 시 오버라이드:
파일역할핵심 포인트
PlayerAttack.mlua
전방 Box 공격
LookDirectionX
로 방향,
AttackFast
+
CollisionGroups.Monster
,
CalcDamage=50
, 30% 크리
PlayerHit.mlua
i-frame
ImmuneCooldown
프로퍼티,
_UtilLogic.ElapsedSeconds
deadline,
IsHitTarget
오버라이드
Monster.mlua
몬스터 HP커스텀
@Sync Hp
(PlayerComponent 없음),
HandleHitEvent
Dead/Respawn
MonsterAttack.mlua
sprite 크기 기반 근접
IsAttackTarget
에서
isvalid(defender.PlayerComponent)
+
__base:IsAttackTarget(...)
super
可直接复制使用,按需重写:
文件作用核心要点
PlayerAttack.mlua
前方Box攻击使用
LookDirectionX
判断方向,
AttackFast
+
CollisionGroups.Monster
CalcDamage=50
,30%暴击率
PlayerHit.mlua
无敌帧
ImmuneCooldown
属性,基于
_UtilLogic.ElapsedSeconds
的截止时间,重写
IsHitTarget
Monster.mlua
怪物HP自定义
@Sync Hp
(无PlayerComponent),
HandleHitEvent
→ 死亡/重生
MonsterAttack.mlua
基于Sprite大小的近战攻击
IsAttackTarget
中判断
isvalid(defender.PlayerComponent)
+ 调用父类
__base:IsAttackTarget(...)

9-5. 시간 기준

9-5. 时间基准

_UtilLogic.ElapsedSeconds
권장 (월드 기준, 일시정지/리스토어 일관).
os.clock()
금지.
推荐使用**
_UtilLogic.ElapsedSeconds
**(世界时间基准,暂停/恢复时保持一致)。禁止使用
os.clock()

9-6. 표준 CollisionGroup

9-6. 标准CollisionGroup

상수용도
CollisionGroups.Player
몬스터 → 플레이어 공격
CollisionGroups.Monster
플레이어 → 몬스터 공격
CollisionGroups.HitBox
HitComponent.CollisionGroup
기본

常量用途
CollisionGroups.Player
怪物→玩家攻击
CollisionGroups.Monster
玩家→怪物攻击
CollisionGroups.HitBox
HitComponent.CollisionGroup
默认值

10. 아바타 모션 —
AvatarStateAnimationComponent

10. 角色动作 —
AvatarStateAnimationComponent

StateComponent
전환을 아바타 애니메이션에 자동 연결.
@Sync property SyncDictionary<string, AvatarBodyActionElement> StateToAvatarBodyActionSheet  -- IsLegacy=false
@Sync property SyncDictionary<string, string>                  ActionSheet                    -- IsLegacy=true (deprecated)

method void   SetActionSheet(string key, string animationClipRuid)
method void   RemoveActionSheet(string key)
method string StateStringToAnimationKey(string stateName)
emitter EmitBodyActionStateChangeEvent(BodyActionStateChangeEvent)
  • ChangeState("HIT")
    → 매핑된
    MapleAvatarBodyActionState.Hit
    자동 재생
  • 전투 관련 상태값:
    Attack
    =3,
    Hit
    =14,
    Dead
    =10,
    Alert
    =4,
    Heal
    =13
  • IsLegacy=false
    고정,
    StateToAvatarBodyActionSheet
    만 사용
Avatar 컴포넌트(
AvatarRendererComponent
등) 전반은
msw-defaultplayer
참조. 본 섹션은 전투 모션 매핑만 다룬다.

StateComponent
状态切换自动关联到角色动画。
@Sync property SyncDictionary<string, AvatarBodyActionElement> StateToAvatarBodyActionSheet  -- IsLegacy=false
@Sync property SyncDictionary<string, string>                  ActionSheet                    -- IsLegacy=true(已废弃)

method void   SetActionSheet(string key, string animationClipRuid)
method void   RemoveActionSheet(string key)
method string StateStringToAnimationKey(string stateName)
emitter EmitBodyActionStateChangeEvent(BodyActionStateChangeEvent)
  • 调用
    ChangeState("HIT")
    → 自动播放映射的
    MapleAvatarBodyActionState.Hit
  • 战斗相关状态值:
    Attack
    =3,
    Hit
    =14,
    Dead
    =10,
    Alert
    =4,
    Heal
    =13
  • 固定设置
    IsLegacy=false
    ,仅使用
    StateToAvatarBodyActionSheet
Avatar组件(
AvatarRendererComponent
等)整体内容请参考
msw-defaultplayer
。本章节仅专注于战斗动作映射。

11. 데미지 스킨 (숫자 표시)

11. 伤害皮肤(数字显示)

기본 RUID

默认RUID

용도RUID사용처
타격
3271c3e79bf04ecba9a107d55495970d
공격자
DamageSkinSettingComponent.DamageSkinId
디폴트
피격
02c22d93421b4038b3c413b3e40b57ec
피격자 측 표시 —
_DamageSkinService:Play
수동 호출
회복
d58b67cf0f3a4eaf9fe1ad87c0ffac8a
힐/포션 —
_DamageSkinService:Play
수동 호출
用途RUID使用场景
攻击伤害
3271c3e79bf04ecba9a107d55495970d
攻击者
DamageSkinSettingComponent.DamageSkinId
默认值
受击伤害
02c22d93421b4038b3c413b3e40b57ec
受击者显示 — 手动调用
_DamageSkinService:Play
恢复
d58b67cf0f3a4eaf9fe1ad87c0ffac8a
治疗/药水 — 手动调用
_DamageSkinService:Play

11-1. 자동 모드 (컴포넌트 기반)

11-1. 自动模式(基于组件)

Attack/AttackFast
호출 시, 아래 3개가 모두 있으면 자동으로 데미지 숫자 표시:
위치컴포넌트역할
공격자
DamageSkinSettingComponent
어떤 스킨/스타일로 표시할지
피격자
DamageSkinSpawnerComponent
표시 위치 오프셋
피격자
DamageSkinComponent
데미지 숫자 본체(엔티티 위)
3개 모두
.model
에 포함시켜두면 스크립트 코드 0줄로 데미지 숫자가 뜬다.
调用
Attack/AttackFast
时,若同时满足以下3个条件,则自动显示伤害数字:
位置组件作用
攻击者
DamageSkinSettingComponent
指定显示的皮肤/样式
受击者
DamageSkinSpawnerComponent
指定显示位置偏移
受击者
DamageSkinComponent
伤害数字本体(显示在实体上方)
将3个组件全部添加到
.model
中,无需编写脚本即可显示伤害数字。

DamageSkinSettingComponent
(공격자)

DamageSkinSettingComponent
(攻击者)

속성타입기본값설명
DamageSkinId
DataRef타격 RUID (위 표)데미지 숫자 스킨 RUID
DamageSkinScale
Vector2(1, 1)숫자 크기
Alpha
float1투명도
PlayRate
float1재생 속도
DelayPerAttack
float0.05멀티히트 간 딜레이(초)
TweenType
DamageSkinTweenTypeDefault연출 타입
LitMode
LitModeDefault조명 영향
DamageSkinTweenType
:
Default
(팝업) /
Volcano
(부채꼴) /
Blade
(겹침) / 각
*Mini
(75% 축소)
属性类型默认值说明
DamageSkinId
DataRef攻击伤害RUID(上表)伤害数字皮肤RUID
DamageSkinScale
Vector2(1, 1)数字大小
Alpha
float1透明度
PlayRate
float1播放速度
DelayPerAttack
float0.05多段伤害间隔(秒)
TweenType
DamageSkinTweenTypeDefault动画类型
LitMode
LitModeDefault光照影响
DamageSkinTweenType
:
Default
(弹出) /
Volcano
(扇形扩散) /
Blade
(叠加) / 各
*Mini
(缩小75%)

DamageSkinSpawnerComponent
(피격자)

DamageSkinSpawnerComponent
(受击者)

속성타입기본값
DamageSkinOffset
Vector2(0,0)
属性类型默认值
DamageSkinOffset
Vector2(0,0)

11-2. 수동 모드 —
DamageSkinService

11-2. 手动模式 —
DamageSkinService

자동 모드로 잡히지 않는 케이스(힐, Miss/Guard, 비표준 데미지원)는
_DamageSkinService
직접 호출.
_DamageSkinService:Play(targetEntity, skinRuid, delay, damages:List<int>, tweenType, isCritical, offset, scale, playRate, alpha, litMode)
_DamageSkinService:PlayTextDamage(targetEntity, skinRuid, textType, tweenType)
_DamageSkinService:PreloadAsync(skinRuid, callback(success))    -- ClientOnly
DamageSkinTextType
:
Miss
/
Guard
/
Resist
/
Shot
/
Counter
_DamageSkinService:Play
Client
영역 — 서버 로직(HP 차감 등)에서 호출하려면
@ExecSpace("Client")
메서드로 래핑하거나
@Sync
프로퍼티 변경 후
OnSyncProperty
에서 트리거.
Play()
의 필수 파라미터는 6개. 옵셔널 5개를 부분만 흘리면 LEA-3005
InvalidArgument
自动模式无法覆盖的场景(治疗、Miss/Guard、非标准伤害源),需直接调用
_DamageSkinService
_DamageSkinService:Play(targetEntity, skinRuid, delay, damages:List<int>, tweenType, isCritical, offset, scale, playRate, alpha, litMode)
_DamageSkinService:PlayTextDamage(targetEntity, skinRuid, textType, tweenType)
_DamageSkinService:PreloadAsync(skinRuid, callback(success))    -- ClientOnly
DamageSkinTextType
:
Miss
/
Guard
/
Resist
/
Shot
/
Counter
_DamageSkinService:Play
属于
Client
执行空间 — 若在服务器逻辑(如HP扣减)中调用,需封装为
@ExecSpace("Client")
方法,或修改
@Sync
属性后在
OnSyncProperty
中触发。
Play()
的必填参数为6个。若仅传递部分可选参数,会触发LEA-3005
InvalidArgument

11-3. 활용 레시피

11-3. 实用示例

(a) 크리티컬 강조 — 자동 모드 + 동적 스케일

(a) 暴击强化 — 自动模式 + 动态缩放

자동 모드는
IsCritical=true
면 빨강 폰트로 자동 처리. 추가 강조하려면 공격자 측 스케일을 일시 증대:
lua
@ExecSpace("ServerOnly")
method int32 CalcDamage(Entity attacker, Entity defender, string attackInfo)
    return 100
end

@ExecSpace("ServerOnly")
method boolean CalcCritical(Entity attacker, Entity defender, string attackInfo)
    return math.random() < 0.3
end

method float GetCriticalDamageRate()
    return 2.5     -- 100 → 250
end
DamageSkinSettingComponent.TweenType = Volcano
(부채꼴 흩뿌림) 또는
Blade
(겹침)로 크리티컬 시각 차별화.
自动模式下
IsCritical=true
会自动使用红色字体。若需进一步强化,可临时增大攻击者的缩放:
lua
@ExecSpace("ServerOnly")
method int32 CalcDamage(Entity attacker, Entity defender, string attackInfo)
    return 100
end

@ExecSpace("ServerOnly")
method boolean CalcCritical(Entity attacker, Entity defender, string attackInfo)
    return math.random() < 0.3
end

method float GetCriticalDamageRate()
    return 2.5     -- 100 → 250
end
设置
DamageSkinSettingComponent.TweenType = Volcano
(扇形扩散)或
Blade
(叠加),可在视觉上区分暴击与普通攻击。

(b) 힐 / 회복 — 수동 호출

(b) 治疗 / 恢复 — 手动调用

lua
local HEAL_RUID = "d58b67cf0f3a4eaf9fe1ad87c0ffac8a"

@ExecSpace("Client")
method void ShowHeal(Entity target, integer amount)
    _DamageSkinService:Play(
        target, HEAL_RUID, 0,
        { amount },                            -- damages
        DamageSkinTweenType.Default,
        false,                                 -- isCritical
        Vector2(0, 0.5),                       -- offset (머리 위)
        Vector2(1, 1), 1.0, 1.0, LitMode.Default
    )
end
lua
local HEAL_RUID = "d58b67cf0f3a4eaf9fe1ad87c0ffac8a"

@ExecSpace("Client")
method void ShowHeal(Entity target, integer amount)
    _DamageSkinService:Play(
        target, HEAL_RUID, 0,
        { amount },                            -- damages
        DamageSkinTweenType.Default,
        false,                                 -- isCritical
        Vector2(0, 0.5),                       -- offset(头顶)
        Vector2(1, 1), 1.0, 1.0, LitMode.Default
    )
end

(c) Miss / Guard / Resist 텍스트

(c) Miss / Guard / Resist文本

lua
local HIT_RUID = "02c22d93421b4038b3c413b3e40b57ec"

@ExecSpace("Client")
method void ShowMiss(Entity target)
    _DamageSkinService:PlayTextDamage(
        target, HIT_RUID, DamageSkinTextType.Miss, DamageSkinTweenType.Default
    )
end
AttackComponent:IsAttackTarget
이 false를 반환했을 때 호출하면 "miss 연출 + 데미지 0".
lua
local HIT_RUID = "02c22d93421b4038b3c413b3e40b57ec"

@ExecSpace("Client")
method void ShowMiss(Entity target)
    _DamageSkinService:PlayTextDamage(
        target, HIT_RUID, DamageSkinTextType.Miss, DamageSkinTweenType.Default
    )
end
AttackComponent:IsAttackTarget
返回false时调用该方法,即可实现“Miss动画 + 0伤害”效果。

(d) 멀티히트 — 한 번 호출로 N개 분할

(d) 多段伤害 — 一次调用显示N段

_DamageSkinService:Play
damages
인자에 List를 통째로 넘기면
DelayPerAttack
(공격자 컴포넌트의 값) 간격으로 순차 표시:
lua
_DamageSkinService:Play(target, ATTACK_RUID, 0, { 12, 8, 14, 11, 9 },
    DamageSkinTweenType.Default, false, Vector2(0,0), Vector2(1,1), 1, 1, LitMode.Default)
자동 모드도
HitEvent.Damages
(List)로 동일 동작 —
GetDisplayHitCount(attackInfo)
를 오버라이드해 분할 수를 제어한다.
将List整体传递给
_DamageSkinService:Play
damages
参数,会按照攻击者组件中的
DelayPerAttack
间隔依次显示:
lua
_DamageSkinService:Play(target, ATTACK_RUID, 0, { 12, 8, 14, 11, 9 },
    DamageSkinTweenType.Default, false, Vector2(0,0), Vector2(1,1), 1, 1, LitMode.Default)
自动模式下通过
HitEvent.Damages
(List)也可实现相同效果 — 可通过重写
GetDisplayHitCount(attackInfo)
控制拆分数量。

(e) Preload — 첫 표시 끊김 방지

(e) Preload — 避免首次显示卡顿

스킨 RUID 첫 사용 시 텍스처 로드 지연이 있을 수 있다. 맵 진입 시 미리 로드:
lua
@ExecSpace("ClientOnly")
method void OnBeginPlay()
    _DamageSkinService:PreloadAsync("3271c3e79bf04ecba9a107d55495970d", function(ok) end)
    _DamageSkinService:PreloadAsync("02c22d93421b4038b3c413b3e40b57ec", function(ok) end)
    _DamageSkinService:PreloadAsync("d58b67cf0f3a4eaf9fe1ad87c0ffac8a", function(ok) end)
end
首次使用皮肤RUID时可能存在纹理加载延迟。可在进入地图时提前加载:
lua
@ExecSpace("ClientOnly")
method void OnBeginPlay()
    _DamageSkinService:PreloadAsync("3271c3e79bf04ecba9a107d55495970d", function(ok) end)
    _DamageSkinService:PreloadAsync("02c22d93421b4038b3c413b3e40b57ec", function(ok) end)
    _DamageSkinService:PreloadAsync("d58b67cf0f3a4eaf9fe1ad87c0ffac8a", function(ok) end)
end

(f) TweenType 사용 케이스

(f) TweenType适用场景

TweenType추천 상황
Default
일반 타격
Volcano
크리티컬 / 광역 타격 (위로 흩뿌림)
Blade
연속 베기 / 콤보 (숫자 겹침)
*Mini
DoT(독/화상) 같은 작은 데미지 — 화면 점유 줄임
TweenType推荐场景
Default
普通攻击
Volcano
暴击 / 范围攻击(向上扩散)
Blade
连续攻击 / 连招(数字叠加)
*Mini
DoT(中毒/灼烧)等小额伤害 — 减少屏幕占用

(g) 진영별 스킨 차별화

(g) 阵营皮肤差异化

플레이어 vs 적, PvP 진영 등에서 다른 스킨 RUID를 쓰려면
DamageSkinSettingComponent.DamageSkinId
를 런타임에 교체:
lua
self.Entity.DamageSkinSettingComponent.DamageSkinId = MY_TEAM_SKIN_RUID

若需在玩家vs敌人、PvP阵营等场景使用不同皮肤RUID,可在运行时修改
DamageSkinSettingComponent.DamageSkinId
lua
self.Entity.DamageSkinSettingComponent.DamageSkinId = MY_TEAM_SKIN_RUID

12. 히트 이펙트 —
HitEffectSpawnerComponent

12. 击中特效 —
HitEffectSpawnerComponent

피격자에 부착만 하면
HitEvent
발생 시 자동으로 히트 이펙트 재생. property 없음,
.model
에 컴포넌트 추가만.

仅需挂载到受击者,当
HitEvent
触发时自动播放击中特效。无属性设置,仅需在
.model
中添加组件即可。

13. 완성형 전투 체크리스트

13. 完整战斗系统检查清单

  • 공격자 모델:
    AttackComponent
    상속 스크립트 (+ 선택:
    DamageSkinSettingComponent
    )
  • 피격자 모델:
    HitComponent
    +
    HitEffectSpawnerComponent
    + (선택:
    DamageSkinSpawnerComponent
    +
    DamageSkinComponent
    )
  • HitComponent:
    IsLegacy=false
    ,
    ColliderType
    /
    BoxSize
    /
    CircleRadius
    설정,
    CollisionGroup
    설정
  • 상태 모션:
    StateComponent
    +
    AvatarStateAnimationComponent.StateToAvatarBodyActionSheet
    ATTACK
    /
    HIT
    /
    DEAD
    등록
  • HP 처리: 플레이어는
    PlayerComponent.Hp
    , 몬스터는 커스텀
    @Sync Hp
  • 방향 판정:
    LookDirectionX
    (Scale.x 금지)
  • 시간 기준:
    _UtilLogic.ElapsedSeconds
    (os.clock 금지)
  • 이벤트 정리:
    OnEndPlay
    에서
    DisconnectEvent
    명시 해제
  • Body 규칙: Body 활성 엔티티에
    TransformComponent.Position
    직접 대입 금지

  • 攻击者模型:继承
    AttackComponent
    的脚本(+ 可选:
    DamageSkinSettingComponent
  • 受击者模型
    HitComponent
    +
    HitEffectSpawnerComponent
    +(可选:
    DamageSkinSpawnerComponent
    +
    DamageSkinComponent
  • HitComponent:设置
    IsLegacy=false
    ,配置
    ColliderType
    /
    BoxSize
    /
    CircleRadius
    ,设置
    CollisionGroup
  • 状态动作
    StateComponent
    + 在
    AvatarStateAnimationComponent.StateToAvatarBodyActionSheet
    中注册
    ATTACK
    /
    HIT
    /
    DEAD
    等状态
  • HP处理:玩家使用
    PlayerComponent.Hp
    ,怪物使用自定义
    @Sync Hp
  • 方向判定:使用
    LookDirectionX
    (禁止使用Scale.x)
  • 时间基准:使用
    _UtilLogic.ElapsedSeconds
    (禁止使用os.clock)
  • 事件清理:在
    OnEndPlay
    中显式调用
    DisconnectEvent
    断开事件
  • Body规则:禁止对有Body激活的实体直接赋值
    TransformComponent.Position

14. 커스텀 구현이 필수

必须自定义实现的内容

Buff/Debuff · BT Decorator/Memory(Blackboard) · Aggro/Threat Table · 투사체 풀링 · 관통/최대 히트 수 · 경직 레벨 체계 · 자원(MP/Stamina/Rage) · 콤보·캔슬 윈도 · 가드/패링 · 세계→스크린 좌표 변환 · 월드스페이스 HP바

Buff/Debuff · BT Decorator/记忆(Blackboard) · 仇恨/威胁表 · 投射物池 · 穿透/最大命中数 · 僵直等级体系 · 资源(MP/耐力/怒气) · 连招/取消窗口 · 格挡/弹反 · 世界→屏幕坐标转换 · 世界空间HP条

비범위

非覆盖范围

  • 플레이어 전반(HP/이동/카메라/코스튬 외):
    msw-defaultplayer
  • mlua 일반 문법·라이프사이클:
    msw-scripting
  • .model
    저작 규칙·템플릿:
    msw-general
  • 玩家整体内容(HP/移动/相机/服装之外):
    msw-defaultplayer
  • mlua通用语法·生命周期:
    msw-scripting
  • .model
    创作规则·模板:
    msw-general