monster-doll-kit
v0.7.0
Published
关节式切件骨架成品包(青蛙骑士):18 件、四肢三段 × 前后两侧 + 头/肩甲/披风/剑,20 个动作(含三段连招、跳斩连击、翻滚、六个法杖招式)、6 顶可换的头 + 1 根可换的魔杖 + 4 套布料配色,Cocos Creator 3.8。npm 装包后跑 monster-doll-sync 把资源同步进工程 assets/resources/。
Readme
monster-doll 关节式骨架包
青蛙骑士:16 件切件 + 一把剑(握在近侧手上,骨骼名 sword,是 hand-front 的子骨),四肢三段 × 前后两侧(肩→肘→腕→指、髋→膝→踝),外加头、眼、嘴、披风、肩甲。
20 个动作。原版五个(idle walk run attack jump)+ 自己拼的十五个:
受创 hurt;近战 chop attack2 attack3 lunge roll airCombo(跳斩连击,空中三下);法杖 cast channel(循环)slam sweep summon blink barrier ultimate。
★attack attack2 attack3 是一套连招,三条接起来是一条连续的弧:劈 → 撩 → 重砸。
两件事让它连得上:① 二三段的底盘是一段的起手位,不是站姿(一段是 Spine 导进来的,
它那个架势和站姿差 55°~71°,从站姿起的话连着播就是"站好→挥→站好→挥");
② 二段的末帧不回起手位,就停在三段的起手位上。三处接缝逐骨对过,差 <0.6°。
★所以 attack2 单独播会停在举高的位置 —— 不接三段的话,游戏侧 crossFade 回 idle。
★airCombo 的腾空弧挂在 root 上、不是 hip —— 这样 measure-box 会把它排除在画布框外。
挂 hip 的话它会参与定框:实测最高点把 TOP 顶高 27px,RIG_PER_PX 从 2.91 变 3.06,
所有动作在屏上一起小 5%,为一个跳斩不值当。(原地跳 jump 是拼 Spine 那四张姿势来的,
arc 挂在 hip 上,那条至今仍在参与定框。)
★roll 带 root 转角(整只娃娃翻一圈),按 measure-box 的规矩不算进画布框 —— 所以离线渲染和预览页里它会被画布切到一点。游戏里没有画布这回事(root 是节点变换),不受影响。
零外部依赖——动作是 Cocos 原生 cc.AnimationClip,
法杖那几个动作都用同一个小函数 _segs 按帧拼时间线(一段一段"用多少帧走到哪个姿势"),写第三个的时候抽出来的。★channel 是循环动作,里面故意不放"举起来/放下去"两段 —— 循环播会变成反复抬手;整条 24 帧就是"持住 + 抖"(6 个来回,首尾同值),进出靠 crossFade。
cast 是举杖施法:举 10 帧 → 蓄 20 帧 → 推出 5 帧 → 收 13 帧,全长 48 帧 = 0.8s。蓄那一段全身发抖(逐帧插点,60fps 下 4 帧一个来回 = 15Hz;两端各留一帧不插,边界值还是"举到顶"那张,前后两段才接得上)。事件名是 cast 不是 hit —— hit 会把剑光那道月牙掏出来,法术不该出刀光。
chop 是举剑劈,四段按帧写(60fps):举 6 帧 → 停 30 帧 → 劈 6 帧 → 收 10 帧,全长 52 帧 = 0.8667s。停顿是两个关键帧同值,真的一动不动;命中事件跟着"劈到底"那一帧走(0.826),改帧数不用回头改事件。刀尖落点是量着定的 —— 再往下就扎进地面线以下了。
运行时只有一个 MonsterDoll 组件。由骨架仓库 RIG=monster python3 tools/pack-kit.py 打出,
skins.ts 是生成物,别手改。运行时脚本和 hero-doll-kit / ogre-doll-kit 是同一份代码、类名加了前缀,
三个包装进同一个工程不撞 @ccclass。
接入(Cocos Creator 3.8)
npm i monster-doll-kit
npx monster-doll-sync # 同步进 assets/resources/monster-doll/或者整个 monster-doll/ 文件夹连 .meta 一起拷进目标工程的 assets/resources/。
- 把
monster-doll.prefab拖进场景(或instantiate); - 根节点挂
MonsterDoll组件; - 代码:
const doll = node.getComponent(MonsterDoll);
doll.play('walk'); // idle / walk / run 循环,attack / jump 一次性
doll.crossFade('attack', 0.1);
doll.bone('arm-front-lower'); // 任意一根骨
doll.slot('weapon'); // 前手腕下的附件槽
node.on(MonsterDoll.EVENT, (name, clip, payload) => {}); // footstep / hit / land角色朝右,往左走把节点 scale.x 取负。骨骼名:
body head eye mouth shoulder cape fingers、
arm-{front,back}-{upper,lower} hand-{front,back}、
leg-{front,back}-{upper,lower} foot-{front,back}。
★整套骨架和动作都是从 Spine 官方 hero 示例原样搬过来的,不是手量的:
tools/spine-rig.py 读骨架 JSON,算出每根骨的挂点、偏移、绑定角、层级和绘制顺序,
并把每张贴图按 attachment.rotation 转正;tools/spine-import.py 搬五个动画。
画面换成青蛙那批图(任务表本来就是按 Spine 的部件清单画的,尺寸一一对得上),几何完全照 Spine。
★两种来源的贴图转的角度不一样:图集里的图按 attachment.rotation 转正,
自备的图(青蛙那批是照"角色身上最终什么样"画的)按骨的世界转角反向转回去。
套错的结果很直观 —— 腿会被多转一百多度,人看着像跪着。源数据留底在 sheets/spine-hero.json 和 sheets/spine-hero.atlas。
★骨架里多一根 hip:1×1 全透明的占位骨。留着它才保得住"转躯干不带动腿"这个层级 ——
合并掉的话,攻击里躯干前倾 32° 会把两条腿整个甩出去。
★贴图是预旋转过的。Spine 把"骨的角"和"图相对骨的角"分开存,本仓库一根骨只有一个角; 不转正的话,子骨的偏移会被祖先的贴图角一起转,位置全乱。
★踩地用 ground='seat'(整段坐地):Spine 已经把接地做在位移轨里了,
逐帧钉会把跑步的腾空相按回地面、把抬膝突刺硬压进地里。
★剑光:fx/mid/01 三帧月牙(借主角刃类档那套,原图不镜像,和 ogre 一致 ——
弧的凹面朝着角色才是挥砍扫过的轨迹;镜像过来会变成往回抽)。
运行时挂 MonsterDollFx 组件,它听 hit 帧事件在剑前方甩一道。
特效钉在哪、多大,由人物表里这三个数说了算,预览页和运行时读同一份
(tools/rigs/monster.py → 打包写进 skins.ts → 组件默认值),
不然就是"页面上摆好了、装进游戏又偏":
| 字段 | 这只 | 说明 |
| --- | --- | --- |
| FX_BONE | sword | 钉在剑这根骨上。默认是 hand-front,可这只的剑握在后手 —— 钉前手的话月牙甩在身上 |
| FX_OFF | 1.0 | 往前推 1 倍宽,月牙右缘正好落在刀尖外一点 |
| FX_WIDTH | 70 | 屏幕像素。比主角(50)大、比一开始试的 110 小:110 那档整道月牙罩住半个人 |
fxKey 同理默认取 skins.ts 的 FX_KEY(这里是 mid/01),不用手填 ——
写死默认值的话目录对不上就是"装了没反应还不报错"。
★原版骨架里没有披风、眼、嘴、手指这几个槽。披风是我们自己加的一根骨
(挂在躯干上、排在绘制顺序最前 = 画在最后面),写在 tools/rigs/monster.py 的 _CAPE 里 ——
不能写进生成出来的骨骼表,那份重导一次就没了。眼、嘴、手指没加:头图本来就画好了眼睛和嘴,
手指是给"盖在剑柄上"用的。
★原地跳是拼出来的。Spine 原版的 jump 不是动画,是一张静止姿势(每根骨只有 t=0 一个关键帧),
fall 也一样 —— 腾空高度是交给游戏物理去做的,直接导进来就是"跳不起来"。
这里拿它自己的 idle / crouch / jump / fall 四张姿势排成一条时间线
(站 → 蹲 → 蹬伸 → 顶点 → 下落 → 落地缓冲 → 站直),再补一条髋的抛物线,腾空约 185 个单位。
要改高度就改 tools/rigs/monster.py 里的 _ARC。
★拼的时候角度必须按最短路展开:Spine 存的是绕了圈的绝对值 —— 蹲姿里前脚是 270.1
(其实就是 −89.9),从站姿的 0 直接线性插过去,脚会转大半圈,看着像翻了个面。
原版不出这问题,是因为那几张本来就是静止姿势、根本不插值。
接进游戏时如果你自己用物理驱动高度,把 _ARC 清零即可,姿势照样能用。
★素材来自 sheets/task-sheet-frog-head.png 里 Hero 那一档(Spine 官方 examples 的青蛙骑士),
用 tools/cut-cards.py 从卡片网格切的。每件只有 12 到 172 像素,放大会糊;要更清楚就重出一张单件大图再切。
头图自带眼睛和嘴,eye / mouth 是叠在上面的表情片,跟着头转。
★武器也能换:现成一根魔杖(doll.equip('weapon', 1),0 换回原件那把剑)。出图要求和头一样是构图定死的 —— 横放、尖端朝右、握把在 17% 宽 / 50% 高,满足就能直接换上。
★头是可换的,现成六顶:青蛙骑士(原件)/ 地府蛙魔 / 地府牛魔 / 金羽盔 / 熔岩牛魔 / 赤缨鬼将 —— doll.equip('head', 1..6),0 穿回原件(= 第 1 顶)。
两颗魔头来自 sheets/head-underworld-*.png(单图棋盘格底,tools/cut-parts.py 抠,keying.py 认「浅色底」),抠完当 spine-rig.py 的换皮贴图喂进去:拉伸到 Spine 声明的 172×173 再转正,出来永远是 184×185 —— 和原件同尺寸同挂点,所以换装表里的 piv/scale 照抄原件,不用像主角那 30 顶盔一样逐顶算。做法和注意事项写在 tools/rigs/monster_skins.py 的开头。
★预览页上有「换皮」那张卡,点一下就换头;换的只是贴图,骨架和六个动作一个字不动。
★换装件还能做逐动作微调(SKINS[...].clips):同一件在不同动作里位置差一点 —— 熔岩牛魔在走路/跑步里就比站着更靠前。为什么要单开这一维:换装只换两样东西(贴图、挂点),而贴图一份、所有动作共用,"这一件 + 这个动作"是两维的,烘进贴图做不到。
运行时在 play() / crossFade() 里按表把这一件的挂点和自转重设一遍 —— 不重新加载贴图,所以每次切动作都调是廉价的;转的是贴图那一层节点,动画绑的是 <部件>-bone 的角和 <部件>-fx 的缩放,互不打架。
表里写的还是预览页面板给的三个数 (Δ角, Δ横, Δ竖),换算成挂点+自转由 hero_rig.skin_clip_tweak 一处负责,pack-kit 和预览页读同一条,不会走偏。
第 4、5 顶(金羽盔 / 熔岩牛魔)是照构图要求出的图(朝右、脸的中线在画面 45%、下颌在 92%),所以挂点不用单量 —— 转正之后正好落回和前三顶一样的 (84,164)。
★出新头时把这两个百分比写进提示词,能省掉「每换一张就得量一次挂点」这一步;朝向也一样,画反了就得在转正之前做镜像。
★布料还有四套配色(赤红 / 靛蓝 / 苔绿 / 紫檀):doll.equip('cloth', 1..4),一套换九件(披风 + 两条手臂上段和手 + 两条腿上段和脚)。白甲、肩甲、剑和头不动 —— 换色只动暖色(皮革的棕、披风的金),靠色相分,不靠饱和度:这套贴图的白甲暗部是蓝的(色相 205),按饱和度切会把整身甲一起染了。出图:RIG=monster python3 tools/recolor-parts.py,换哪几件、换成什么色写在 tools/rigs/monster_skins.py 的 CLOTH / CLOTH_COLORS。
★贴图和预制体的 .meta 是脚本生成的,不是 Creator 导出的。首次导入请看一眼预制体里贴图有没有掉。
