关于 msw-defaultplayer
msw-defaultplayer 是面向 MapleStory Worlds 的技能,使用 ModelBuilder 检查和修改 DefaultPlayer 模型,供游戏创作者配置玩家组件及移动、物理、HP 和摄像机设置。
主要功能
- 01检查并修改 DefaultPlayer 模型
- 02管理玩家组件
- 03配置移动与物理属性
- 04调整 HP 和摄像机设置
- 05了解玩家运行时层级
适用场景
- 01修改玩家移动或跳跃设置
- 02调整摄像机跟踪和 HP
- 03添加或移除玩家组件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ msw-git/ msw-ai-coding-plugins-official --skill msw-defaultplayer安装后在 Claude Code 中输入/msw-defaultplayer确认已加载。
详细介绍
MSW 默认玩家
使用 msw-general ModelBuilder 检查或修改 DefaultPlayer 模型文件、管理组件,并配置移动/物理/HP/摄像机。
对于服装/虚拟形象装备,请参阅
msw-avatar技能。服装不仅适用于 DefaultPlayer,也适用于任何实体,因此归入单独的技能。
DefaultPlayer 概览
什么是 DefaultPlayer?
MapleStory Worlds Maker 工作区默认提供的玩家角色模型。
- 任何用户进入世界时,都会基于此模型创建一个玩家实体。
- 要使用的模型 ID 由
DefaultUserEnterLeaveLogic的PlayerUri属性指定。
文件位置和结构
DefaultPlayer 由两个 .model 文件组成:
| 文件 | 路径 | 作用 |
|---|---|---|
| Player.model | ./Global/Player.model | 基础模型。定义 Components 列表和 Properties 链接 |
| DefaultPlayer.model | ./Global/DefaultPlayer.model | 继承 Player(BaseModelId: "player")。覆盖 Values |
重要:这两个文件都位于
./Global/中。自定义脚本文件创建于./RootDesk/MyDesk/下。
通过 ModelBuilder 修改 DefaultPlayer
DefaultPlayer 通过同级目录中的 msw-general/scripts/model/msw_model_builder.cjs 管理,而不是直接编辑原始 JSON。
- 更改属性值:
ModelBuilder.read("./Global/DefaultPlayer.model").value(...) - 添加/移除组件:
component()/removeComponent() - 查看基础组件列表:
ModelBuilder.snapshot("./Global/Player.model")
文件结构详情
Player.model(基础模型)
Path: ./Global/Player.model
EntryKey: model://player
Components:玩家默认组件的完整列表(MOD.Core.* 原生组件)Properties:模型属性 → 组件属性链接定义(可在检查器中编辑的属性)Values:为空(默认值由引擎提供)
DefaultPlayer.model(覆盖模型)
Path: ./Global/DefaultPlayer.model
EntryKey: model://defaultplayer
BaseModelId: "player"
Components:仅包含 DefaultPlayer 上新增的组件(例如script.PlayerHit、script.PlayerAttack)Values:被覆盖设置值的数组
DefaultPlayer 默认组件列表
从 Player.model 继承的原生组件:
| 组件 | 作用 |
|---|---|
| TransformComponent | 位置、旋转、缩放 |
| MovementComponent | 移动速度和跳跃力度控制 |
| RigidbodyComponent | 物理(重力、踏脚点)、MapleStory 风格的移动 |
| KinematicbodyComponent | 在 RectTileMap 上进行上下左右移动 |
| SideviewbodyComponent | 在 SideViewRectTileMap 上进行横版移动 |
| StateComponent | 状态机(Walk、Jump、Dead 等) |
| AvatarRendererComponent | 虚拟形象渲染、颜色、表情 |
| AvatarStateAnimationComponent | 状态 → 虚拟形象动画映射 |
| CostumeManagerComponent | 装备/服装管理 → 详情请参阅 msw-avatar 技能 |
| CameraComponent | 摄像机跟踪设置 |
| PlayerControllerComponent | 输入到动作的映射、条件处理 |
| PlayerComponent | HP、死亡/复活、PVP、地图移动 |
| ChatBalloonComponent | 聊天气泡 |
| NameTagComponent | 名称标签 |
| DamageSkinSettingComponent | 伤害皮肤 |
| DamageSkinSpawnerComponent | 伤害皮肤生成 |
| HitEffectSpawnerComponent | 受击效果生成 |
| TriggerComponent | 碰撞检测 |
| InventoryComponent | 背包 |
DefaultPlayer.model 中添加的脚本组件:
| 组件 | 作用 |
|---|---|
| script.PlayerHit | 玩家受击处理逻辑 |
| script.PlayerAttack | 玩家攻击逻辑 |
快速参考 — 关键组件
| 组件 | 作用 | 关键属性 / 方法 |
|---|---|---|
| PlayerComponent | HP、死亡 / 复活、PVP、地图移动 | Hp, MaxHp, PVPMode, RespawnDuration, RespawnPosition, UserId, IsDead(), ProcessDead(), ProcessRevive(), MoveToMapPosition() |
| PlayerControllerComponent | 输入 → 动作映射、条件控制 | SetActionKey(key, actionName), ActionAttack(), ActionJump(), LookDirectionX |
| MovementComponent | 高级移动速度 / 跳跃接口 | InputSpeed(默认值为 1.0)、JumpForce(默认值为 1)、Jump(), Stop() |
| RigidbodyComponent | Maple 侧视物理(重力 / 落脚点) | Gravity, WalkAcceleration, WalkSpeed, AddForce(), IsOnGround() |
| KinematicbodyComponent | RectTile 上的俯视上下左右移动 | (仅限 RectTile 地图模式) |
| SideviewbodyComponent | SideViewRectTile 上的侧视移动 | (仅限 SideViewRectTile 地图模式) |
| AvatarRendererComponent | Avatar 渲染 / 颜色 / 表情 | SetColor(), SetAlpha(), PlayEmotion(), PlayRate |
| StateComponent | 状态机(Walk/Jump/Dead) | CurrentStateName, ChangeState(), DeadEvent/ReviveEvent |
| NameTagComponent | 名称标签 | Name, FontSize, FontColor, NameTagRUID |
| ChatBalloonComponent | 聊天气泡 | Message, ChatModeEnabled, ShowDuration |
| CameraComponent | 摄像机跟踪 | DeadZone, SoftZone, Damping, ScreenOffset |
| TriggerComponent | 碰撞检测 | BoxSize, Offset, CollisionGroup |
DefaultPlayer Values 结构
DefaultPlayer.model 的 Values 数组中每个条目的格式:
{
"TargetType": "<component name> or null",
"Name": "<property name>",
"ValueType": {
"$type": "MODNativeType",
"type": "<type info>"
},
"Value": <value>
}
TargetType 规则
null:Player.model 的 Properties 中定义的模型属性(通过 Properties 链接到实际组件属性)"MOD.Core.<ComponentName>":直接覆盖特定原生组件上的属性"script.<ScriptName>":自定义脚本组件的属性
模型属性(TargetType: null)
通过 Player.model 的 Properties 中定义的链接,映射到实际组件属性。
| 模型属性名称 | 源组件.属性 | 说明 | 默认值 |
|---|---|---|---|
| speed | MovementComponent.InputSpeed | 移动速度 | 1.0 |
| jumpForce | MovementComponent.JumpForce | 跳跃高度 | 1.0 |
| walkAcceleration | RigidbodyComponent.WalkAcceleration | 加速 / 减速 | 1.0 |
| gravity | RigidbodyComponent.Gravity | 重力 | 1.0 |
| cameraDeadZone | CameraComponent.DeadZone | 摄像机死区 | {x: 0.052, y: 0.08} |
| cameraSoftZone | CameraComponent.SoftZone | 摄像机软区 | {x: 0.268, y: 0.7} |
| cameraDamping | CameraComponent.Damping | 摄像机平滑跟随 | {x: 2.5, y: 3.9} |
| cameraScreen | CameraComponent.ScreenOffset | 死区中心点 | {x: 0.5, y: 0.655} |
| cameraDutch | CameraComponent.DutchAngle | 摄像机旋转 | 0.0 |
| cameraOffset | CameraComponent.CameraOffset | 摄像机位置偏移 | {x: 0.0, y: 0.0} |
| message | ChatBalloonComponent.Message | 聊天气泡消息 | "" |
| chatModeEnabled | ChatBalloonComponent.ChatModeEnabled | 是否处理聊天(例如显示气泡) | true |
| nameTag | NameTagComponent.Name | 名称标签 | "" |
| damageSkinId | DamageSkinSettingComponent.DamageSkinId | 伤害皮肤类型 | DataRef |
| damageDelayPerAttack | DamageSkinSettingComponent.DelayPerAttack | 伤害延迟 | 0.05 |
| triggerBodyBoxSize | TriggerComponent.BoxSize | 碰撞检测区域大小 | {x: 0.66, y: 0.7} |
| triggerBodyBoxOffset | TriggerComponent.BoxOffset | 碰撞检测区域偏移 | {x: 0.0, y: 0.35} |
| triggerBodyColliderOffset | TriggerComponent.ColliderOffset | 碰撞体偏移 | {x: 0.0, y: 0.35} |
| maxHp | PlayerComponent.MaxHp | 最大 HP | 1000 |
直接覆盖组件(TargetType:特定组件)
直接覆盖组件属性,而不通过模型属性链接的值:
| TargetType | Name | Description | Default |
|---|---|---|---|
| MOD.Core.CameraComponent | ZoomRatioMax | 摄像机最大缩放比例 | 500.0 |
| MOD.Core.MovementComponent | JumpForce | 跳跃力度(直接覆盖) | 1.0 |
| MOD.Core.MovementComponent | InputSpeed | 移动速度(直接覆盖) | 1.0 |
| script.PlayerHit | CollisionGroup | 命中碰撞组 | CollisionGroup ID |
| script.PlayerHit | BoxSize | 命中碰撞区域大小 | {x: 0.45, y: 0.7} |
| script.PlayerHit | ColliderOffset | 命中碰撞偏移量 | {x: 0.0, y: 0.35} |
各地图模式下的移动组件
瓦片地图模式与 Body 的映射表请参阅
msw-general/references/platform.md§4。根据地图模式,RigidbodyComponent / KinematicbodyComponent / SideviewbodyComponent 中的一个会处于激活状态。
识别玩家(供脚本引用)
entity.PlayerComponent ~= nil→ 判断实体是否为玩家_UserService.LocalPlayer→ 我的玩家实体(仅客户端)_UserService:GetUserEntityByUserId(userId)→ 特定用户的玩家实体
玩家实体的运行时结构(根实体与子实体)
生成的玩家并非单个扁平实体。运行时,引擎会在玩家根实体下构建一个小型层级结构,且头像动作选择器位于孙级实体上,而非根实体上。这会影响组件的查找方式以及触发头像姿势的方式。
组件 → 实体映射
| Component | 所在位置 | 查找方式 |
|---|---|---|
PlayerComponent | 根实体 | player:GetComponent("PlayerComponent")(或 player.PlayerComponent) |
StateComponent | 根实体 | player:GetComponent("StateComponent") |
MovementComponent | 根实体 | player:GetComponent("MovementComponent") |
AvatarRendererComponent | 根实体 | player.AvatarRendererComponent |
AvatarStateAnimationComponent | 根实体 | player:GetComponent("AvatarStateAnimationComponent") |
PlayerControllerComponent | 根实体 | player.PlayerControllerComponent |
AvatarBodyActionSelectorComponent | 根实体的 Body 孙级实体(位于头像根实体下) | 无法通过 player:GetComponent(...) 访问——见下文 |
AvatarFaceActionSelectorComponent | 根实体的 Face 孙级实体 | 无法通过 player:GetComponent(...) 访问——见下文 |
player:GetComponent("AvatarBodyActionSelectorComponent") 会返回 nil,且 LSP 不会发出警告(签名为 Component,而非可空类型)。只有在运行时才能看到此失败。
如何访问选择器
-- ClientOnly context (recommended — the direct API)
local body = self.Entity.AvatarRendererComponent:GetBodyEntity()
local face = self.Entity.AvatarRendererComponent:GetFaceEntity()
local bodySelector = body and body:GetComponent("AvatarBodyActionSelectorComponent")
local faceSelector = face and face:GetComponent("AvatarFaceActionSelectorComponent")
-- Server or "either side" context (GetBodyEntity / GetFaceEntity are ClientOnly)
local bodySelector = self.Entity:GetFirstChildComponentByTypeName(
"AvatarBodyActionSelectorComponent", true)
AvatarRendererComponent:GetBodyEntity()和GetFaceEntity()声明为@ExecSpace("ClientOnly")——从服务端方法调用时会返回nil。跨端的备用方案是使用GetFirstChildComponentByTypeName(name, recursive=true)。
触发头像姿势——使用 StateComponent,绝不要直接写入选择器
运行中的玩家每个 tick 都会执行一个状态机:PlayerControllerComponent 评估输入/移动 → StateComponent 转换状态(IDLE / MOVE / 等)→ AvatarStateAnimationComponent.ReceiveStateChangeEvent 将其转换为 BodyActionStateChangeEvent → 选择器的 ActionState 被重写。
这意味着直接写入 AvatarBodyActionSelectorComponent.ActionState 会被静默覆盖:该值只生效一帧,接着下一个状态机 tick 会将当前 StateComponent 状态映射回选择器,你写入的值便消失了。赋值后,日志会立即打印 ActionState=Attack,但在游戏模式下,姿势只会闪现一帧,随后消失。
正确的入口点
local state = self.Entity:GetComponent("StateComponent")
state:ChangeState("ATTACK") -- ActionSheet keys are UPPERCASE
状态键来自玩家的 ActionSheet。DefaultPlayer 自带 11 个大写键,每个键都映射到一个默认动画:
StateComponent:ChangeState(...) 键 | 默认动画 |
|---|---|
"IDLE" | stand |
"MOVE" | walk |
"ATTACK" | attack |
"HIT" | hit |
"CROUCH" | crouch |
"FALL" | fall |
"JUMP" | fall |
"CLIMB" | rope |
"LADDER" | ladder |
"DEAD" | dead |
"SIT" | sit |
动作结束后,状态机将自动返回 IDLE,无需手动设置计时器恢复状态。
大小写陷阱:传给
ChangeState的字符串键必须是大写("ATTACK")。直接写入selector.ActionState的枚举值(NPC 路径——见下文)则是MapleAvatarBodyActionState.Attack,采用 PascalCase。这是独立的 API,但对应相同的底层状态。字符串键大小写错误("attack"/"Attack")会导致 ActionSheet 映射失效,且不会发出警告。
何时可以直接写入 selector?
仅适用于没有运行中的 PlayerControllerComponent + StateComponent + AvatarStateAnimationComponent 组件栈的实体,例如使用 avatar 渲染器显示视觉效果、但没有输入控制器驱动状态机的 NPC / 怪物。对于这些实体,selector.ActionState = MapleAvatarBodyActionState.<Pose> 会生效。对于 DefaultPlayer 结构的实体,则应改为调用 StateComponent:ChangeState(...)。
常用服务一览(脚本参考)
| 服务 | 作用 | 主要 API |
|---|---|---|
| _UserService | 用户管理、进入 / 离开 | LocalPlayer、UserEntities、GetUserEntityByUserId()、UserEnterEvent/UserLeaveEvent |
| _TeleportService | 传送 / 地图移动 | TeleportToEntity()、TeleportToMapPosition()、WarpUserToWorldAsync() |
| _CameraService | 摄像机控制 | SwitchCameraTo()、ZoomTo()、ZoomReset() |
| DefaultUserEnterLeaveLogic | 用户进入 / 离开逻辑 | PlayerUri(玩家模型 ID)、StartPoint(起始地图) |
如何修改 DefaultPlayer
修改属性值(Values)
使用 ModelBuilder.read() 加载 ./Global/DefaultPlayer.model,然后通过 value() 更新值。
示例:将移动速度设为 2.0
const { ModelBuilder } = require("../msw-general/scripts/model/msw_model_builder.cjs");
const b = ModelBuilder.read("./Global/DefaultPlayer.model");
b.value(null, "speed", 2.0, "float")
.value("MovementComponent", "InputSpeed", 2.0, "float")
.write("./Global/DefaultPlayer.model");
注意:模型属性(
TargetType: null、Name: "speed")和直接组件覆盖项(TargetType: "MOD.Core.MovementComponent"、Name: "InputSpeed")可能同时存在。请通过value()将二者设置为一致的值。
示例:跳跃力度设为 1.5,HP 设为 2000
const b = ModelBuilder.read("./Global/DefaultPlayer.model");
b.value(null, "jumpForce", 1.5, "float")
.value("MovementComponent", "JumpForce", 1.5, "float")
.value(null, "maxHp", 2000, "int")
.write("./Global/DefaultPlayer.model");
添加新的 Values 条目
使用 ModelBuilder.value(targetType, name, value, typeKey)。构建器会生成 ValueType 描述符;不要手动编写类型字符串。
常见的 typeKey 值:bool、int、float、double、string、vector2、vector3、data_ref、collision_group。
添加组件
对 ./Global/DefaultPlayer.model 使用 component()。
只添加未从 Player.model 继承的组件。对于继承的原生组件(PlayerComponent、MovementComponent、CameraComponent、StateComponent 等),请使用 value(...) 覆盖值,而不是重新声明组件。如果添加的组件已从 BaseModelId: "player" 继承,ModelBuilder 会发出警告(M040)。
添加自定义脚本组件:
const b = ModelBuilder.read("./Global/DefaultPlayer.model");
b.component("script.MyCustomComponent")
.write("./Global/DefaultPlayer.model");
自定义脚本(.mlua)必须创建在
./RootDesk/MyDesk/下。先编写脚本,再由 Maker 执行refresh,然后使用构建器添加"script.<ScriptName>"。
添加未继承的原生组件:
const b = ModelBuilder.read("./Global/DefaultPlayer.model");
b.component("SpriteRendererComponent")
.write("./Global/DefaultPlayer.model");
移除组件
对 DefaultPlayer.model 使用 removeComponent()。构建器会移除相关的 Values 条目。
注意:从 Player.model(基模型)继承的组件不会出现在 DefaultPlayer.model 的 Components 中。移除基模型组件需要通过
ModelBuilder修改Player.model,通常不建议这样做。
常见陷阱(常见错误)
在 DefaultPlayer.model 中添加组件和更改值时的常见错误。
组件列表相关错误
| # | 错误 | 现象 | 解决方法 |
|---|---|---|---|
| C1 | 添加的 script.XXX 消失或未生效 | 如果某个脚本组件未注册在同一目录中对应的 .codeblock 元数据里,加载时会被静默丢弃;如果在此状态下保存,该组件将永久丢失 | 编写 .mlua 后,使用 Maker Refresh 自动生成 .codeblock。或者在实体生成后立即通过 entity:AddComponent("Name") 在运行时添加 |
| C2 | 重复添加 Player.model 上已有的原生组件(例如 MOD.Core.MovementComponent) | 只会发出重复组件警告,不会阻止添加 → 工作区警告不断累积,行为变得不确定 | 添加前检查基础组件列表(§65-89)。如果组件已存在,只需通过 Values 更改设置 |
| C3 | 移除 script.PlayerHit / script.PlayerAttack | 这是 DefaultPlayer 附带的仅有额外脚本。移除它们会导致失去受击免疫 / 攻击逻辑 | 如果想禁用这些功能,请切换脚本内的逻辑,或在 Values 中设置 Enable=false |
| C4 | 禁用 AvatarRendererComponent 并添加 SpriteRendererComponent(或替换为其他渲染器) | 如果 Avatar 和 Sprite 渲染器同时处于活动状态,就会出现 Z-fighting / 服装未应用的问题 | 仅在禁用 Avatar 后添加 Sprite(参见 §395 中的模式) |
| C5 | 自定义伤害流程只减少 HP 属性(或只广播伤害外观事件)——引擎的受击 / 死亡流程不会触发 | Avatar 状态机响应的是 StateChangeEvent,而不是属性写入。伤害数字 / 粒子都能正常显示,但 Avatar 在受击 / 死亡 / 复活期间仍保持空闲状态——视觉效果无声失效,且不会记录错误日志 | 首选方案:通过 HitComponent:OnHit(attacker, damage, isCrit, attackInfo, hitCount) 处理伤害。随后 script.PlayerHit 会自动处理受击 / 死亡 / 重生状态转换。必须手动处理伤害时(持续引导 / 光环 / 脚本控制):将 StateComponent:ChangeState("HIT") 用于受击姿势,并配合 PlayerComponent:ProcessDead() / ProcessRevive() 处理死亡和复活流程。不要只修改 HP——Avatar 不会有任何反应。 |
| C6 | 在启用了 AvatarRendererComponent 的实体(例如 DefaultPlayer)上设置 SpriteRendererComponent.Color / FlipX | 组件确实存在,GetComponent 返回非 nil,但 Sprite 输出被 Avatar 渲染器自身的渲染流程遮挡——颜色 / 翻转写入会静默失效。同样的操作在纯 Sprite 渲染的实体上有效,因此首次复制粘贴时会失败,且不会出现任何警告 | 使用 AvatarRendererComponent:SetColor(r, g, b, a)(0–1 浮点数)调整色调,并使用 :SetAlpha(a) 淡出。两者均为 ClientOnly。如需改变朝向,请通过 MovementComponent.MoveDirection(或游戏逻辑中的朝向 API)控制角色,而不是使用 sprite.FlipX |
Values 变更注意事项 — 只有 jumpForce / speed 需要额外注意
大多数 Values 条目都采用 TargetType=null(别名)形式,可以通过 ModelBuilder.value(null, ...) 设置。只有以下两个字段例外——别名条目和原生条目(TargetType="MOD.Core.MovementComponent")同时存在:
| 字段 | 别名条目 | 原生条目 |
|---|---|---|
| 跳跃力 | jumpForce(TargetType=null) | JumpForce(TargetType="MOD.Core.MovementComponent") |
| 移动速度 | speed(TargetType=null) | InputSpeed(TargetType="MOD.Core.MovementComponent") |
生成实体时,Values 会按数组顺序应用,且两者都会写入同一个原生字段;原生条目在数组中出现得更晚,因此原生值会生效。
- 错误:只修改别名一侧(
jumpForce/speed)→ 会被后面的原生条目覆盖并忽略 - 正确:将两者都改为相同的值,或只修改原生一侧(
JumpForce/InputSpeed)
其他仅有别名的条目(walkAcceleration、gravity、与摄像机相关的条目(cameraDeadZone 除外)、nameTag、damageSkinId、damageDelayPerAttack、triggerBody*、maxHp 等)可以直接通过别名修改。
隐藏 DefaultPlayer
DefaultPlayer 的组件继承自基础模型,因此无法删除。唯一的选择是通过 Enable=false 禁用它们。
组件保留/禁用分类
| 组件 | 完全隐藏 | 仅隐藏外观 | 备注 |
|---|---|---|---|
| TransformComponent | 保留 | 保留 | 必需 |
| PlayerComponent | 保留 | 保留 | 必需——禁用会导致进入失败 |
| StateComponent | 保留 | 保留 | 禁用会导致其他组件报错 |
| MovementComponent | 保留 | 保留 | 需要移动功能时保留 |
| CameraComponent | 保留 | 保留 | 需要摄像机时保留 |
| AvatarRendererComponent | 禁用 | 禁用 | 关键——仅禁用此项即可隐藏外观 |
| AvatarStateAnimationComponent | 禁用 | 禁用 | |
| CostumeManagerComponent | 禁用 | 禁用 | |
| PlayerControllerComponent | 禁用 | 保留 | 取决于是否需要阻止移动 |
| ChatBalloonComponent | 禁用 | 禁用 | |
| NameTagComponent | 禁用 | 禁用 | |
| DamageSkinSettingComponent | 禁用 | 禁用 | |
| DamageSkinSpawnerComponent | 禁用 | 禁用 | |
| HitComponent | 禁用 | 禁用 | |
| HitEffectSpawnerComponent | 禁用 | 禁用 | |
| TriggerComponent | 禁用 | 禁用 | |
| InventoryComponent | 禁用 | 禁用 | |
| RigidbodyComponent | 禁用 | 根据地图模式保留 | 在 MapleTile 地图上时 |
| SideviewbodyComponent | 禁用 | 根据地图模式保留 | 在 SideViewRectTile 地图上时 |
| KinematicbodyComponent | EnableShadow=false | EnableShadow=false | 仅移除阴影 |
Builder 编辑 — 在 Values 中添加 Enable=false
通过 ModelBuilder.value() 设置组件值。对于尚无 Enable 条目的组件,Builder 会添加该条目。
const { ModelBuilder } = require("../msw-general/scripts/model/msw_model_builder.cjs");
const b = ModelBuilder.read("./Global/DefaultPlayer.model");
b.enable("AvatarRendererComponent", false)
.value("KinematicbodyComponent", "EnableShadow", false, "bool")
.write("./Global/DefaultPlayer.model");
保存后,必须执行 Maker Refresh。
DefaultPlayer 组件扩展模式
- 非外观玩家:禁用 AvatarRendererComponent → 添加 SpriteRendererComponent → 设置 SpriteRUID。
- 碰撞设置:调整 TriggerComponent 的 Values 中的 ColliderType 和 CollisionGroup。
- SpawnLocation:在地图(.map)文件中放置 Special → SpawnLocation(复活位置)。
工作流
修改玩家基本属性(移动速度、跳跃力、HP 等)
1. Load ./Global/DefaultPlayer.model with ModelBuilder.read()
2. Update values with value(targetType, name, value, typeKey)
3. If both the model property (TargetType: null) and the direct component override exist, set both consistently
4. write("./Global/DefaultPlayer.model")
为玩家添加自定义脚本
1. Write a new .mlua script under ./RootDesk/MyDesk/ (see the msw-scripting skill)
2. Maker refresh so the script type is registered
3. Load ./Global/DefaultPlayer.model with ModelBuilder.read()
4. Add "script.<ScriptName>" with component()
5. If needed, add default property values for the script with value()
6. write("./Global/DefaultPlayer.model")
7. Request Maker Refresh
更改摄像机设置
1. Load ./Global/DefaultPlayer.model with ModelBuilder.read()
2. Set cameraDeadZone, cameraSoftZone, cameraDamping, cameraScreen, cameraDutch, cameraOffset with value()
3. write("./Global/DefaultPlayer.model")
限制与注意事项
范围内
- 通过 ModelBuilder 检查/修改 DefaultPlayer/Player 模型文件
- 通过
component()/removeComponent()添加/移除组件 - 通过
value()设置移动/物理/HP/摄像机参数
范围外
- 服装/头像装备 →
msw-avatar技能 - UI 编辑器 →
./ui/下的 .ui 文件(专用技能) - 地图编辑 →
./map/下的 .map 文件(专用技能,包括 NPC/怪物生成点) - 通用脚本/资源 → 各自的专用技能
限制
- 谨慎处理 Global/:DefaultPlayer.model 和 Player.model 位于
./Global/。此文件夹用于存放引擎默认模板,因此不建议在此处创建新文件。 - 自定义脚本位置:新脚本文件必须创建在
./RootDesk/MyDesk/下。 - 地图模式注意事项:当前使用的移动组件因地图模式(MapleTile/RectTile/SideViewRectTile)而异。
- ValueType 正确性:添加 Values 条目时,请使用带有显式
typeKey的 ModelBuilder.value();不要手动编写ValueType。 - Maker Refresh:添加/修改脚本后,必须执行 Maker Refresh(.codeblock 会自动生成)。