如何修复Raycast使其在玩家下方有Tile时返回true,解决角色吸附Tilemap侧面问题
解决Tilemap侧面吸附与射线检测导致的跳跃问题
问题根源分析
你当前的代码存在几个关键问题:
- 混用3D与2D物理API:使用了
Physics.Raycast(3D射线),但你的游戏是2D平台跳跃,应该用Physics2D.Raycast。 - 检测时机错误:仅在碰撞开始时触发射线检测,无法实时判断玩家是否接地,导致
isGrounded状态更新不及时。 - 未处理非接地状态:代码仅在射线击中floor时设
isGrounded = true,但未在未击中时重置为false,导致状态异常。 - 射线长度无限制:默认射线长度为无穷大,可能误击中场景深处的物体,干扰接地判断。
修正方案
1. 替换为2D射线检测并实时更新接地状态
删除原OnCollisionEnter2D中的射线逻辑,改用FixedUpdate持续检测:
public float groundCheckDistance = 0.1f; // 可根据玩家高度调整,比如胶囊底部到地面的距离 public Transform groundCheckPoint; // 可选:把射线起点放在玩家脚部,更准确 void FixedUpdate() { // 可选:用脚部的检测点代替transform.position,避免玩家中心离地导致误判 Vector2 rayOrigin = groundCheckPoint ? groundCheckPoint.position : transform.position; RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.down, groundCheckDistance); // 不仅判断是否击中floor,还要检测碰撞法线是否接近向上(避免侧面碰撞误判为接地) isGrounded = hit.collider != null && hit.collider.gameObject == floor && Vector2.Angle(hit.normal, Vector2.up) < 30f; }
2. 移除Tilemap侧面吸附效果
侧面吸附通常是因为碰撞时的摩擦力导致,可通过以下两种方式解决:
- 方法一:动态调整摩擦力
在碰撞持续时判断是否为侧面碰撞,临时移除摩擦力:
void OnCollisionStay2D(Collision2D col) { if (col.gameObject != floor) return; foreach (ContactPoint2D contact in col.contacts) { // 法线与向上方向夹角大于60度,判定为侧面碰撞 if (Vector2.Angle(contact.normal, Vector2.up) > 60f) { col.rigidbody.friction = 0; // 可选:给玩家一个轻微的横向推力,避免卡墙 transform.Translate(Vector2.right * Time.deltaTime * 0.1f); } else { // 地面碰撞时恢复摩擦力(如果需要) col.rigidbody.friction = 0.5f; // 设为你需要的地面摩擦力值 } } }
- 方法二:调整Tilemap碰撞体
打开Tilemap的碰撞体设置,将碰撞类型改为“Sprite”而非“Grid”,确保侧面没有多余的碰撞区域;或者使用Composite Collider 2D,优化碰撞形状。
3. 修复跳跃与动画逻辑
确保跳跃逻辑只在isGrounded为true时触发,下落动画在isGrounded为false且rigidbody.velocity.y < 0时播放(避免跳跃上升阶段播放下落动画)。
内容的提问来源于stack exchange,提问作者sleepstorm
相关产品推荐
相关产品推荐

