尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
FPS角色移动:从撞墙卡死到顺滑贴墙
玩 FPS 你肯定有这体感:斜着撞上一堵墙,人不会当场钉死在那,而是顺着墙面滑走,还能继续往前蹭。这个手感太理所当然了,以至于没人觉得它是个需要设计的东西。但你要是自己写移动,第一版八成就是撞到就停,玩起来像被墙粘住,难受得要命。这篇讲的就是从撞到停死到贴墙滑走这中间发生了什么。这套东西业内叫 Collide-and-Slide,碰撞加滑动,是几乎所有 FPS 角色移动的底层。照旧,全程定点数,坐标单位米。先看停死版本错在哪最朴素的移动是这样:算出这一帧想去的位置,检测一下路上撞没撞到东西,撞到了就别动。voidMove(refFixVector3pos,FixVector3velocity,Fixdt){FixVector3targetposvelocity*dt;// 这帧想去的地方if(SweepHit(pos,target,outvarhit)){// 撞到了……那就别动了return;// ← 停死罪魁祸首}postarget;}问题出在return这一下。玩家明明是斜着撞墙的,他的运动里其实一部分是往墙里钻,另一部分是沿着墙走。往墙里钻的那部分该拦,没问题;但沿着墙走的那部分是完全合法的,你一个return把两部分一起毙了,人就贴墙上不动了。所以关键不是撞到了要不要停,而是撞到了,把运动拆开,只砍掉不合法的那部分,合法的那部分放行。核心就一个动作:把速度拍到墙面上想通了上面那点,解法就浮出来了。撞墙的时候,墙会给你一个法线——就是垂直于墙面、指向外面的那个方向。玩家的速度向量,可以沿着这个法线拆成两块:墙面法线 N ↑ | 玩家速度 V | ↗ | ╱ ─────────┼──────╱──────── 墙面 | ╱ | ╱ |╱ V 拆成两块 一块顺着 N钻进墙里的分量—— 要砍掉 一块沿着墙面滑动的分量 —— 要保留怎么拆?靠点积。速度 V 在法线 N 上的投影长度,就是Dot(V, N)。这个值代表 V 有多少是朝着法线方向去的——也就是有多少在往墙里钻。拆出来之后,把钻墙那部分从 V 里减掉,剩下的自然就是沿墙滑那部分:// 把速度投影到墙面上去掉钻进墙里的分量staticFixVector3ProjectOnPlane(FixVector3v,FixVector3normal){FixdistFixVector3.Dot(v,normal);// v 有多少朝着法线方向returnv-normal*dist;// 减掉这部分剩下的贴着墙面}就这三行,是整个滑动手感的心脏。normal * dist是钻墙分量,v减掉它,留下的就是平行于墙面的滑动速度。这个操作数学上叫把向量投影到平面上,名字唬人,干的事就是把往墙里去的劲儿抽掉。这里要提醒一句,Dot内部是三个分量各自相乘再相加,每个乘法都是定点乘法,中间值会暴涨,前面反复讲过的那个 64 位防溢出的坑,这儿照样存在。你的FixVector3.Dot底层必须把中间乘积提到 long,不然大坐标下点积直接溢出,滑动方向瞬间乱套。一次滑动的完整流程有了投影,把移动逻辑重写一遍:voidMove(refFixVector3pos,refFixVector3velocity,Fixdt){FixVector3remainingvelocity*dt;// 这帧还剩多少位移要走if(SweepHit(pos,posremaining,outvarhit)){// 走到撞墙点先把撞之前那段路走完poshit.point;// 剩下没走完的位移拍到墙面上改方向继续滑FixVector3leftover(posremaining)-hit.point;remainingProjectOnPlane(leftover,hit.normal);// 顺便把速度本身也拍一下不然下一帧又直直撞上来velocityProjectOnPlane(velocity,hit.normal);}posremaining;}流程说白了三步:走到撞墙那一点停下,把没走完的路折向墙面,顺着新方向把剩下的路走完。速度也得跟着拍一下,否则这帧滑走了,下一帧速度还是原来那个直冲墙的方向,又撞上,白忙活。一次滑动不够,要能连着滑上面这版有个隐患。你斜着撞墙滑走,滑着滑着可能又撞上另一堵墙——比如墙角。这时候你只做了一次投影就pos remaining收工,那第二堵墙就漏检了,人会直接穿进墙角里。所以真正的 Collide-and-Slide 是循环的:滑动之后再检测,又撞到就再滑,直到这帧的位移全部走完,或者撞够了次数为止。voidMove(refFixVector3pos,refFixVector3velocity,Fixdt){FixVector3remainingvelocity*dt;constintMAX_SLIDE4;// 最多滑 4 次够用且防死循环for(inti0;iMAX_SLIDE;i){if(!SweepHit(pos,posremaining,outvarhit)){posremaining;// 一路无阻走完收工return;}poshit.point;// 走到这次的撞墙点FixVector3leftover(posremaining)-hit.point;remainingProjectOnPlane(leftover,hit.normal);// 折向墙面velocityProjectOnPlane(velocity,hit.normal);}// 滑够 4 次还在撞墙角、夹缝剩下的位移就不走了防止卡进几何体posremaining;}MAX_SLIDE这个上限很重要。墙角、V 字形夹缝这种地方,你滑向 A 墙又撞 B 墙,滑向 B 墙又撞 A 墙,不设上限能无限循环下去,一帧卡死。设个 4 次,既够处理绝大多数复杂几何,又能兜住死循环。撞满 4 次还在撞,说明玩家钻进了个特别刁钻的角落,这时候宁可让他停一下,也不能让游戏卡住。为什么这套东西非定点不可你可能想,滑动手感是表现层的东西,用 float 算算得了,反正玩家又看不出那点误差。在竞技 FPS 里这想法要命。角色位置是权威状态,它要参与服务器校验、参与延迟补偿回放、参与命中判定。你在客户端用浮点滑出来一个位置,服务器用浮点滑出另一个略微不同的位置,两边一对不上,轻则位置回弹(玩家看着自己被拽回去,俗称橡皮筋),重则整局 desync。而滑动这套逻辑里全是点积、向量减法、乘法——正好都是定点数逐比特一致的强项。同样的输入、同样的墙、同样的法线,红米和 iPhone 和服务器滑出来的位置,连最低位都一样。这样服务器校验才有意义,延迟补偿倒带才能精确复现你当时到底贴在墙的哪个位置。这也是为什么滑动逻辑必须整个待在定点模拟层里,连那个ProjectOnPlane都不能图省事转 float 算。一处泄漏,满盘皆输——这话在这个系列里说过好几遍了,但每一处都是真金白银的教训。几个手感上的延伸基础的贴墙滑讲完了,顺带说几个让手感更真实的常见处理,不展开写代码,给你个方向:地面和斜坡。走斜坡本质也是滑动,只不过法线朝上。你走上一个缓坡,速度被投影到坡面上,人就顺着爬上去了;坡太陡,投影完向上的分量太小,人就爬不动往下出溜——滑动这套逻辑天然就把斜坡处理了,不用额外写。台阶。想让玩家能自动迈上小台阶而不是被矮墙挡住,得在撞到矮障碍时先试着抬高一点再往前探,探到了就踩上去。这叫 step offset,是 Collide-and-Slide 之上加的一层。保留下落。人在空中斜撞墙,水平方向该被墙挡住并滑走,但竖直方向的重力下落不该被影响。所以有些实现会把水平滑动和竖直下落分开算,别让投影把重力也给抹了。收尾回到最开始那个问题:为什么撞墙不停死、要滑走?因为玩家斜着撞墙时,他的运动里往墙里钻和沿墙走是两码事。停死是把两者一起毙了,粗暴。正确做法是用点积把速度沿墙面法线拆开,只砍掉钻墙那部分,保留沿墙那部分——这就是ProjectOnPlane那三行干的事。再套上一个滑完再检测的循环处理墙角,配一个次数上限防死循环,一套顺滑的角色移动就成了。而这一切之所以能放心用,是因为底下全是定点数的点积和向量运算,逐比特一致,服务器和每个客户端滑出来的位置分毫不差。手感是玩家感受到的,确定性是玩家感受不到、但一旦缺了就满屏橡皮筋的东西。好的移动手感,就是这两样在底下悄悄咬合的结果。
RELATED

相关推荐

基于Spring Boot的“暖暖小屋”咖啡馆管理系统的设计与实现

基于Spring Boot的“暖暖小屋”咖啡馆管理系统的设计与实现

摘要本文详细阐述了基于Spring Boot框架的“暖暖小屋”咖啡馆管理系统的设计与实现过程。文章首先介绍了项目的背景意义与技术栈选型,随后从需求分析、系统设计、数据库设计、核心功能实现等多个维度展开,并提供了关键模块的代码示例。该系统旨在通过信息…

📅 2026/11/7 15:29:35
汽车行业数据分析:从销量与等车周期解读市场供需与产品策略

汽车行业数据分析:从销量与等车周期解读市场供需与产品策略

1. 从一则行业快讯说起:数据背后的市场逻辑最近看到一则汽车行业的快讯,标题是“广汽丰田销售6.8万辆 凯美瑞需等1-2月提车”。这短短一句话,其实包含了非常丰富的市场信息,远不止一个简单的销量数字和提车周期那么简单。对于汽车…

📅 2026/10/7 5:00:47
Arduino QuickFFT:用精度换速度,实现8位MCU实时频谱分析

Arduino QuickFFT:用精度换速度,实现8位MCU实时频谱分析

1. 项目缘起:为什么Arduino需要一个“快但糙”的FFT?如果你玩过Arduino上的音频可视化、频谱分析或者简单的振动监测,大概率听说过或者尝试过FFT(快速傅里叶变换)。FFT是个好东西,它能把时域信号&#xff0…

📅 2026/10/8 19:36:11
MORE NEWS

更多资讯

📰

电工的工作业绩和能力在哪考怎么转省证

电工的工作业绩和能力在哪考怎么转省证 之前考的证在外省能不能转过来?这是很多电工最关心的问题,尤其是在跨省打工或换工作时,证书能不能顺利“搬家”成了关键。别急,先说结论:…

📰

工地太忙根本没时间复习考试?电工证熔断器答题技巧+含金量全解析

工地太忙根本没时间复习考试?电工证熔断器答题技巧+含金量全解析 工地太忙根本没时间复习考试,这是很多特种作业人员的真实写照。尤其是像电工证这种涉及安全操作的证书,考试内容不仅专业,还包含大量实操题和理论题,比如 熔断器答题技巧…

📰

电工的工作业绩和能力值不值得考?真实案例告诉你答案

电工的工作业绩和能力值不值得考?真实案例告诉你答案 你是不是也遇到过这种情况:刚找了个电工的工作,结果入职时被告知“必须有特种作业操作证才能上岗”?别急,这正是我们今天要聊的—— 电工的工作业绩和能力值不值得考…

📰

哪个电工证最吃香行业前景与薪资待遇

你拟定的标题 哪个电工证最吃香 电子证书怎么申请和复审最省心 证书过期了不知道怎么复审延期?你不是一个人。尤其是在周口市从事市政公用工程的电工,经常因为工作繁忙错过复审时间,导致电子证书失效,影响项目进度和职业发展。很多人不知道的是,…

📰

工地电工证要怎么考?上岗必备证件怎么拿?太忙也没关系

工地电工证要怎么考?上岗必备证件怎么拿?太忙也没关系 工地太忙根本没时间复习考试,这话真不是夸张。每天早出晚归,手头活儿堆成山,哪还有精力去背那些电工理论和操作规范?但别小看这本工地电工证,它可是 上岗必备…

📰

中级电工证电工上岗证值不值得考?工地太忙根本没时间复习考试

中级电工证电工上岗证值不值得考?工地太忙根本没时间复习考试 工地太忙根本没时间复习考试,这几乎是每个一线电工都面临的现实问题。你是不是也常常觉得, 中级电工证电工上岗证…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬