独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多段铰接式柔性底盘 · 台阶攀爬原理动画</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{background:#0d1117;display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh;font-family:-apple-system,'Segoe UI',sans-serif;color:#c9d1d9;overflow:hidden}
.title{font-size:1.2rem;margin-bottom:8px;color:#8b949e;text-align:center;letter-spacing:1.5px}
.container{width:96vw;max-width:1200px;background:linear-gradient(145deg,#111820,#161d27);border-radius:12px;padding:6px;box-shadow:0 6px 28px rgba(0,0,0,.6);border:1px solid rgba(255,255,255,.04)}
svg{width:100%;height:auto;display:block}
#chassis_rear_pivot,#chassis_front_pivot{transform-origin:0 0}
#cargo_platform{transform-origin:0 0}
.wheel-spoke{transform-origin:0 0}
#gyro_spinner{transform-origin:0 0}
.bar{margin-top:8px;display:flex;gap:12px;flex-wrap:wrap;justify-content:center}
.bar .it{background:rgba(255,255,255,.05);padding:5px 12px;border-radius:5px;font-size:.75rem;border:1px solid rgba(255,255,255,.06)}
.bar .it b{color:#FF6B35;font-weight:600}
.rbtn{margin-top:8px;padding:7px 22px;background:#FF6B35;color:#fff;border:none;border-radius:5px;cursor:pointer;font-size:.82rem;font-weight:600;transition:background .2s}
.rbtn:hover{background:#e05520}
</style>
</head>
<body>
<p class="title">多段铰接式柔性底盘 · 毛毛虫式蠕动攀爬原理</p>
<div class="container">
<svg id="scene" viewBox="0 0 1200 650">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#0d1117"/><stop offset="100%" stop-color="#161d27"/></linearGradient>
<linearGradient id="bG" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#3A8BC5"/><stop offset="100%" stop-color="#1C5A8A"/></linearGradient>
<linearGradient id="pG" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#56C45E"/><stop offset="100%" stop-color="#348F3A"/></linearGradient>
<filter id="gl"><feGaussianBlur stdDeviation="3.5" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
<filter id="sh"><feDropShadow dx="1" dy="3" stdDeviation="3" flood-color="#000" flood-opacity=".35"/></filter>
</defs>
<!-- Background -->
<rect width="1200" height="650" fill="url(#bg)"/>
<!-- Subtle grid -->
<g opacity=".03" stroke="#fff" stroke-width=".5">
<line x1="0" y1="100" x2="1200" y2="100"/><line x1="0" y1="200" x2="1200" y2="200"/>
<line x1="0" y1="300" x2="1200" y2="300"/><line x1="0" y1="400" x2="1200" y2="400"/>
<line x1="0" y1="500" x2="1200" y2="500"/><line x1="0" y1="600" x2="1200" y2="600"/>
</g>
<!-- Terrain -->
<g id="terrain">
<rect x="0" y="500" width="1200" height="150" fill="#1e1a14" rx="0"/>
<rect x="0" y="498" width="650" height="3" fill="#3a3228" rx="1"/>
<rect x="650" y="420" width="550" height="80" fill="#1e1a14"/>
<rect x="650" y="418" width="550" height="3" fill="#3a3228" rx="1"/>
<rect x="648" y="420" width="5" height="80" fill="#2a2418"/>
<line x1="650" y1="420" x2="650" y2="500" stroke="#4a3f32" stroke-width="1.5"/>
<line x1="650" y1="420" x2="1200" y2="420" stroke="#4a3f32" stroke-width="1"/>
</g>
<!-- Step height annotation -->
<g opacity=".45">
<line x1="632" y1="420" x2="632" y2="500" stroke="#FF6B35" stroke-width="1" stroke-dasharray="3,3"/>
<line x1="628" y1="420" x2="636" y2="420" stroke="#FF6B35" stroke-width="1"/>
<line x1="628" y1="500" x2="636" y2="500" stroke="#FF6B35" stroke-width="1"/>
<text x="626" y="464" font-size="10" fill="#FF6B35" text-anchor="end">h</text>
</g>
<!-- Phase label -->
<rect x="370" y="18" width="460" height="34" rx="7" fill="rgba(0,0,0,.55)" stroke="rgba(255,255,255,.08)" stroke-width="1"/>
<text id="phaseLabel" x="600" y="41" text-anchor="middle" font-size="15" fill="#e6edf3" font-weight="600">① 平地行驶</text>
<!-- Angle readout -->
<g id="angleReadout" opacity="0">
<rect x="16" y="70" width="130" height="30" rx="5" fill="rgba(255,107,53,.15)" stroke="#FF6B35" stroke-width=".8"/>
<text id="angleVal" x="81" y="90" text-anchor="middle" font-size="13" fill="#FF6B35" font-weight="600">弯折角: 0°</text>
</g>
<!-- Force arrow (appears during climbing) -->
<g id="forceArrow" opacity="0">
<line x1="0" y1="0" x2="0" y2="-40" stroke="#4CAF50" stroke-width="2.5" marker-end="url(#arrowHead)"/>
<text x="14" y="-18" font-size="10" fill="#4CAF50" font-weight="600">摩擦力</text>
</g>
<defs><marker id="arrowHead" markerWidth="7" markerHeight="5" refX="6" refY="2.5" orient="auto"><polygon points="0 0,7 2.5,0 5" fill="#4CAF50"/></marker></defs>
<!-- Platform level indicator -->
<g id="levelIndicator" opacity="0">
<line x1="0" y1="0" x2="40" y2="0" stroke="#FFD700" stroke-width="1.5" stroke-dasharray="4,2"/>
<text x="48" y="4" font-size="9" fill="#FFD700">水平</text>
</g>
<!-- ======================== VEHICLE ======================== -->
<g id="vehicle" filter="url(#sh)">
<!-- ===== REAR CHASSIS PIVOT ===== -->
<g id="chassis_rear_pivot">
<g id="chassis_rear">
<!-- Rear track band -->
<path d="M-138 15 L-18 15 A15 15 0 0 0-18-15 L-138-15 A15 15 0 0 0-138 15Z" fill="none" stroke="#222" stroke-width="16" stroke-linecap="round" stroke-linejoin="round"/>
<path class="tread rt" d="M-138 15 L-18 15 A15 15 0 0 0-18-15 L-138-15 A15 15 0 0 0-138 15Z" fill="none" stroke="#444" stroke-width="1.8" stroke-dasharray="5 3.5"/>
<!-- Rear body -->
<rect x="-148" y="-40" width="148" height="40" rx="5" fill="url(#bG)"/>
<rect x="-148" y="-40" width="148" height="4" rx="2" fill="rgba(255,255,255,.13)"/>
<!-- Body detail lines -->
<line x1="-148" y1="-20" x2="0" y2="-20" stroke="rgba(255,255,255,.06)" stroke-width=".8"/>
<!-- Motor -->
<rect x="-105" y="-34" width="32" height="12" rx="2" fill="#0f3a5e" stroke="#3A8BC5" stroke-width=".7"/>
<text x="-89" y="-25" font-size="6" fill="#6ABBE8" text-anchor="middle">电机R</text>
<!-- Rear wheels -->
<g class="whl" transform="translate(-128,0)"><circle r="15" fill="#333" stroke="#222" stroke-width="1.8"/><circle r="4.5" fill="#555"/><g class="wheel-spoke"><line y1="-11" y2="11" stroke="#555" stroke-width="1.3"/><line x1="-11" x2="11" stroke="#555" stroke-width="1.3"/></g></g>
<g class="whl" transform="translate(-28,0)"><circle r="15" fill="#333" stroke="#222" stroke-width="1.8"/><circle r="4.5" fill="#555"/><g class="wheel-spoke"><line y1="-11" y2="11" stroke="#555" stroke-width="1.3"/><line x1="-11" x2="11" stroke="#555" stroke-width="1.3"/></g></g>
<!-- Platform assembly -->
<g id="platform_joint" transform="translate(-74,-40)">
<rect x="-3" y="-14" width="6" height="14" fill="#666" rx="1.5"/>
<circle r="3.5" cy="-14" fill="#888" stroke="#666" stroke-width=".8"/>
<g id="cargo_platform">
<rect x="-52" y="-16" width="104" height="16" rx="3" fill="url(#pG)"/>
<rect x="-52" y="-16" width="104" height="3" rx="1.5" fill="rgba(255,255,255,.18)"/>
<!-- Cargo -->
<rect x="-28" y="-29" width="42" height="13" rx="2" fill="#8D6E63" stroke="#6D4C41" stroke-width=".7"/>
<text x="-7" y="-20" font-size="5.5" fill="#D7CCC8" text-anchor="middle">货物</text>
<!-- Gyroscope -->
<g id="gyroscope" transform="translate(34,-8)">
<circle r="8.5" fill="none" stroke="#FFD700" stroke-width="1" opacity=".6"/>
<circle r="5.5" fill="none" stroke="#FFD700" stroke-width=".7" opacity=".4"/>
<g id="gyro_spinner">
<line x1="-7.5" y1="0" x2="7.5" y2="0" stroke="#FFD700" stroke-width="1"/>
<line x1="0" y1="-7.5" x2="0" y2="7.5" stroke="#FFD700" stroke-width="1"/>
<line x1="-5.3" y1="-5.3" x2="5.3" y2="5.3" stroke="#FFD700" stroke-width=".7"/>
<line x1="5.3" y1="-5.3" x2="-5.3" y2="5.3" stroke="#FFD700" stroke-width=".7"/>
</g>
<circle r="1.8" fill="#FFD700"/>
</g>
<text x="34" y="-19" font-size="5" fill="#FFD700" text-anchor="middle" opacity=".65">陀螺仪</text>
</g>
</g>
</g>
</g>
<!-- ===== FRONT CHASSIS PIVOT ===== -->
<g id="chassis_front_pivot">
<g id="chassis_front">
<!-- Front track band -->
<path d="M18 15 L138 15 A15 15 0 0 0 138-15 L18-15 A15 15 0 0 0 18 15Z" fill="none" stroke="#222" stroke-width="16" stroke-linecap="round" stroke-linejoin="round"/>
<path class="tread ft" d="M18 15 L138 15 A15 15 0 0 0 138-15 L18-15 A15 15 0 0 0 18 15Z" fill="none" stroke="#444" stroke-width="1.8" stroke-dasharray="5 3.5"/>
<!-- Front body -->
<rect x="0" y="-40" width="148" height="40" rx="5" fill="url(#bG)"/>
<rect x="0" y="-40" width="148" height="4" rx="2" fill="rgba(255,255,255,.13)"/>
<line x1="0" y1="-20" x2="148" y2="-20" stroke="rgba(255,255,255,.06)" stroke-width=".8"/>
<!-- Motor -->
<rect x="58" y="-34" width="32" height="12" rx="2" fill="#0f3a5e" stroke="#3A8BC5" stroke-width=".7"/>
<text x="74" y="-25" font-size="6" fill="#6ABBE8" text-anchor="middle">电机F</text>
<!-- Front wheels -->
<g class="whl" transform="translate(28,0)"><circle r="15" fill="#333" stroke="#222" stroke-width="1.8"/><circle r="4.5" fill="#555"/><g class="wheel-spoke"><line y1="-11" y2="11" stroke="#555" stroke-width="1.3"/><line x1="-11" x2="11" stroke="#555" stroke-width="1.3"/></g></g>
<g class="whl" transform="translate(128,0)"><circle r="15" fill="#333" stroke="#222" stroke-width="1.8"/><circle r="4.5" fill="#555"/><g class="wheel-spoke"><line y1="-11" y2="11" stroke="#555" stroke-width="1.3"/><line x1="-11" x2="11" stroke="#555" stroke-width="1.3"/></g></g>
</g>
</g>
<!-- ===== UNIVERSAL JOINT ===== -->
<g id="universal_joint">
<circle cx="0" cy="-20" r="11" fill="#FF6B35" stroke="#CC5522" stroke-width="1.8" filter="url(#gl)"/>
<circle cx="0" cy="-20" r="4.5" fill="#FFB088"/>
<line x1="-6" y1="-26" x2="6" y2="-14" stroke="#CC5522" stroke-width="1.5"/>
<line x1="6" y1="-26" x2="-6" y2="-14" stroke="#CC5522" stroke-width="1.5"/>
</g>
<!-- Joint label -->
<g id="jointLabel" opacity=".7">
<line x1="0" y1="-34" x2="0" y2="-52" stroke="#FF6B35" stroke-width=".8" stroke-dasharray="2,2"/>
<text x="0" y="-56" font-size="8" fill="#FF6B35" text-anchor="middle">万向节</text>
</g>
</g>
<!-- 45° limit arc (appears during bending) -->
<g id="limitArc" opacity="0">
<path id="limitArcPath" d="" fill="none" stroke="rgba(255,107,53,.25)" stroke-width="12" stroke-linecap="round"/>
<path id="bendArcPath" d="" fill="none" stroke="#FF6B35" stroke-width="3" stroke-linecap="round"/>
<text id="limitLabel" x="0" y="0" font-size="9" fill="rgba(255,107,53,.5)" text-anchor="middle">45°限</text>
</g>
</svg>
</div>
<div class="bar">
<div class="it">万向节最大弯折角:<b>45°</b></div>
<div class="it">履带宽度:<b>150mm</b></div>
<div class="it">驱动方式:<b>各舱段独立电机</b></div>
<div class="it">稳定:<b>自平衡陀螺仪补偿</b></div>
</div>
<button class="rbtn" onclick="replay()">↻ 重新播放</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script>
/* ========== 常量 ========== */
const GROUND_Y = 500, STEP_TOP = 420, STEP_FACE_X = 650;
const WHEEL_R = 15;
const JOINT_GROUND_Y = GROUND_Y - WHEEL_R; // 485
const JOINT_STEP_Y = STEP_TOP - WHEEL_R; // 405
const MAX_BEND = 42; // 动画中使用42°,在45°限制内
/* ========== 元素引用 ========== */
const vehicle = document.getElementById("vehicle");
const frontPivot = document.getElementById("chassis_front_pivot");
const rearPivot = document.getElementById("chassis_rear_pivot");
const cargoPlat = document.getElementById("cargo_platform");
const gyroSpin = document.getElementById("gyro_spinner");
const phaseLabel = document.getElementById("phaseLabel");
const angleReadout= document.getElementById("angleReadout");
const angleVal = document.getElementById("angleVal");
const forceArrow = document.getElementById("forceArrow");
const levelInd = document.getElementById("levelIndicator");
const limitArc = document.getElementById("limitArc");
const limitArcP = document.getElementById("limitArcPath");
const bendArcP = document.getElementById("bendArcPath");
const limitLabel = document.getElementById("limitLabel");
const uJoint = document.getElementById("universal_joint");
/* ========== 持续动画(轮子、履带、陀螺仪) ========== */
const wheelAnim = gsap.to(".wheel-spoke", {
rotation: 360, duration: 0.55, repeat: -1, ease: "none"
});
const gyroAnim = gsap.to("#gyro_spinner", {
rotation: -360, duration: 0.45, repeat: -1, ease: "none"
});
gsap.to(".rt", { strokeDashoffset: -17, duration: 0.35, repeat: -1, ease: "none" });
gsap.to(".ft", { strokeDashoffset: -17, duration: 0.35, repeat: -1, ease: "none" });
/* ========== 工具:绘制弧线路径 ========== */
function arcPath(cx, cy, r, startDeg, endDeg) {
const s = startDeg * Math.PI / 180, e = endDeg * Math.PI / 180;
const x1 = cx + r * Math.cos(s), y1 = cy + r * Math.sin(s);
const x2 = cx + r * Math.cos(e), y2 = cy + r * Math.sin(e);
const large = Math.abs(endDeg - startDeg) > 180 ? 1 : 0;
const sweep = endDeg > startDeg ? 1 : 0;
return `M${x1} ${y1} A${r} ${r} 0 ${large} ${sweep} ${x2} ${y2}`;
}
/* ========== 主时间轴 ========== */
let mainTL;
function buildTimeline() {
if (mainTL) { mainTL.kill(); }
// 重置所有状态
gsap.set(vehicle, { x: 120, y: JOINT_GROUND_Y });
gsap.set(frontPivot, { rotation: 0 });
gsap.set(rearPivot, { rotation: 0 });
gsap.set(cargoPlat, { rotation: 0 });
gsap.set(forceArrow, { opacity: 0 });
gsap.set(levelInd, { opacity: 0 });
gsap.set(angleReadout,{ opacity: 0 });
gsap.set(limitArc, { opacity: 0 });
gsap.set(uJoint, { scale: 1, transformOrigin: "0px -20px" });
gsap.set(phaseLabel, { textContent: "① 平地行驶" });
mainTL = gsap.timeline({
repeat: -1,
repeatDelay: 1.8,
defaults: { ease: "power2.inOut" }
});
/* ---- 阶段1:平地行驶接近台阶 ---- */
mainTL.addLabel("s1")
.to(vehicle, { x: STEP_FACE_X - 145, duration: 2.6, ease: "power1.inOut" }, "s1")
.to(phaseLabel, { duration: 0, textContent: "① 平地行驶 → 接近台阶" }, "s1");
/* ---- 阶段2:前端触壁 · 被动折叠抬升 ---- */
mainTL.addLabel("s2", "+=0.15")
.to(phaseLabel, { duration: 0, textContent: "② 前舱段被动折叠抬升" }, "s2")
.to(frontPivot, { rotation: -MAX_BEND, duration: 2.2, ease: "power2.out" }, "s2")
.to(vehicle, { x: STEP_FACE_X - 90, duration: 2.2, ease: "power1.out" }, "s2")
// 万向节高亮
.to(uJoint, { scale: 1.35, duration: 0.4, ease: "back.out(2)" }, "s2")
.to(uJoint, { scale: 1.15, duration: 0.6 }, "s2+=0.4")
// 角度指示
.to(angleReadout, { opacity: 1, duration: 0.3 }, "s2+=0.2")
.to(limitArc, { opacity: 1, duration: 0.3 }, "s2+=0.2")
// 摩擦力箭头
.to(forceArrow, { opacity: 1, duration: 0.3 }, "s2+=0.5")
// 弯折角实时更新
.to({}, {
duration: 2.2,
onUpdate: function() {
const r = gsap.getProperty(frontPivot, "rotation");
const deg = Math.abs(r).toFixed(1);
angleVal.textContent = "弯折角: " + deg + "°";
// 更新弧线
const vx = gsap.getProperty(vehicle, "x");
const vy = gsap.getProperty(vehicle, "y");
const jx = vx, jy = vy - 20;
const arcR = 35;
limitArcP.setAttribute("d", arcPath(jx, jy, arcR, 180, 180 - 45));
bendArcP.setAttribute("d", arcPath(jx, jy, arcR, 180, 180 - Math.abs(r)));
limitLabel.setAttribute("x", jx - arcR - 14);
limitLabel.setAttribute("y", jy + 4);
// 箭头位置
const contactX = Math.min(vx + 128 * Math.cos(r * Math.PI / 180), STEP_FACE_X);
const contactY = vy + 128 * Math.sin(r * Math.PI / 180);
forceArrow.setAttribute("transform", `translate(${STEP_FACE_X - 8}, ${Math.min(contactY, GROUND_Y - 10)})`);
}
}, "s2");
/* ---- 阶段3:趴伏台阶边缘 ---- */
mainTL.addLabel("s3", "+=0.2")
.to(phaseLabel, { duration: 0, textContent: "③ 前舱段趴伏台阶边缘 · 后段被动倾斜" }, "s3")
.to(frontPivot, { rotation: 0, duration: 1.8 }, "s3")
.to(vehicle, { x: STEP_FACE_X + 30, y: JOINT_STEP_Y, duration: 1.8, ease: "power2.inOut" }, "s3")
// 后段随关节抬升而倾斜,保持远端触地
.to(rearPivot, { rotation: 30, duration: 1.8, ease: "power2.inOut" }, "s3")
// 平台陀螺仪补偿
.to(cargoPlat, { rotation: -30, duration: 1.8, ease: "power2.inOut" }, "s3")
// 水平指示器
.to(levelInd, { opacity: 1, duration: 0.3 }, "s3+=0.3")
// 角度淡出
.to(angleReadout,{ opacity: 0, duration: 0.4 }, "s3+=1.2")
.to(limitArc, { opacity: 0, duration: 0.4 }, "s3+=1.2")
.to(forceArrow, { opacity: 0, duration: 0.3 }, "s3+=0.5")
// 万向节恢复
.to(uJoint, { scale: 1, duration: 0.5 }, "s3+=0.5")
// 更新角度
.to({}, {
duration: 1.8,
onUpdate: function() {
const fr = gsap.getProperty(frontPivot, "rotation");
const rr = gsap.getProperty(rearPivot, "rotation");
const bendDeg = Math.max(Math.abs(fr), Math.abs(rr)).toFixed(1);
angleVal.textContent = "弯折角: " + bendDeg + "°";
// 水平指示器跟随平台
const vx = gsap.getProperty(vehicle, "x");
const vy = gsap.getProperty(vehicle, "y");
const platX = vx - 74;
const platY = vy - 40 - 16;
levelInd.setAttribute("transform", `translate(${platX - 30}, ${platY})`);
}
}, "s3");
/* ---- 阶段4:重心前移 · 后段攀爬 ---- */
mainTL.addLabel("s4", "+=0.15")
.to(phaseLabel, { duration: 0, textContent: "④ 后舱段攀爬 · 陀螺仪补偿保持水平" }, "s4")
.to(rearPivot, { rotation: 0, duration: 1.8 }, "s4")
.to(cargoPlat, { rotation: 0, duration: 1.8 }, "s4")
.to(vehicle, { x: STEP_FACE_X + 120, duration: 1.8, ease: "power1.inOut" }, "s4")
.to(angleReadout,{ opacity: 0, duration: 0.2 }, "s4")
.to({}, {
duration: 1.8,
onUpdate: function() {
const rr = gsap.getProperty(rearPivot, "rotation");
const platX = gsap.getProperty(vehicle, "x") - 74;
const platY = gsap.getProperty(vehicle, "y") - 40 - 16;
levelInd.setAttribute("transform", `translate(${platX - 30}, ${platY})`);
}
}, "s4");
/* ---- 阶段5:恢复平直 · 继续行驶 ---- */
mainTL.addLabel("s5", "+=0.1")
.to(phaseLabel, { duration: 0, textContent: "⑤ 自重恢复平直 · 跨越完成" }, "s5")
.to(levelInd, { opacity: 0, duration: 0.4 }, "s5")
.to(vehicle, { x: 1060, duration: 2.2, ease: "power1.inOut" }, "s5");
}
buildTimeline();
/* ========== 重播 ========== */
function replay() {
buildTimeline();
}
</script>
</body>
</html>
这个动画完整呈现了多段铰接式柔性底盘的台阶攀爬原理,核心设计要点如下:
部件层级与连接关系:
- 前后舱段分别包裹在
chassis_front_pivot/chassis_rear_pivot组中,两组的旋转原点均为万向节中心(0,0),确保弯折动作围绕正确的机械锚点发生 - 货物平台通过
platform_joint挂载在后舱段顶部,内部cargo_platform独立旋转以实现陀螺仪补偿 - 履带、轮组作为各舱段的子元素,随舱段弯折自然变形
时间轴编排(6 个阶段):
- 平地行驶 — 整车平直推进接近台阶
- 被动折叠抬升 — 前舱段绕万向节向上弯折约 42°(在 45° 限制内),万向节高亮闪烁,弯折角弧线实时指示
- 趴伏台阶边缘 — 前舱段回落至台阶顶面,关节中心抬升,后舱段被动倾斜保持远端触地,平台陀螺仪反向补偿旋转
- 后段攀爬 — 后舱段被拉动绕万向节上移,平台持续补偿保持水平
- 恢复平直 — 后舱段搭接台阶,自重恢复直线构型,补偿归零
视觉引导:
- 万向节在弯折时放大+发光,聚焦核心创新点
- 弯折角弧线对比 45° 限制区间
- 摩擦力箭头标示台阶面受力
- 水平指示器标示平台姿态稳定
- 陀螺仪持续旋转暗示补偿生效
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
