虚幻引擎5.2蓝图实现:角色游泳、潜水与浮力控制系统开发指南
1. 项目概述从“会动”到“会游”的角色进化在虚幻引擎5.2里做一个能跑能跳的角色对很多开发者来说已经是家常便饭。但当你需要把角色丢进一个广阔的水世界让他不仅能浮在水面扑腾还能一个猛子扎下去探索深海事情就变得有趣且棘手了。物理引擎的默认浮力往往生硬得像块木头角色要么沉得太快像绑了石头要么漂在水上像个不倒翁更别提配合上流畅的游泳动画和潜水控制了。这个项目要解决的就是如何绕开复杂的物理卷Physics Volume设置纯粹用蓝图系统构建一套手感自然、响应迅速、且能与水体深度交互的角色游泳、潜水与浮力控制系统。最终你会得到一个不仅“物理正确”而且“感觉正确”的水中角色并附上完整的项目文件供你拆解和复用。2. 核心设计思路状态驱动与物理模拟的分离传统的做法可能会试图用一个复杂的物理材质或者调整角色的质量密度来模拟浮力但这通常会导致角色行为不可预测动画也难以同步。我们的核心思路是将“逻辑控制”与“物理表现”分离。逻辑层状态机在动画蓝图中我们建立一个以“游泳状态”枚举变量为核心的状态机。典型的状态包括IdleOnLand陆地待机、SurfaceSwim水面游泳、Diving潜水、UnderwaterSwim水下游泳、Surfacing上浮等。这个状态机不直接驱动位移它只负责根据输入如按键、角色与水面的相对位置切换状态并触发对应的动画。表现层蓝图逻辑在角色蓝图的事件图表中我们根据当前的状态动态地施加各种力来模拟物理效果。例如在SurfaceSwim状态我们施加一个向上的浮力其大小可能与角色浸入水体的体积相关和一个基于输入的前进推力在Diving状态我们可能取消大部分浮力并施加一个向下的力帮助角色下潜。这种分离的好处是巨大的动画师可以专注于让每个状态下的动画看起来自然而程序员则可以精细地调整每个状态下的物理参数力度、阻尼、旋转速度直到获得最佳的手感两者互不干扰。2.1 为什么不用物理卷物理卷Physics Volume如Water Volume确实能提供全局的浮力和流体阻力但它是一种“环境规则”对所有进入其中的物体一视同仁。对于主角这种需要特殊交互逻辑的对象全局规则往往不够用。比如我们可能希望角色在水面游泳时受到较大的阻力但在潜水冲刺时阻力变小或者希望角色从高处落水时有一个“砸入水中”的减速效果而主动跳水则是流畅的。这些精细的、与状态绑定的控制用蓝图直接施加力来实现要灵活得多。3. 关键系统拆解与蓝图实现3.1 水体检测与深度判定一切始于知道角色是否在水中以及在水中的哪个部分。实现方法我们通常使用射线检测Line Trace。从角色的头顶或胶囊体顶部向下发射一条射线检测到水面的碰撞点。通过比较角色底部或胶囊体底部与水面碰撞点的垂直高度Z轴差值我们可以计算出角色的“浸入深度”。这个深度值将是计算浮力、决定是否切换为游泳状态的关键参数。注意水面本身需要一个碰撞通道如Water并且你的水体网格需要设置正确的碰撞预设。一个常见的坑是水面视觉效果如水的材质平面没有碰撞导致射线检测失败。确保你的水体Actor包含了用于检测的碰撞体。蓝图节点示例Line Trace by Channel从Get Actor Location(0,0, CapsuleHalfHeight)开始向(0,0, -CapsuleHeight-Offset)方向追踪。命中结果中的Impact Point的Z值即为水面高度。(角色底部位置Z) - (水面高度Z) 浸入深度。若结果为负说明角色底部在水面之上为正则说明已浸入水中。3.2 浮力系统的蓝图实现浮力不是简单的“向上推”。一个真实的浮力感觉应该考虑角色的姿态、浸入体积和运动状态。基础浮力公式简化浮力 浸入深度 * 浮力系数 * 角色质量 * 重力加速度。在蓝图中我们不会真的去计算排开水的体积而是用浸入深度作为一个合理的模拟量。当角色完全浸没时浮力达到最大稳定值。实现步骤计算基础浮力在角色蓝图的Tick事件中如果检测到角色在水中则根据上述公式计算一个向上的向量力。应用浮力使用Add Force或Add Impulse取决于你想要更平滑还是更瞬时的反应节点将计算出的浮力施加到角色的Character Movement组件或根骨骼上。更推荐对Character Movement组件施加力因为它能更好地与行走/游泳模式集成。浮力阻尼为了让角色不会在水面上无限弹跳需要施加垂直方向的速度阻尼。当角色垂直速度向上且较大时减小浮力系数当角色试图下沉时给予一个基础的浮力支撑。这可以通过一个基于垂直速度的浮力系数乘数来实现。// 伪代码逻辑示意 float ImmersionDepth CalculateImmersionDepth(); float BuoyancyFactor BaseBuoyancy; float VerticalVelocity GetVelocity().Z; if (VerticalVelocity 0) { // 上浮时减少浮力避免蹦出水面 BuoyancyFactor * FMath::Max(0.2f, 1.0f - VerticalVelocity / MaxRiseSpeed); } FVector BuoyancyForce FVector::UpVector * ImmersionDepth * BuoyancyFactor * Mass * Gravity; CharacterMovement-AddForce(BuoyancyForce);3.3 游泳与潜水控制输入与运动这是手感的核心。我们需要重写或扩展角色的移动输入逻辑。水面游泳控制模式切换当浸入深度大于阈值如膝盖高度将角色移动模式Movement Mode从Walking切换为Flying。Flying模式在水中提供了更自由的全向移动控制不受重力直接支配。输入映射将前进/后退、左右平移输入映射为在水平面X, Y轴上的移动向量。同时将“上浮”如空格键和“下潜”如Ctrl键映射到Z轴输入。施加运动力根据输入向量在Tick中向Character Movement组件施加一个力。这个力的大小应该与输入值成正比并受到一个“水中阻力”系数的限制使得角色有一个最大游泳速度。朝向控制角色的朝向应逐渐转向移动输入的方向但转弯速率Turn Rate在水中应比在陆地上更慢以模拟水的阻力。可以使用RInterp To节点平滑地插值旋转。潜水控制状态切换当玩家主动按下“下潜”键且角色已在水面时切换到Diving状态。在此状态可以暂时大幅降低甚至取消基础浮力并施加一个向下的初始冲力。水下游泳进入完全水下后浸没深度超过角色身高切换到UnderwaterSwim状态。此时的移动控制与水面游泳类似但可以在所有六个自由度前后、左右、上下上自由移动。你需要调整各轴上的最大速度和加速度使其感觉既灵活又有水的阻滞感。上浮与出水按下“上浮”键或角色自然浮到水面时触发Surfacing状态。这个状态需要平滑地处理角色从水中露头、浮力恢复、以及最终切换到水面游泳或陆地行走的过渡。3.4 动画状态机集成动画蓝图是让一切看起来自然的关键。状态机设计变量驱动在动画蓝图中创建一个枚举变量ESwimState与角色蓝图中逻辑层的状态同步使用Blueprint Read Write并在角色蓝图中设置。状态机布局在动画图表中创建状态机状态与ESwimState枚举值对应。每个状态连接一个动画子图Blend Space或具体的动画序列。混合空间Blend Space的运用水面游泳使用一个2D混合空间一个轴是前进速度从后退到前进另一个轴是横向速度左移到右移。根据角色移动速度向量在本地平面上的投影来驱动这个混合空间可以产生非常自然的踩水、转向动画。水下游泳可以使用另一个2D混合空间或者使用分层动画Layered Animation来处理上下方向的姿态。过渡规则状态之间的过渡条件应基于角色蓝图传递过来的参数如速度、是否在水中、浸入深度、输入方向等。避免使用简单的延时过渡而应采用逻辑判断确保动画切换及时准确。动画与物理的反馈高级技巧是让动画反过来影响物理。例如当播放强有力的划水动画时可以在动画通知Animation Notify触发的瞬间给角色施加一个额外的推进脉冲Impulse这样能产生“划水发力”的真实感让操作反馈与视觉表现高度同步。4. 完整实现流程与参数调优4.1 项目初始化与组件设置创建角色蓝图基于Character类创建一个新的蓝图如BP_WaterCharacter。配置移动组件在Character Movement组件细节面板中预先设置好Flying模式下的参数。关键参数包括Max Speed最大速度设置为一个合理的游泳速度如300-500。Braking Deceleration制动减速度水中应较高如500-1000让角色能快速停下。Air Control空中控制这个参数在Flying模式下也生效影响转向灵敏度可设为0.5-1.0。添加自定义变量SwimState (Enum)游泳状态枚举。bIsInWater (Boolean)是否在水中。ImmersionDepth (Float)浸入深度。BuoyancyFactor (Float)基础浮力系数可调。WaterDrag (Float)水中移动阻力系数。4.2 核心事件图表构建在角色蓝图的Event Graph中我们需要构建几个持续运行的逻辑链。主Tick逻辑水体检测每帧执行射线检测更新bIsInWater和ImmersionDepth。状态判断根据检测结果和输入更新SwimState枚举。这是一个简单的状态机逻辑可以用Switch on Enum节点实现。力施加根据当前的SwimState在Tick中调用对应的函数来施加浮力、推进力等。务必注意施加力的操作应在Character Movement组件更新之后进行通常Tick本身就在每帧更新后以确保力的计算基于最新状态。输入事件重写SetupPlayerInputComponent绑定的事件。例如SwimForward、SwimRight、SwimUp、SwimDown下潜、StartSwimming、StopSwimming等。这些输入事件主要设置用于计算移动向量的轴值Axis Value或触发状态切换。运动函数创建多个自定义函数来组织代码如CalculateBuoyancyForce、ApplySwimMovement、UpdateSwimState等。这会让蓝图更清晰易于调试。4.3 参数调优心得找到“感觉”的关键蓝图搭好了但角色在水里可能还是像个机器人。调优是赋予灵魂的过程。浮力与重力平衡目标是让角色在水面附近能轻松保持悬浮轻微按“下潜”能下沉松开后能缓慢上浮。调整BuoyancyFactor直到找到这个平衡点。可以尝试让浮力略小于完全抵消重力的值这样角色会非常缓慢地下沉需要轻微操作来维持高度更真实。起跳与入水处理角色从陆地跳入水中的瞬间。此时应快速将移动模式切换到Flying并可能施加一个临时的、较大的阻力来模拟“砸水”效果。可以通过检测垂直速度的突然变化来触发。转向灵敏度水中的转向应该比空中更“粘滞”。除了调整Air Control还可以在计算转向时对输入的旋转值进行一个平滑插值RInterp To并设置一个较长的插值时间如0.3秒。速度曲线不要让速度是线性的。可以设计一个速度曲线在低速时加速快接近最大速度时加速变慢。使用Curve Float资产根据当前速度与最大速度的比值来查询一个加速度倍乘系数。相机与角色旋转解耦在水下尤其是第一人称可以考虑让相机旋转独立于角色身体的偏航Yaw旋转仅让角色身体根据移动方向缓慢跟随。这能带来更灵活、更像潜水员的观察体验。5. 常见问题、调试技巧与性能优化5.1 问题排查速查表问题现象可能原因排查与解决思路角色完全无法浮起浮力计算未生效或力太小1. 检查水体射线检测是否成功打印Impact Point。2. 打印计算出的浮力向量值看是否非零。3. 检查Add Force节点是否被正确执行连接线是否畅通。4. 临时将浮力系数调至一个极大值如100看是否有反应。角色在水面疯狂跳动或抖动浮力与阻尼不平衡1. 检查浮力是否每帧都在施加且未在角色离开水面时及时停止。2. 引入速度阻尼当垂直速度向上时大幅降低浮力系数或施加一个向下的阻尼力。3. 考虑使用Add Force而非Add Impulse力更平滑。游泳控制迟滞或无响应移动模式未切换或输入未映射1. 确保进入水后角色移动模式已从Walking切换为Flying。2. 检查Flying模式下的Max Speed和Acceleration是否设置合理。3. 在输入事件中打印输入轴值确认按键绑定正确触发。动画状态不切换或切换错误动画蓝图变量未同步1. 在角色蓝图中确保在改变SwimState后使用Set节点同步给动画蓝图的变量。2. 在动画蓝图的状态机过渡规则中使用Time Remaining和逻辑判断结合避免状态抖动。水下移动感觉“太飘”或“太沉”各轴向速度/加速度参数不匹配1. 分别调整Max Swim Speed水平和Max Ascend/Descend Speed垂直。2. 调整Braking Deceleration垂直方向的制动减速度可以设得比水平方向小让上浮/下潜有惯性。性能开销大每帧进行复杂的射线检测和计算1. 优化射线检测只在角色可能接触水体的区域如角色底部附近进行检测或降低检测频率如每2-3帧一次。2. 使用简单的碰撞体如Box作为水体检测区域而非复杂的网格体。5.2 调试可视化技巧蓝图调试有时像在摸黑走路打开可视化工具能让你看清一切。绘制调试射线在Line Trace节点中勾选Draw Debug Type选择For One Frame或For Duration。你就能在游戏窗口中看到检测射线的路径和命中点。打印字符串在关键计算节点后使用Print String节点将变量值如ImmersionDepth、BuoyancyForce的大小、SwimState实时打印到屏幕上。自定义调试HUD创建一个简单的调试HUD蓝图将这些关键变量以文本形式常驻在屏幕一角比Print String更整洁。使用蓝图调试器在编辑器中运行游戏时可以在蓝图编辑器中设置断点单步执行观察变量流的变化。5.3 性能优化建议事件优化将每帧都必须执行的逻辑如浮力计算、基础移动放在Tick中但将频率较低的逻辑如状态切换判断放在一个自定义的、由定时器Timer驱动的函数中例如每0.1秒判断一次。距离检查在开始水体射线检测前先做一个简单的距离检查。如果角色最近的水体Actor在很远的地方则跳过当帧的检测。LOD逻辑当角色远离相机或处于非活动状态时可以大幅简化其游泳物理模拟例如使用一个固定的浮力值而非动态计算。池化与缓存如果你的水世界有很多独立的水体考虑使用对象池来管理水体检测结果避免重复构造数据结构。6. 项目文件使用指南与扩展思路随项目提供的完整蓝图文件是你学习和修改的起点。建议按以下步骤深入研究先玩再拆首先在打包的游戏或编辑器的模拟模式下体验角色控制感受当前的手感。逐块分析打开BP_WaterCharacter不要被复杂的连线吓到。从Event BeginPlay和Tick事件开始顺着执行流看下去。重点关注UpdateSwimState和ApplySwimForces这两个核心函数。修改参数尝试调整BuoyancyFactor、WaterDrag、MaxSwimSpeed等暴露在蓝图实例上的变量感受它们对手感的直接影响。动画重定向项目中的动画是针对特定骨骼制作的。如果你想用到自己的角色上需要确保骨骼结构兼容或使用虚幻引擎的重定向工具进行适配。扩展思路高级水体交互集成虚幻引擎5.2的Water插件让角色移动时能产生动态的涟漪和波浪。这需要读取角色的速度和在Water Body上的位置去驱动水的Gerster Waves参数。体力与氧气系统为游泳和潜水添加体力值Stamina和氧气值Oxygen。快速游泳消耗体力体力耗尽则速度下降潜水消耗氧气氧气耗尽开始损失生命值。这能立刻增加游戏的策略性和紧张感。水下特效与音效根据深度和速度动态调整后处理效果如色差、模糊、颜色滤镜来模拟水下视觉。同时切换水下混响Reverb和声音衰减Attenuation让音频也有沉浸感。载具与道具将这套系统应用到小船、潜水艇等载具上或者制作需要上浮的救生衣、增加下潜速度的配重等道具。网络同步如果你在做多人游戏所有状态SwimState、ImmersionDepth和施加的力都需要在服务器和客户端之间进行可靠的复制Replication并做好预测和纠偏防止不同玩家看到的位置不一致。最终这套基于蓝图的水世界角色控制系统其价值在于提供了一个高度可定制、手感可调的解决方案。它剥离了物理引擎的“黑盒”让你能亲手塑造每一个交互细节。从浮力到阻力从动画融合到状态切换每一个参数都触手可及。调试过程可能充满反复但当你的角色在水世界中自如穿梭动画与操控浑然一体时那种成就感是无可替代的。

相关新闻

KeymouseGo:5分钟上手!免费鼠标键盘录制工具彻底解放你的双手

KeymouseGo:5分钟上手!免费鼠标键盘录制工具彻底解放你的双手

KeymouseGo:5分钟上手!免费鼠标键盘录制工具彻底解放你的双手 【免费下载链接】KeymouseGo 类似按键精灵的鼠标键盘录制和自动化操作 模拟点击和键入 | automate mouse clicks and keyboard input 项目地址: https://gitcode.com/gh_mirrors/ke/Keymou…

2026/10/14 13:45:12 阅读更多 →
Chrome自动播放策略解析:从本地文件到生产环境的实战解决方案

Chrome自动播放策略解析:从本地文件到生产环境的实战解决方案

1. 问题根源:为什么Chrome不让我的网页自动播放了? 如果你最近在用Chrome浏览器打开本地HTML文件,或者部署一个简单的网页demo时,发现背景音乐不响了,开场视频卡住了,第一反应可能是:“我的代码…

2026/10/2 14:01:46 阅读更多 →
如何一键重置JetBrains IDE试用期:3步简单操作指南

如何一键重置JetBrains IDE试用期:3步简单操作指南

如何一键重置JetBrains IDE试用期:3步简单操作指南 【免费下载链接】ide-eval-resetter 项目地址: https://gitcode.com/gh_mirrors/id/ide-eval-resetter JetBrains IDE试用期重置工具是一款专为开发者设计的免费开源插件,能够智能清理IDE评估信…

2026/10/14 22:33:54 阅读更多 →

最新新闻

Matplotlib图表美化:Spines与坐标轴设置全攻略

Matplotlib图表美化:Spines与坐标轴设置全攻略

做数据可视化这几年,我越来越觉得,一张图好不好看,关键不是配色多花哨、特效多炫技,而是那些最容易被忽略的“基础件”处理得干不干净。Matplotlib作为Python生态里最常用的绘图库,功能确实强大,但默认出图…

2026/10/16 0:13:12 阅读更多 →
Delphi 老兵用 TMS WEB Core 写 Web:环境搭建、组件模型与前后端通信实战

Delphi 老兵用 TMS WEB Core 写 Web:环境搭建、组件模型与前后端通信实战

简介:这份PDF教程面向希望用Delphi切入Web前端开发的初学者与进阶开发者,围绕TMS WEB Core框架讲解如何以Delphi或Lazarus快速构建网站、Web应用及跨Windows、Mac、iOS、Android、Linux的App。内容从Delphi/Object Pascal的历史与现状讲起,对…

2026/10/16 0:13:12 阅读更多 →
Matlab电场仿真入门:线电荷离散化与可视化三部曲

Matlab电场仿真入门:线电荷离散化与可视化三部曲

简介:本资源是一份面向电子信息、物理电子及电磁场相关专业本科生的Matlab仿真实验报告,聚焦线电荷电场与电位分布的数值建模与可视化。通过库仑定律、电场强度定义及势函数积分原理,结合Matlab矩阵运算、网格生成(meshgrid&#…

2026/10/16 0:13:12 阅读更多 →
京东2020首页高仿:CSS布局、滚动动效与性能优化实战

京东2020首页高仿:CSS布局、滚动动效与性能优化实战

1. 项目概述:这不是“抄界面”,而是一次前端布局与动效的系统性复盘“高仿京东2020版首页布局及刷新效果”——这个标题乍看像学生作业,实则藏着前端工程师日常攻坚中最硬核的三重关卡:结构语义化落地能力、响应式断点控制精度、以…

2026/10/16 0:13:12 阅读更多 →
SAS数据步行列变换:宽表转长表与混合类型处理实战

SAS数据步行列变换:宽表转长表与混合类型处理实战

1. 项目概述:为什么“行列变换”是SAS数据步里最常被低估的硬功夫?在某高校统计实验室带学生做课程设计时,我见过太多人把SAS当成“高级Excel”来用——导入数据、跑个proc means、画张直方图,就以为掌握了。直到某次模拟项目X中&…

2026/10/16 0:13:12 阅读更多 →
多端口隔离聊天室:用TCP端口实现天然通信域划分

多端口隔离聊天室:用TCP端口实现天然通信域划分

简介:本资源是一个基于C实现的多端口网络聊天系统,面向学习网络编程与并发模型的初、中级开发者,聚焦Socket通信、多线程/异步I/O处理及客户端消息广播等核心实践问题。项目通过服务器监听多个端口,支持多个客户端同时接入并实时互…

2026/10/16 0:12:11 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

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

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/15 9:49:14 阅读更多 →