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

Unity中基于Raycast的避障问题:左右传感器冲突及hit.normals困惑

Obstacle Avoidance Algorithm Fixes for Your Robot

Hey Ruben, let's work through the two issues you're hitting with your obstacle avoidance code one by one:

Issue 1: Rotation cancels when left and right sensors trigger simultaneously

The core problem here is that your current code runs both left and right rotation commands at the exact same time when both side sensors detect obstacles. Rotating -80 and +80 degrees per frame cancels each other out, leaving your robot completely stuck in place.

Fix:

We'll add a priority check for when both sensors trigger first, then handle individual sensor hits with an else if chain. This ensures only one rotation action runs per frame—you can adjust the priority (like preferring left turns over right, or vice versa) based on your robot's needs.

Issue 2: Trouble accessing hit.normal from the front sensor

Looking at your code, the front sensor's hit variable is only valid when the Physics.Raycast call succeeds. You might be trying to access hit.normal (note: it's singular normal, not normals in Unity) outside the successful raycast block, or in a branch where the ray didn't hit anything (like the else path where you move forward).

Fix:

We'll make sure to only access hit.normal inside the block where we confirm the front raycast hit something. I'll show how to integrate this safely into the revised code below.

Revised Code

Ray ray = new Ray(transform.position + Vector3.up, transform.forward);
Vector3 posInicial = transform.position;

// Store raycast results in booleans for cleaner logic
bool frontHit = Physics.Raycast(ray, out RaycastHit hit, 55f);
bool rightSensorHit = Physics.Raycast(posInicial, Quaternion.AngleAxis(45f, transform.up) * transform.forward, out RaycastHit hit2, 20f);
bool leftSensorHit = Physics.Raycast(posInicial, Quaternion.AngleAxis(-45f, transform.up) * transform.forward, out RaycastHit hit3, 20f);

// Front sensor handling
if (frontHit)
{
    Debug.DrawLine(ray.origin, hit.point, hit.collider.CompareTag("Pick Up") ? Color.red : Color.blue);

    if (hit.collider.CompareTag("Pick Up"))
    {
        // Move toward the pick-up target
        transform.position = Vector3.MoveTowards(transform.position, hit.point, Time.deltaTime * speed);
        
        // Safely access hit.normal here—we know frontHit is true
        Debug.Log("Front obstacle normal direction: " + hit.normal);
    }
    else
    {
        // Rotate if front hits a non-pick-up obstacle
        transform.Rotate(0, -80 * Time.deltaTime, 0);
    }
}
else
{
    // Move forward if no front obstacles
    transform.position += transform.forward * speed * Time.deltaTime;
    Debug.DrawLine(ray.origin, ray.GetPoint(55f), Color.white);
}

// Side sensor handling (fixed rotation cancel issue)
if (rightSensorHit && leftSensorHit)
{
    // Both sensors hit: choose a rotation direction (example: prefer left turn)
    transform.Rotate(0, -80 * Time.deltaTime, 0);
    Debug.DrawLine(posInicial, hit2.point, Color.yellow);
    Debug.DrawLine(posInicial, hit3.point, Color.cyan);
}
else if (rightSensorHit)
{
    // Only right sensor hit: rotate left to avoid
    transform.Rotate(0, -80 * Time.deltaTime, 0);
    Debug.DrawLine(posInicial, hit2.point, Color.yellow);
}
else if (leftSensorHit)
{
    // Only left sensor hit: rotate right to avoid
    transform.Rotate(0, 80 * Time.deltaTime, 0);
    Debug.DrawLine(posInicial, hit3.point, Color.cyan);
}

Key Changes Explained:

  1. Rotation Conflict Resolution:
    • We first check if both side sensors are triggered, then handle that edge case before individual sensor hits. Using else if ensures only one rotation action runs per frame, eliminating the canceling effect.
  2. Safe hit.normal Access:
    • Moved the hit.normal access inside the frontHit block, where we're guaranteed the hit variable is valid. Also corrected the property name to Unity's correct hit.normal.
  3. Cleaner, More Robust Logic:
    • Stored raycast results in boolean variables to avoid redundant checks and make the code easier to read.
    • Used CompareTag() instead of == for tag checks (it's more efficient and less error-prone in Unity).
    • Fixed the white debug line to use ray.GetPoint(55f) when there's no front hit (since hit.point would be invalid in that scenario).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:26:39