You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity零重力场景下实现玩家吸附小行星碰撞体并沿表面行走

零重力小行星表面吸附优化方案

问题根源

原代码依赖单射线检测地面,检测范围过窄,玩家在尖锐边缘或高速移动时极易漏检,导致吸附中断被弹开;且仅靠持续施加固定力吸附,状态切换逻辑生硬,无法稳定贴合曲面。

优化方案(保留所有理想行为)


1. 替换检测方式:用球形覆盖检测替代单射线

扩大接地检测范围,覆盖玩家脚部周围区域,确保边缘、高速移动场景下仍能稳定检测到地面。

2. 吸附逻辑升级:位置修正+动态力结合

不仅施加吸附力,还通过平滑位置修正让玩家快速贴合表面,避免悬空;根据玩家与地面的距离动态调整吸附力大小,离得越远力越强,贴合后保持稳定拉力。

3. 严格主动脱离判定

只有玩家主动触发跳跃输入时,才完全解除吸附;其他场景(包括快速移动)均保持吸附,直到跳跃动作完成。


修改后的完整代码

[Header("吸附参数")]
public Transform feetPosition;
public float feetCheckRadius = 0.2f; // 球形检测半径,根据玩家尺寸调整
public LayerMask groundLayer;
public float surfaceTension = 5f;
public float positionCorrectionSpeed = 10f; // 位置修正速度

[Header("跳跃参数")]
public float jumpForce = 7f;
public float jumpCooldown = 0.2f;

private Rigidbody2D rb;
private Vector2 surfaceNormal;
private bool isGrounded;
private float jumpTimer;

private void Awake()
{
    rb = GetComponent<Rigidbody2D>();
}

private void Update()
{
    jumpTimer -= Time.deltaTime;
    
    // 跳跃逻辑:仅主动按下跳跃键且接地时,解除吸附并跳跃
    if (Input.GetButtonDown("Jump") && isGrounded && jumpTimer <= 0)
    {
        Jump();
    }
}

private void FixedUpdate()
{
    CheckGrounded();
    
    // 非跳跃状态下保持吸附
    if (isGrounded && jumpTimer <= 0)
    {
        ApplySurfaceAttachment();
    }
}

private void CheckGrounded()
{
    // 球形检测:覆盖脚部周围区域,检测地面
    Collider2D hit = Physics2D.OverlapCircle(feetPosition.position, feetCheckRadius, groundLayer);
    
    if (hit != null)
    {
        // 获取地面法线,平滑对齐玩家旋转
        surfaceNormal = hit.bounds.ClosestPoint(feetPosition.position) - (Vector2)feetPosition.position;
        surfaceNormal.Normalize();
        
        float angle = Mathf.Atan2(surfaceNormal.y, surfaceNormal.x) * Mathf.Rad2Deg - 90f;
        transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(0, 0, angle), 0.1f);
        rb.freezeRotation = true;
        isGrounded = true;
    }
    else
    {
        isGrounded = false;
        rb.freezeRotation = false;
    }
}

private void ApplySurfaceAttachment()
{
    // 1. 位置修正:让玩家快速贴合地面,避免悬空
    RaycastHit2D hit = Physics2D.Raycast(feetPosition.position, -surfaceNormal, feetCheckRadius * 2f, groundLayer);
    if (hit)
    {
        float distance = Vector2.Distance(feetPosition.position, hit.point);
        if (distance > 0.01f) // 微小距离忽略,避免抖动
        {
            Vector2 targetPosition = (Vector2)transform.position + (-surfaceNormal) * (distance * positionCorrectionSpeed * Time.fixedDeltaTime);
            rb.MovePosition(targetPosition);
        }
    }
    
    // 2. 动态吸附力:地面法线方向施加拉力,保持贴合
    Vector2 force = surfaceNormal * -surfaceTension;
    rb.AddForce(force);
}

private void Jump()
{
    jumpTimer = jumpCooldown;
    // 沿地面法线反方向跳跃(垂直于表面)
    rb.AddForce(surfaceNormal * jumpForce, ForceMode2D.Impulse);
}

关键逻辑说明

  • 球形检测:Physics2D.OverlapCircle会检测脚部周围圆形区域内的地面,比单射线覆盖范围大,能有效避免边缘、高速移动时的漏检问题。
  • 位置修正:通过射线检测玩家到地面的实际距离,平滑修正位置,确保玩家不会悬空,解决了仅靠力吸附时的滞后问题。
  • 主动脱离:只有玩家按下跳跃键时才触发Jump()方法,此时会重置jumpTimer,暂时关闭吸附逻辑,跳跃完成后自动恢复吸附。
  • 理想行为保留:
    • 慢走/停下:吸附逻辑会持续让玩家贴合地面,配合移动输入即可实现稳定行走。
    • 垂直跳跃:跳跃力沿地面法线反方向,保证是"垂直于小行星表面"的跳跃。
    • 快速行走跳跃:跳跃时保留玩家原有水平动量,同时施加跳跃力,实现带动量脱离吸附。

内容的提问来源于stack exchange,提问作者Borhink

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 09:25:13