Unity中基于Raycast的避障问题:左右传感器冲突及hit.normals困惑
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:
- Rotation Conflict Resolution:
- We first check if both side sensors are triggered, then handle that edge case before individual sensor hits. Using
else ifensures only one rotation action runs per frame, eliminating the canceling effect.
- We first check if both side sensors are triggered, then handle that edge case before individual sensor hits. Using
- Safe
hit.normalAccess:- Moved the
hit.normalaccess inside thefrontHitblock, where we're guaranteed thehitvariable is valid. Also corrected the property name to Unity's correcthit.normal.
- Moved the
- 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 (sincehit.pointwould be invalid in that scenario).
内容的提问来源于stack exchange,提问作者Ruben

