news 2026/10/26 13:38:03

Unity PlatformEffector2D 实现2D单向平台与下穿详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Unity PlatformEffector2D 实现2D单向平台与下穿详解

横版过关里那种"从下往上跳能穿过去、从上面掉下来能站住、站着按一下键还能掉下去"的浮空平台,几乎是2D平台跳跃的标配。我最早做这块的时候用了很笨的办法:给平台挂触发器,角色一进来就把碰撞体关掉,结果角色在半空被顶飞、贴着边缘抖、跳到一半突然掉下去,全来了。后来项目里统一换成 PlatformEffector2D,问题一下少了大半,剩下的都是参数和恢复时机上的细节。这篇就把我在横版过关项目里做单向通行(One Way Platform)的完整做法摊开讲:组件到底怎么挂、Used By Effector 为什么是最容易漏的一步、Surface Arc 这个看着像"角度装饰"的参数其实直接决定边缘手感、下穿逻辑怎么写才不抖不断,以及一份我自己用了很久的排查清单。内容适合已经摸过 Rigidbody2D 和 Collider2D、正在做2D平台跳跃的新手,也适合已经上了 Effector 但被"角色黏在平台侧边"折磨过的老手。

1. 单向通行的本质:需求先拆清楚再选方案

1.1 从"跳上去卡住"说起,一条平台其实有五个需求

很多人以为单向平台就是"从下面能穿",实际做起来会发现这是五个互相牵制的需求,少一个玩家就会觉得别扭。第一个,角色从下方起跳、以向上的速度接触平台时,必须完全忽略这次碰撞,不能有半点减速或者被顶一下的感觉。第二个,角色从上方下落、以向下的速度接触平台时,必须正常站住,并且站稳之后不能因为重力累积而缓慢下沉。第三个,角色站在平台上左右移动,走到平台边缘之外要自然掉落,不能"悬空踩着空气"。第四个,站着的时候按方向下加跳跃键,要能主动下穿,而且下穿过程中不能再被这块平台挡住。第五个,角色从平台侧面水平撞过去(比如从旁边的墙跳过来),不能被弹飞或者卡住不动。

这五条里,第三条和第五条是最容易被忽略的。我见过不少项目,前两条做得很顺,结果玩家在平台边缘反复横跳时会出现"半个身子悬在外面还能站着"的诡异画面,原因就是碰撞体比角色视觉宽,或者平台的 Composite Collider 合并后的轮廓比想象中大。所以动手之前,我建议先拿张纸把这五条列出来,做完之后逐条测,比事后到处救火省事得多。

1.2 三条常见路线的取舍,为什么我最后选了 Effector

做单向通行大致有三条路,每条我都实际用过,优缺点很明显。

路线核心做法优点主要问题
触发器开关碰撞体OnTriggerEnter2D 里把平台 collider.enabled 设为 false上手最快,逻辑直观物理帧与触发帧不同步,高速下落会直接穿过去;角色停在触发器范围内时碰撞体一直关着,人直接掉下去
射线检测改碰撞关系每帧打射线判断角色在平台上还是下,动态调 IgnoreCollision 或换 Layer可控性极强,能做出各种花样状态机很容易写乱,多平台叠加、平台移动、角色贴边时判断条件爆炸
PlatformEffector2D引擎层按碰撞法线与相对运动方向做单向判定几乎不用写代码,稳定,性能好判定方向强依赖 transform.up,灵活性靠补丁补

第一条路的问题在于"时机"。触发器回调和物理求解不在同一拍上,角色速度一快,触发器的回调还没跑到,人已经穿过去了;而且角色站在平台上时,如果碰撞体是关的,重力会直接把人拽下去,你得再加一套"站住了就打开"的逻辑,越写越像在跟引擎打架。

第二条路不是不能用,如果你要做"只看角色脚底一小段"的精细判定,它确实更自由。但它本质上是自己实现一遍物理判定,边界情况多得吓人,我在一个项目里为了修"下穿后立刻被顶回去"的 bug 花了两天。

第三条路把判定交给引擎,我只要负责"什么时候允许穿"这一件事,工作量直接砍掉一大半。所以我的默认选择是 PlatformEffector2D,遇到它办不到的需求(比如同一块平台对玩家单向、对敌人实体),再在它上面打补丁。

1.3 组件挂上去没反应?先检查 Used By Effector

这是新手踩得最多的一脚,包括我自己。PlatformEffector2D 挂在平台上、参数全开,跳上去照样被挡住,翻半天文档才发现问题不在 Effector 上,而在 Collider2D 上那个不起眼的复选框:Used By Effector。

它没勾,Effector 就是一个纯装饰组件,引擎根本不拿它参与碰撞求解。所以每次我新建平台,动作顺序固定是:先加碰撞体,再把 Used By Effector 勾上,最后加 PlatformEffector2D。反过来做,很容易在中间某一步漏掉。另外还有两个隐性前提:一个碰撞体同一时间只能被一个 Effector 驱动,别想着叠两个;碰撞体不能是 Trigger,Trigger 根本不参与实体碰撞,Effector 自然也无从下手。这两点看起来是常识,但真出问题的时候,人往往先怀疑参数,最后才发现是这两个开关。

2. 平台怎么搭:组件关系与参数落地

2.1 挂载结构与三种平台的差异

静态平台的搭法最简单:一个空 GameObject 加 BoxCollider2D,勾上 Used By Effector,再挂 PlatformEffector2D,完事。平台本身不需要 Rigidbody2D,引擎会把它当作静态碰撞体处理,性能上是划算的。

移动平台就得多加一个 Rigidbody2D,Body Type 设成 Kinematic,Interpolate 打开。这里有个细节值得说:Kinematic 刚体移动时最好用MovePosition或者直接改linearVelocity(老版本叫velocity),别在 Update 里直接改 transform.position。直接改位置等于瞬移,物理系统拿不到速度信息,站在上面的角色不会被"带着走",表现就是人在移动平台上原地打滑。我一般会给移动平台配一个简单的位移组件,把速度算出来写进刚体,这样角色站在上面能被正确带飞。

瓦片地图做的平台要注意层级:Tilemap 上挂 TilemapCollider2D,再加 CompositeCollider2D 把碎块合成一个整体轮廓,勾 Used By Effector 的是CompositeCollider2D,不是 TilemapCollider2D。勾错的话要么完全没效果,要么只有部分瓦片生效,排查起来很折磨人。合成之后记得把 CompositeCollider2D 的 Geometry Type 设成 Outlines,能省不少顶点。

2.2 参数逐个拆:哪些能调,哪些别碰

PlatformEffector2D 的参数不多,但每一个都有明确的物理含义,我按"改不改"分成三类。

参数含义常规平台取值我的建议
Use One Way是否启用单向判定开关掉就退化成实体平台,做可破坏平台时可以用它切换状态
Use One Way Grouping多个碰撞体是否作为整体参与单向判定复合碰撞体、瓦片地图时开单碰撞体的平台关着就行
Surface Arc被当作"平台面"的角度范围,以局部上方向为中心向两侧展开180别乱调,见 3.2
Use Side Friction侧面是否施加摩擦关开了必黏边,除非你就是要这个手感
Use Side Bounce侧面是否施加弹力关想做弹跳墙才开
Side Arc侧弧角度,由 Surface Arc 自动推算自动只读,不用管
Rotational Offset单向方向相对局部上方向的偏移角0斜坡素材不能旋转时用它救场
Collider Mask哪些层的碰撞体受这个 Effector 约束默认全部出问题先确认没被改成空

Use Side Friction 这一项我想多说两句。它的作用是给"侧弧"范围内的接触面加摩擦,听起来挺合理,实际表现是角色贴着平台侧边往上跳的时候会被"吸住"一下,落地时如果脚趾刚好擦到平台侧边,人会贴着边缘慢慢滑下去而不是直接掉。这个手感非常糟糕,所以我的习惯是永远关掉它,需要侧面摩擦的场合(比如贴着墙缓降)单独做一层墙体碰撞体,别跟单向平台混在一起。

Use One Way Grouping 这个选项文档里的描述比较抽象,我的理解是:当同一块平台由多个碰撞体拼成时,如果不分组,每个碰撞体各自做一次单向判定,角色在拼接处就可能出现"一只脚被这块挡住、另一只脚从旁边穿过去"的情况;开了分组,这些碰撞体在判定上被当作一个整体,行为就统一了。用 Composite Collider 的场景基本可以无脑开。

Collider Mask 我吃过一次亏:某次为了做"单向平台只对玩家生效",把这个 Mask 改成了只包含玩家层,结果敌人确实能穿过去了,但玩家站在平台上时也没法被平台的其他逻辑检测到,地面检测直接失效。后来改成"平台层不变,敌人层不与平台层碰撞",问题解决。Mask 尽量别动,多角色需求用 Layer 碰撞矩阵解决更干净。

2.3 角色那边也得配合,不然 Effector 白搭

平台配完了,角色没配好照样出问题。我的角色 Rigidbody2D 一般这样设:Body Type 选 Dynamic,Gravity Scale 根据手感在 3 到 6 之间,Freeze Rotation Z 一定要勾上(不勾的话角色会在落地瞬间被物理引擎转个角度),Collision Detection 根据最高下落速度决定,速度快就上 Continuous,Interpolate 打开让视觉更顺滑。

碰撞体形状是个容易被低估的点。CapsuleCollider2D 在斜坡上滑得顺,但它的底部是个圆角,角色下落时如果脚正好落在平台边缘的角附近,那个圆角很容易"咬"住平台,表现为落地后被轻轻弹开或者卡在边缘。BoxCollider2D 落地更干脆,但走斜坡会一顿一顿的。我的做法是角色用 CapsuleCollider2D,但把底部半径压小,同时给平台碰撞体保证至少 0.2 个单位的厚度,让落点判定有余量。如果项目里斜坡不多,直接上 Box 更省心。

摩擦力这块,我建议在角色身上挂一个 Physics Material 2D,Friction 设 0 或者很低,Bounciness 设 0。平台不加材质。这样所有平台的摩擦手感由角色统一控制,改一次全局生效;反过来做(每个平台加材质)项目一大就彻底失控。真正需要"冰面"手感的地面,再单独给它加低摩擦材质覆盖角色设置。

3. 机制深挖:判定方向、表面弧与下穿

3.1 transform.up 决定一切,这条要记牢

单向平台"哪一面是实心的",完全由平台 GameObject 的局部上方向(也就是 transform.up,场景里那根绿箭头)决定。绿箭头指哪边,哪边就是可以站的地板面。

这条规则带来两个直接结论。第一,平台旋转 Z 轴 180 度,实心面就翻到下面去了,角色会变成从上方穿过去、站到平台底部。所以别随手旋转平台,转之前想清楚。第二,绝对不要用负缩放来翻转平台,负缩放会让局部坐标系整体反号,单向判定直接乱掉,表现是"有时候能站有时候不能站",这种问题极难查。要翻转视觉表现,用 SpriteRenderer 的 Flip X,别动 Transform 的 Scale。

斜坡同理:平台转 30 度,transform.up 跟着转 30 度,判定面自动贴着斜坡走,这种情况下你什么都不用改。

3.2 Surface Arc 的几何含义,别为了"更好穿"去调小它

Surface Arc 描述的是"以局部上方向为中心,向两侧各展开多少角度"的范围,默认 180 度,也就是一个完整的半圆。落在弧内的接触面被当作"平台面"处理——单向判定加上摩擦;弧外的部分被平分成左右两个侧弧,按"墙面"对待,始终是实体,是否带摩擦弹力由那两个 Side 开关决定。

这意味着 Surface Arc 越小,侧弧占的比例就越大,平台左右两端"像墙"的区域就越厚。角色从斜下方贴着平台角往上跳的时候,接触法线可能落在侧弧里,于是被当成撞墙处理,人被挡下来——这大概就是"明明是从下面跳却被卡住"的常见来源之一。

所以我的建议是:常规平台保持 180,不要动。只有在做斜坡单向平台、或者想刻意制造"边缘能挂一下"的手感时,才试着往下调到 165 到 175 之间,并且改完一定要实机跑一遍完整的跳跃测试:从下方正中跳、从下方贴边跳、从上方正中落、从上方贴边落、站在边缘横移掉下去。这五个动作跑完没问题,才算调对了。

3.3 侧边黏住的两个开关,按顺序关

角色黏在平台侧边的现象我在三个项目里都遇到过,基本是这两个原因之一。

第一顺位检查Use Side Friction是不是被勾上了,勾了就关掉,八成能解决。第二顺位看平台的碰撞体是不是比视觉宽 —— 尤其是用了 Composite Collider 或者 Sprite 自带物理形状的情况,轮廓会往外扩一圈,角色看着是站在平台边缘,实际早就压在碰撞体上了。这种情况下把碰撞体轮廓往里收一点即可,Unity 的 Sprite 编辑器里可以直接编辑物理形状的顶点。

还有一种更隐蔽的情况:角色自己身上有其他碰撞体(比如攻击判定、拾取范围)没设成 Trigger,无意中和平台发生了碰撞。这类问题看现象非常像 Effector 的问题,实际一查是别的碰撞体在作妖,我是靠 Physics2D 的碰撞回调把接触双方的名字打出来才定位到的。

3.4 下穿(Drop Through)的三种做法与取舍

站着按方向下要能掉下去,这件事 Effector 本身不管,得自己写。常见三种做法,我按推荐度排序。

做法一:临时忽略碰撞(推荐)。用Physics2D.IgnoreCollision把角色碰撞体和脚下这块平台碰撞体的碰撞关系临时关掉,持续一小段时间后恢复。优点是只影响这两个碰撞体,角色其他碰撞体、其他平台全都不受影响;缺点是恢复时机要算准,恢复早了会被顶回去,恢复晚了角色穿过平台后可能又被吸住。

做法二:临时切成 Trigger。把平台的 Collider2D 设成 isTrigger,掉下去之后再改回来。问题是平台一旦变成 Trigger,所有站在它上面的角色(包括敌人、其他物体)都会一起掉,多人场景直接崩。除非你的游戏里这类平台永远只有一个角色会站,否则别用。

做法三:换 Layer。把角色切到"不与平台碰撞"的层,等掉出平台范围再切回来。问题是切层是全局生效的,如果角色此时正站在另一块同层的平台上,也会一起穿过去。多层平台堆叠的场景特别容易出 bug。

我选做法一,并且把它写成一个独立组件,任何角色挂上就能用。

3.5 忽略时长到底设多少,给个算式

忽略时长不能拍脑袋。太短了角色还没离开平台碰撞体,碰撞一恢复就会被顶回平台上;太长了玩家会觉得"掉下去要等一下才动",操作发黏。

粗略的算法是:忽略时长 ≥ (平台碰撞体厚度 + 角色碰撞体高度) ÷ 角色下落时的速度,再取一个安全系数。举个例子,平台厚 0.3 单位,角色碰撞体高 1.0 单位,重力 4、起跳下落初速度约 0,落到平台时被忽略后开始加速,取下落一段后的平均速度 8 单位每秒,那么 (0.3 + 1.0) ÷ 8 ≈ 0.1625 秒,取 1.5 倍安全系数就是 0.24 秒左右,实际取 0.25 秒比较舒服。

这只是基准值,手感还得靠实机调。项目里我一般把时长做成可配置字段,先在编辑器里调,调好了再固化到预制体上。另外一定要在恢复碰撞之前做一次"是否还在平台范围内"的检查,不然角色刚离开就被恢复的话,还是会有一帧被顶的感觉。

4. 从零到可用:一份能直接抄的实操流程

4.1 场景搭建的十步

  1. 新建空物体命名 Platform_OneWay,位置放在关卡需要的高度。
  2. 加 BoxCollider2D,把 Size 调成你想要的平台尺寸,厚度不要低于 0.2。
  3. 勾上 BoxCollider2D 的Used By Effector。这一步最容易漏,做完回头看一眼。
  4. 加 PlatformEffector2D,确认 Use One Way 勾上。
  5. 确认 Use Side Friction 和 Use Side Bounce 都没勾。
  6. Surface Arc 保持 180,Rotational Offset 保持 0。
  7. 给平台加个 SpriteRenderer 或者交给 Tilemap 渲染,视觉宽度比碰撞体略大一点点,玩家会觉得"看着能站就能站"。
  8. 角色身上:Rigidbody2D 设 Dynamic,Freeze Rotation Z,Gravity Scale 4 左右。
  9. 角色身上:CapsuleCollider2D,底部半径压小;加 Physics Material 2D,Friction 为 0。
  10. 给角色挂下穿组件,把角色的碰撞体和平台层 Mask 填进去。

跑一遍五个基础动作,都过了再往下做。

4.2 下穿组件的完整实现

下面这份是我项目里一直在用的版本,做了简化,能直接跑。核心思路是:先用一个薄薄的探针盒在脚底找脚下的平台碰撞体,找到之后逐个忽略,等一段时间再检查一次脚下,确认离开了才恢复。

using System.Collections; using UnityEngine; [RequireComponent(typeof(Rigidbody2D))] public class OneWayDropThrough : MonoBehaviour { [SerializeField] private Collider2D bodyCollider; [SerializeField] private LayerMask platformMask; [Tooltip("忽略碰撞的基础时长,按平台厚度和下落速度估算")] [SerializeField] private float ignoreDuration = 0.25f; [Tooltip("恢复碰撞前的额外等待上限")] [SerializeField] private float maxExtraWait = 0.5f; private readonly Collider2D[] probeHits = new Collider2D[8]; private Coroutine running; private Collider2D[] ignored = new Collider2D[8]; private int ignoredCount; public bool IsDropping => running != null; public bool TryDrop() { if (running != null) return false; if (!IsStandingOnOneWayPlatform()) return false; running = StartCoroutine(DropRoutine()); return true; } private bool IsStandingOnOneWayPlatform() { int count = ProbeFeet(); for (int i = 0; i < count; i++) { if (probeHits[i].GetComponent<PlatformEffector2D>() != null) return true; } return false; } private int ProbeFeet() { Bounds b = bodyCollider.bounds; Vector2 center = new Vector2(b.center.x, b.min.y - 0.02f); Vector2 size = new Vector2(Mathf.Max(b.size.x - 0.06f, 0.05f), 0.08f); return Physics2D.OverlapBoxNonAlloc( center, size, 0f, probeHits, platformMask); } private IEnumerator DropRoutine() { ignoredCount = ProbeFeet(); if (ignoredCount == 0) { running = null; yield break; } for (int i = 0; i < ignoredCount; i++) { ignored[i] = probeHits[i]; if (ignored[i] != null) Physics2D.IgnoreCollision(bodyCollider, ignored[i], true); } float t = 0f; while (t < ignoreDuration) { t += Time.deltaTime; yield return null; } float extra = 0f; while (extra < maxExtraWait && ProbeFeet() > 0) { extra += Time.deltaTime; yield return null; } for (int i = 0; i < ignoredCount; i++) { if (ignored[i] != null) Physics2D.IgnoreCollision(bodyCollider, ignored[i], false); ignored[i] = null; } ignoredCount = 0; running = null; } }

调用侧就一行,在角色控制里判断输入:

if (inputDropPressed && isGrounded) { dropThrough.TryDrop(); // 关键:立刻给一个向下的初速度,别等重力慢慢加速 rb.linearVelocity = new Vector2(rb.linearVelocity.x, -dropInitialSpeed); }

这里有个细节值得单独拎出来:按下的瞬间要主动给一个向下速度。只靠重力,角色会有一小段时间"贴着平台不动",因为重力还没积累起来,玩家会觉得按键没反应。给一个初始向下速度(我一般取 5 到 8),下穿会干脆很多。注意这一脚别给太大,给大了角色会像被弹射下去一样。

另外linearVelocity是较新版本的字段名,老工程里对应的是velocity,两个都存在过一段时间,按你项目用的版本写就行,别混着抄。

4.3 验收清单,五加三

做完之后按这张表跑一遍,全过再提交。

测试动作期望表现不通过时先查
从下方正中跳起穿过完全无阻挡,速度不受影响Used By Effector 是否勾上
从下方贴边跳起不被卡住,能穿过或被轻微推开但不停止Surface Arc 是否被调小、侧摩擦是否关了
从上方落下站住站稳不下沉、不抖动角色摩擦材质、重力与碰撞检测模式
站在边缘横移走出边缘自然掉落碰撞体轮廓是否比视觉宽
按下加跳跃下穿干脆下坠,不反弹是否给了向下初速度、忽略时长是否过短
下穿后立刻起跳能正常跳上其他平台碰撞恢复时机
连续快速下穿两次第二次不会卡在半空协程重入是否被拦住
站在移动平台上随行跟随移动不滑落平台是否用 MovePosition 移动

最后一条经常被忽略。移动平台上的单向通行是另一个故事:平台在动,Effector 的判定方向不变,但角色的相对速度变了,站在上面如果平台向下走,角色可能出现"短暂脱离平台再落回"的顿挫。我的处理是给移动平台加一点点向上位移补偿,或者干脆在移动平台上把角色的父级临时改成平台(我不太喜欢这个做法,遇到角色死亡、传送会出乱子,慎用)。

5. 踩过的坑与排查速查

5.1 问题速查表

现象大概率原因处理方式
加了 Effector 完全没效果Used By Effector 没勾 / 碰撞体是 Trigger勾上复选框,取消 Trigger
从下方跳被挡住平台旋转过导致 up 方向反了 / 负缩放检查 Z 轴旋转和 Scale
从上方落下却穿过去平台被旋转了 180 度 / Transform.up 被父物体带偏检查父级旋转,必要时重置
角色贴着平台侧边慢慢滑Use Side Friction 被开启关掉
落地瞬间被轻弹一下角色碰撞体摩擦材质 Bounciness 不为 0 / 胶囊底部圆角咬边材质 Bounciness 归零,压小底部半径
下穿一半被顶回来忽略时长太短,或者恢复碰撞前没检查重叠加长时长,恢复前做探测
角色站在平台上自己缓慢下沉碰撞检测模式不合适,或者平台被做成 Kinematic 后在移动开 Continuous,检查平台位移方式
站在平台边缘悬空Composite 轮廓比视觉大编辑物理形状顶点

5.2 三个印象最深的坑

第一个是高速下落穿模。有个项目角色下落速度能到 25 单位每秒,单向平台怎么调都会偶尔穿过去。查了很久才想明白:问题不在 Effector,而在离散碰撞检测本身。物理步长 0.02 秒,25 单位每秒意味着一步走 0.5 个单位,平台厚度只有 0.3,这一步直接跳过去了,引擎根本没检测到接触,Effector 自然也没机会做判定。解决办法两个:给角色开 Continuous 碰撞检测,或者把平台厚度加到 0.5 以上。我用前者,代价是性能开销稍高,但角色通常只有一两个,完全能接受。

第二个是下穿之后被"吸"回去。现象是按下键掉下去,掉到一半突然弹回平台上。原因是忽略时长结束时角色恰好还在平台的接触范围内,碰撞一恢复,物理引擎要解决重叠,就把角色往上推。我后来把恢复逻辑改成"先探测脚下是否还有平台碰撞体,有就继续等,最多再等半秒",问题消失。

第三个是斜坡上的单向平台会自行滑动。平台转 20 度做斜坡,角色站上去会慢慢往下滑。这不是 Effector 的锅,是重力分量在斜面上没有足够的静摩擦力抵消。处理办法有两种:给角色的物理材质加上一点点摩擦(但会影响其他场景),或者在斜坡上给角色做"落地吸附",把速度在斜坡方向上钳住。我用的是后者,写了个小脚本在落地且坡度小于阈值时把沿坡向下的速度清零,代价不高,手感也稳。

6. 再往前走一点:多层、瓦片与移动平台

6.1 多层堆叠时的优先级问题

关卡里经常出现两层甚至三层单向平台上下叠放,角色从最下面一层往上跳,穿过第一层、穿过第二层、落到第二层上。这种场景里,Effector 本身没问题,出问题的是你的"地面检测"。

如果地面检测用的是单个射线或者单个 OverlapCircle,角色跳起来穿过第一层的瞬间,检测结果里会出现第一层,此时角色明明在空中,却被判定成落地,于是二段跳被消耗、跳跃被截断。我的做法是:地面检测记录"接触到的所有碰撞体里,位置最低且法线朝上的那个",而不是只看第一个;同时加一个很小的初始向上速度宽容期,起跳后的前 0.05 秒内不接受落地判定。这两条加上,多层跳跃的手感就正常了。

还有一点,Physics2D.queriesStartInColliders这个全局设置会影响射线检测能不能打到"起点所在的那个碰撞体"。角色起跳瞬间如果还嵌在平台碰撞体里,射线可能直接从内部穿过去,检测不到落地。遇到"刚站上去检测不到地面"这种怪现象,先去检查这个设置。

6.2 瓦片地图与 Composite Collider 的配合细节

用瓦片地图做平台,流程固定:Tilemap 上挂 TilemapCollider2D 和 CompositeCollider2D,给 Tilemap 加 Rigidbody2D 设 Static,让 Composite 自动合并。合并之后,Used By Effector 要勾在 CompositeCollider2D 上,Effector 挂在有 Composite 的那个物体上。

这里有两个坑。一是合并后的轮廓会向外扩张,尤其是 Geometry Type 用 Outlines 加偏移的情况下,玩家会觉得"没碰到就被挡住了"。把 Composite 的 Offset Distance 调成很小的值或者 0,再手动修一下边缘顶点。二是瓦片地图里不同瓦片如果有不同朝向(比如斜坡瓦片),合并后轮廓是一个整体,一个 Effector 只能给一个方向,做不了"这块斜坡向上、那块向下"。这种场合必须把斜坡单独拎出来做成独立的平台物体,不要塞进同一个 Tilemap 里。我为了省事塞进去过一次,最后整张地图重做。

6.3 移动平台上的单向通行

移动平台加单向,是我觉得最容易出意外气的组合。平台一动,角色的相对速度就变了,而 Effector 的判定基于接触时的相对运动方向,于是会出现"平台上升时角色被短暂顶起"、"平台下降时角色脚下悬空一帧"的现象。

我的处理有两条。第一条,移动平台的速度别太快,尤其别在下穿忽略时间内移动,否则角色会被平台"追上"或者"落下",恢复碰撞时的重叠更严重。第二条,角色站在移动平台上时,把平台的速度合成到角色的移动计算里,让角色的物理表现保持一致,而不是靠物理引擎的摩擦去带。前者是可预测的,后者是各种玄学顿挫的来源。

顺带说一句,需要做"平台上升顶住角色往天花板挤压"的效果时,单向平台反而不合适,应该改用普通的实体碰撞体加一个触发区域,让玩家自己决定要不要跳过去。单向平台的价值在于"可穿",一旦你开始需要"被顶",说明这个平台的设计目标变了。

6.4 给个可扩展的方向

如果项目里平台类型比较多(单向、实体、可破碎、会消失、只能从某侧穿),我建议不要给每个平台写一个脚本,而是做一个简单的平台类型枚举加一个统一的配置组件,把"是否单向、碰撞层、Effector 开关、破碎后的表现"都收在一个数据结构里,运行时按类型初始化。这样新增一种平台只要加一条配置,不用动代码逻辑。

我在一个项目里就是这么做,前期多花了半天搭结构,后面加了六种平台类型,每种只写十几行配置,省下来的时间远超那半天。反过来如果一开始就各种 If 判断堆在一起,到第五种平台的时候你会想推倒重来。

最后分享一个我自己调参的小习惯:把角色的重力、下落速度上限、平台的忽略时长这三个值写在一张便签上,每次改动只动一个,改完立刻跑五个基础动作。三个一起改是绝对查不出是谁的锅的,这个教训我交了不止一次学费。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/26 13:36:23

ReentrantLock与AQS原理:多线程锁机制深度解析

1. ReentrantLock与AQS的"抢座位"游戏本质 第一次接触ReentrantLock源码时&#xff0c;我盯着那几行lock()和unlock()的调用看了半天——这看似简单的加锁解锁背后&#xff0c;到底藏着怎样的玄机&#xff1f;直到把AQS&#xff08;AbstractQueuedSynchronizer&#…

作者头像 李华
网站建设 2026/10/26 13:36:19

AI工具7天实战:SEO效果提升数据全解析

1. 项目概述 这个标题直指一个当下最热门的话题&#xff1a;AI工具能否在短时间内显著提升网站SEO效果。作为一名经历过无数次SEO战役的老兵&#xff0c;我见过太多"7天速成"的承诺&#xff0c;但这次我们要用实战数据说话。AISEO作为新兴的智能优化工具&#xff0c;…

作者头像 李华
网站建设 2026/10/26 13:35:35

镜像视界技术:多模态感知与智能决策的工程实践

1. 项目概述&#xff1a;镜像视界的技术本质与应用边界 "镜像视界多维感知与空间智能管控"这个看似抽象的概念&#xff0c;实际上正在重塑我们与物理世界交互的方式。简单来说&#xff0c;它就像给真实世界装上了一套高精度的数字神经系统——通过多模态传感器阵列实…

作者头像 李华
网站建设 2026/10/26 13:32:16

双出口PPPoE拨号实战:策略路由、负载均衡与故障切换

两条宽带同时入户这件事&#xff0c;放在几年前还算个折腾活儿&#xff0c;现在装维师傅上门&#xff0c;光猫后面挂个多网口设备就能开搞。但“能拨上去”和“拨得稳、跑得快、掉线不慌”完全是两码事。双出口PPPoE拨号说白了就是让一台路由设备同时用两个账号&#xff08;或两…

作者头像 李华
网站建设 2026/10/26 13:31:31

大模型为何分不清左右?从奇偶轴校验到缪刺算法的空间推理纠偏

你有没有遇到过这种事——让大模型帮你确认“你左手边的杯子是哪一只”&#xff0c;它大概率会给你一个看起来有理有据、但方向完全反了的答案。换到图像生成场景更明显&#xff1a;让模型画一个“左手比耶”的人物&#xff0c;十有八九出来的是右手&#xff0c;或者一只手指数…

作者头像 李华
网站建设 2026/10/26 13:31:13

嵌入式转端侧AI:从CNN部署到MCU落地全攻略

在嵌入式这行干了五年之后&#xff0c;我终于对自己承认了一件事&#xff1a;接下来三年再不碰AI&#xff0c;可能就要被行业落下了。车载、安防、工业控制、可穿戴设备&#xff0c;客户的需求从"能跑就行"变成了"要带端侧智能"&#xff0c;而这个转变最直…

作者头像 李华