UE5蓝图交互核心:手部Socket配置与拾取投掷系统实战
1. 项目概述为什么“手”是UE5蓝图交互的灵魂在虚幻引擎5UE5里鼓捣角色交互给角色加个“手”来拾取和投掷物品这几乎是每个新手开发者都会遇到的第一个“坎”。听起来简单不就是让角色能拿起东西再扔出去吗但真做起来你会发现这里面的门道比想象中多。很多教程会直接甩给你一堆蓝图节点告诉你“连这里连那里”结果你照猫画虎做出来要么东西拿不起来要么拿起来位置飘在天上要么扔出去的方向乱七八糟。这背后的核心其实就藏在一个看似不起眼的概念里Socket插槽。Socket是骨骼网格体Skeleton Mesh上的一个预定义附着点。你可以把它想象成你衣服上的一个魔术贴或者挂钩。角色的“手”本身不是一个独立的模型它只是角色骨骼网格体的一部分。当我们说“给角色加个手”本质上是在角色的手部骨骼比如hand_r上定义一个精确的附着点Socket所有被拾取的物体都将以这个点为基准进行位置和旋转的绑定。这个Socket的配置直接决定了物体是稳稳地握在手里还是像鬼魂一样穿透手掌。我见过太多项目因为Socket没配好导致整个交互系统后期bug频出推倒重来。所以今天我们不只讲“5分钟搞定”的快速流程更要深挖Socket配置里的那些“坑”让你一次配置终身受用。无论你是想做一个第一人称的捡枪游戏还是一个第三人称的投掷解谜这套基于Socket的拾取投掷蓝图逻辑都是你必须掌握的基石。2. 核心思路拆解从“想”到“做”的蓝图设计在动手连节点之前我们必须把整个交互流程的逻辑想清楚。一个健壮的拾取投掷系统不应该是一堆散乱的脚本而应该是一个有状态、可预测的有限状态机。虽然我们不用蓝图专门画一个状态机但脑子里要有这个模型。2.1 交互状态流转图整个流程可以简化为三个核心状态空闲Idle-持握Holding-投掷中Throwing。所有蓝图逻辑都围绕状态切换和状态内的行为展开。空闲状态角色可以自由移动检测前方的可拾取物体。通常通过射线检测Line Trace或球形检测Sphere Overlap来实现。持握状态当玩家按下拾取键且检测到有效物体时系统进入此状态。核心操作是解除物体的物理模拟将其附着Attach To到角色手部的Socket上。此时物体的运动完全跟随角色。投掷状态当玩家在持握状态下按下投掷键系统进入此状态。核心操作是将物体从Socket上分离Detach重新启用物理模拟并赋予其一个初始速度和方向。完成后状态回归空闲。这个清晰的状态划分能帮你避免很多逻辑冲突比如防止角色在投掷动画播放中途再次拾取物体。2.2 关键组件与蓝图选择在UE5中实现这个功能主要有几个地方可以写逻辑角色蓝图Character Blueprint、玩家控制器Player Controller或是单独的交互组件Actor Component。我的建议是将核心拾取与投掷逻辑放在角色蓝图里而将物体被拾取时的响应行为放在物品本身的蓝图里。这样职责清晰耦合度低。角色蓝图负责检测、状态管理、发出“拾取”和“投掷”指令、计算投掷向量。物品蓝图通常继承自Actor。它需要包含一个Static Mesh Component或Skeletal Mesh Component并编写被拾取时如禁用物理、附着到Socket和被投掷时如启用物理、应用力的具体行为函数。这些函数应被设计为可供外部调用。这种分离设计的好处是当你新增一种可投掷物品比如从石头换成手榴弹时你只需要修改该物品自身的蓝图例如手榴弹被投掷后3秒爆炸而角色的交互代码完全不用动。3. 避坑核心手部Socket的精确配置指南这是全文的重中之重也是大多数问题的根源。Socket配置不对后面蓝图连得再漂亮也是白搭。3.1 创建与定位Socket的正确姿势首先打开你的角色骨骼网格体在内容浏览器中双击打开。在骨架树Skeleton Tree中找到你打算用来持物的骨骼通常是hand_r右手或hand_l左手。右键点击目标骨骼选择“添加插槽”Add Socket。给Socket起一个直观的名字例如Socket_Grab_R。关键步骤调整Socket变换Transform。新加的Socket默认位置和旋转与父骨骼完全一致这通常是不对的。你需要使用视口工具栏的移动W、旋转E、缩放R工具在本地空间Local Space下调整这个Socket。位置将Socket移动到手掌中心或者你希望物体接触的确切点例如剑柄的位置。你可以临时添加一个立方体模型附着上去在视口中直观调整。旋转这决定了物体附着时的朝向。一个常见的错误是忽略旋转导致物体“横着”被握住。你需要根据物体的自然持握方向来调整。例如对于一个棒球你可能希望Socket的Z轴朝上对于一把剑你可能希望Socket的X轴沿着剑身方向。重要提示务必在“细节”面板中确认你修改的是“相对变换”Relative Transform并且是在Socket被选中的情况下操作。有时在视口中拖动会不小心选中骨骼导致错误操作。3.2 方向与轴向的“坑”UE5使用左手坐标系X向前Y向右Z向上。但模型资产尤其是从不同软件导入的其轴向可能千差万别。问题从市场购买的模型其手部骨骼的本地轴向可能并非你预想的方向。导致你按“常识”调整旋转后物体附着方向依然怪异。排查在骨架编辑器中选中手部骨骼在视口下方开启“显示轴向”Show Axes。观察红色X、绿色Y、蓝色Z箭头分别指向哪里。你的Socket旋转调整应基于此实际轴向进行。技巧一个笨但有效的方法是在角色蓝图中临时写一段测试代码生成一个带有明显方向标识的物体比如一个一头红一头蓝的细长圆柱体附着到Socket上在游戏运行中实时观察其方向然后返回骨架编辑器微调Socket旋转。3.3 缩放继承的陷阱这是最隐蔽的坑之一。Socket有一个属性叫“缩放继承”Inherit Scale”默认是勾选的。这意味着Socket的缩放会继承其父骨骼的缩放。如果你的角色动画中有手部骨骼的轻微缩放某些动画包会有那么这个缩放也会传递给你持有的物体导致物体被意外地放大或缩小看起来极其不协调。解决方案在骨架编辑器中选中你创建的Socket如Socket_Grab_R在细节面板中找到“缩放继承”选项取消勾选。这样无论手部骨骼如何动画Socket的缩放比例将保持为1物体大小也就固定了。99%的情况下我们都应该取消这个选项。4. 蓝图实战构建拾取与投掷逻辑链理论清晰了坑也知道了现在我们来用蓝图具体实现。我会以第三人称角色蓝图ThirdPersonCharacter为例。4.1 物品检测射线检测的实现与优化我们首先需要在角色蓝图中实现物品检测。通常使用“射线检测Line Trace by Channel”。在角色蓝图中创建一个自定义事件比如叫DetectInteractable每帧调用或在Tick事件中调用但注意性能也可以使用定时器控制频率。拖出“射线检测”节点。设置起始点为摄像机组件或角色的眼睛位置终点为起始点 摄像机前向向量 * 检测距离例如500单位。碰撞通道Trace Channel选择“可见性Visibility”或自定义一个“可交互Interactable”通道。后者更专业需要在项目设置中预先定义。将检测结果Out Hit的“命中Actor”Hit Actor提升为变量命名为CurrentFocusActor用于存储当前瞄准的可交互物体。优化技巧纯射线检测可能感觉不够“自然”。你可以结合“球形检测Sphere Overlap”。在摄像机前方一个小范围内做球形检测获取所有重叠物体再从其中筛选出距离角色最近且在屏幕中心一定角度内的那个。这样即使物体不在精确的射线路径上只要在“手边”也能被检测到体验更友好。4.2 拾取功能附着与状态管理当玩家按下拾取键如E键时我们触发拾取逻辑。输入绑定在项目设置中绑定“拾取PickUp”动作到E键。蓝图逻辑在角色蓝图中为“拾取”动作创建一个已按压Pressed事件。首先判断CurrentFocusActor是否有效并且该Actor是否实现了我们约定的交互接口例如一个叫Interactable的蓝图接口里面有一个OnPickUp函数。这是良好的设计模式避免直接类型转换。如果有效调用CurrentFocusActor的OnPickUp接口函数。在这个接口函数里我们传递一个关键参数目标Socket的名字如“Socket_Grab_R”。在物品Actor的蓝图中实现OnPickUp函数。具体操作包括禁用物理模拟获取物品的网格体组件设置“模拟物理Simulate Physics”为false。禁用碰撞将网格体的碰撞预设改为“无碰撞NoCollision”或自定义一个“被持有Held”预设避免与其他物体发生不必要的碰撞。附着到Socket使用“附着到组件AttachToComponent”节点。父组件Parent参数传入接口调用者即角色的骨骼网格体组件Get Mesh。Socket名称参数就是刚才传入的Socket_Grab_R。附着规则Attachment Rule选择“保持世界位置Keep World”这通常能避免物体在附着瞬间的突兀跳动。在角色蓝图中成功调用接口后将CurrentFocusActor存储到一个新的变量中如HeldActor并将一个布尔变量bIsHolding设为true标志进入持握状态。4.3 投掷功能力的计算与释放投掷的核心是给物体一个合理的初速度。输入绑定绑定“投掷Throw”动作到鼠标左键或F键。蓝图逻辑首先检查bIsHolding是否为true并且HeldActor有效。计算投掷方向一个常见的方案是使用摄像机的前向向量Get Forward Vector作为基础方向。为了增加一点抛物线感觉可以混合一点摄像机的上向量Get Up Vector。例如投掷方向 摄像机前向向量 * 0.9 摄像机向上向量 * 0.2需归一化。更高级的可以加入角色速度的影响。计算投掷力度可以是一个固定值也可以通过按住按键的时间来蓄力。将力度值乘以方向向量得到最终的速度向量Velocity Vector。执行投掷调用HeldActor的投掷接口如OnThrow将计算好的速度向量传递过去。在物品的OnThrow函数中先将物体从Socket上分离Detach From Parent。立即启用物理模拟Simulate Physics true。启用碰撞恢复原来的碰撞预设。使用“添加冲量Add Impulse”或“设置物理线性速度Set Physics Linear Velocity”节点将速度向量应用到物体的根组件上。“添加冲量”更符合瞬间发力的物理感。在角色蓝图中投掷执行后将HeldActor清空bIsHolding设为false回归空闲状态。5. 高级技巧与细节打磨基础功能跑通后这些细节能让你的交互体验从“能用”跃升到“好用”。5.1 平滑的附着与分离直接附着和分离可能会导致物体“瞬移”。我们可以用插值Lerp来平滑过渡。平滑拾取在物品被拾取时不要立刻AttachToComponent。可以先记录下物品当前的世界变换和目标Socket的世界变换然后在接下来的几帧里利用Timeline或Tick将物品的位置和旋转逐渐插值到目标位置。当距离足够近时再执行真正的附着。这能消除“吸附”感。平滑投掷预览在持握状态下按住投掷键可以进入“蓄力瞄准”状态。此时可以让物品轻微地脱离Socket比如沿着投掷方向向后移动一小段距离并跟随摄像机方向微调给玩家一个直观的力度和方向预览。5.2 投掷物的物理属性调校物体扔出去的感觉“轻飘飘”或者“像块砖”主要取决于其物理材质和质量。质量Mass在物品网格体的细节面板中调整质量。质量越大惯性越大同样的力扔出去速度越慢下落越快。物理材质Physical Material创建一个物理材质分配给物品。调整摩擦力和反弹系数。这会影响物体在地面滚动、碰撞墙壁反弹的效果。一个高反弹的球和一块低摩擦的木块投掷手感截然不同。空气阻力Linear Damping在物理属性中增加一点线性阻尼可以模拟空气阻力让抛物线更真实避免物体飞得太“飘”。5.3 动画通知与音效集成拾取和投掷不能是“静默”的。动画通知Animation Notify在角色的拾取和投掷动画蒙太奇Montage中在合适的时间点比如手接触到物体的那一帧插入动画通知。在蓝图中捕获这些通知来精确触发“执行附着”或“执行分离”的逻辑让动作和逻辑完美同步。音效在拾取成功、投掷出手的瞬间播放相应的音效。投掷音效的音调可以根据蓄力时间动态调整增强反馈。6. 常见问题排查与调试技巧即使按照步骤做也难免遇到问题。这里是一份快速排错清单。问题现象可能原因排查步骤与解决方案物体拾取后位置偏移/穿透1. Socket位置不准。2. 附着时规则用错。1. 返回骨架编辑器仔细调整Socket位置可附着参考物体查看。2. 尝试将附着规则从“Keep World”改为“Snap to Target”。物体拾取后方向错误/倾斜Socket旋转未配置或配置错误。检查Socket的本地旋转。在物品蓝图的OnPickUp中尝试在附着后额外设置一次物品的相对旋转Set Relative Rotation来强制修正。投掷物体无反应/直接掉落1. 物理模拟未启用。2. 施加的力/冲量太小或方向错误。3. 碰撞被禁用。1. 确认投掷逻辑中Simulate Physics已设为True。2. 打印出计算出的速度向量检查其数值和方向是否合理。可先尝试一个较大的固定值如向量(1000,0,0)。3. 确认投掷后物体的碰撞预设已恢复。拾取或投掷时角色动画不同步动画蒙太奇播放时机不对或未与蓝图逻辑绑定。确保播放动画蒙太奇的事件在接口调用之前或通过动画通知触发。使用动画通知来驱动关键的状态切换和函数调用。手持物体时物体异常缩放Socket的“缩放继承Inherit Scale”属性被启用。在角色骨架中找到对应的Socket在细节面板中取消勾选“Inherit Scale”。射线检测不到物体1. 检测通道不匹配。2. 物体碰撞体积设置问题。3. 检测起点/终点错误。1. 确保物体网格体的碰撞响应Collision Responses对你使用的检测通道如Visibility是“阻挡Block”。2. 检查物体是否有正确的碰撞体Collision Mesh。3. 在视口中绘制调试射线Draw Debug Line直观查看射线路径。调试利器打印字符串与调试绘图在开发过程中不要吝啬使用Print String节点。在关键分支、函数入口处打印变量状态如CurrentFocusActor的名字、bIsHolding的值、计算出的投掷向量等能快速定位逻辑流。对于空间问题使用Draw Debug Line画射线、Draw Debug Sphere画检测范围等节点能在游戏运行时直观看到你的检测范围和方向事半功倍。最后记住蓝图开发是一个迭代的过程。先搭起主干逻辑让最基本的功能跑通然后再一点点添加平滑过渡、物理反馈、音效动画等细节。这套基于Socket的拾取投掷框架非常稳固在此基础上你可以扩展出双持、不同类型的抓握姿势如抓、托、扛、甚至是将Socket与动画曲线驱动结合实现更动态的持物效果。当你真正理解了Socket这个“空间锚点”的精髓UE5中许多基于骨骼的附着问题都会迎刃而解。

相关新闻

TVP5147M1 VBI配置实战:解码模拟视频隐藏数据通道

TVP5147M1 VBI配置实战:解码模拟视频隐藏数据通道

1. 项目概述:解码模拟视频的“隐藏”数据通道 在模拟视频时代,除了我们肉眼可见的画面,每一帧图像中还隐藏着一个不为人知的数据通道——垂直消隐间隔。对于从事视频处理、广播工程或复古游戏机改造的工程师来说,能否正确配置并利…

2026/10/17 20:20:37 阅读更多 →
Mac 上如何替代 WinSCP?SFTP/FTP 文件传输工具选择与实践

Mac 上如何替代 WinSCP?SFTP/FTP 文件传输工具选择与实践

从 Windows 转到 Mac 后,很多开发者都会遇到一个实际问题:以前习惯使用的 WinSCP 找不到对应版本了。WinSCP 是 Windows 平台上非常常用的文件传输工具,主要用于服务器文件管理,包括:通过 SFTP、FTP、SCP、WebDAV、S3 …

2026/10/18 10:41:22 阅读更多 →
算法面试——堆与优先队列:前K个高频元素、合并K个链表、数据流中位数

算法面试——堆与优先队列:前K个高频元素、合并K个链表、数据流中位数

堆&#xff08;优先队列&#xff09;常用于需要反复获取最大/最小值的场景。Java 中用 PriorityQueue。 一、前 K 个高频元素 public int[] topKFrequent(int[] nums, int k) {Map<Integer, Integer> freq new HashMap<>();for (int num : nums) freq.put(num, …

2026/10/17 20:23:49 阅读更多 →

最新新闻

【信道估计】毫米波MIMO系统LS、OMP和SBL UPA远场信道估计(NMSE性能评估)【含Matlab源码 16091期】

【信道估计】毫米波MIMO系统LS、OMP和SBL UPA远场信道估计(NMSE性能评估)【含Matlab源码 16091期】

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;Matlab武动乾坤博客之家&#x1f49e;…

2026/10/18 21:33:03 阅读更多 →
Qwen3-TTS零样本音色克隆实战:从3秒参考音频到批量语音合成

Qwen3-TTS零样本音色克隆实战:从3秒参考音频到批量语音合成

简介&#xff1a;这份资源是面向语音合成初学者与开发者的Qwen3-TTS实战教程配套代码包&#xff0c;重点解决多语种语音生成中语速、音高、音色难以独立调节的问题。教程覆盖环境准备、快速部署到分步实践&#xff0c;并延伸至视频配音、有声书制作、智能客服等落地场景&#x…

2026/10/18 21:33:03 阅读更多 →
C++游戏开发实战:SDL2引擎下的超级玛丽复刻与实时系统训练

C++游戏开发实战:SDL2引擎下的超级玛丽复刻与实时系统训练

简介&#xff1a;这是一份基于C语言实现的经典横版闯关游戏——超级玛丽的完整源码工程&#xff0c;面向C初学者与面向对象编程实践者&#xff0c;适用于课程设计、游戏开发入门及OOP项目实训。资源包含可直接编译运行的Visual Studio 2008工程&#xff08;.sln/.vcproj&#x…

2026/10/18 21:32:02 阅读更多 →
DHI MATLAB工具箱:解析DFS0/DFS2/MESH水文模型文件

DHI MATLAB工具箱:解析DFS0/DFS2/MESH水文模型文件

简介&#xff1a;本资源是面向水文水利、海洋工程及环境建模领域科研人员与MATLAB开发者的DHI文件专用处理工具箱&#xff0c;解决MIKE系列软件&#xff08;如MIKE 21/3、DHI DFS格式&#xff09;生成的二进制数据在MATLAB中读写、解析与后处理困难的问题。压缩包共108个文件&a…

2026/10/18 21:32:02 阅读更多 →
Phoenix与HBase的关系:SQL-on-HBase架构原理与性能调优实践

Phoenix与HBase的关系:SQL-on-HBase架构原理与性能调优实践

1. 这俩到底啥关系&#xff1a;先扒清楚Phoenix和HBase的定位很多刚接触大数据组件的人第一次看到“Phoenix与HBase的关系”这个问题&#xff0c;第一反应可能是&#xff1a;这俩是不是同一个东西的两个名字&#xff1f;或者一个是一个的升级版&#xff1f;都不对。Phoenix和HB…

2026/10/18 21:32:02 阅读更多 →
UltraEdit 语法高亮文件下载与添加:用 TaoToken 统一管理配置来源

UltraEdit 语法高亮文件下载与添加:用 TaoToken 统一管理配置来源

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 21:32:02 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →