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

如何在Unity Job中使用Raycast Commands实现射线检测?(C#)

解决Unity Job System多线程射线检测的问题

错误原因

你遇到的UnityException核心问题是:在Job线程中访问了RaycastHit.collider属性。这个属性属于Unity的Object类型,访问它会触发内部的FindObjectFromInstanceID调用,而该操作只能在主线程执行,因此报错。

修正方案

要在多线程中实现射线检测,需遵循以下规则:

  • 用RaycastCommand批量处理所有射线,避免循环内重复调度Job
  • Job中仅处理值类型数据,绝不直接访问Unity对象(如Collider、GameObject)
  • 所有涉及Unity对象的操作(如Debug.Log、访问对象属性)移至主线程执行

修正后的完整代码

using System.Collections.Generic;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;

public class SimpleRaycast : MonoBehaviour
{
    [SerializeField] private List<Agent> agentList;
    
    public class Agent
    {
        public Vector3 position; // 存储Agent位置,用于发射射线
    }

    void Start()
    {
        agentList = new List<Agent>();
        for (int i = 0; i < 5000; i++)
        {
            var agent = new Agent();
            // 随机生成Agent位置,模拟场景分布
            agent.position = new Vector3(Random.Range(-50f, 50f), 10f, Random.Range(-50f, 50f));
            agentList.Add(agent);
        }
    }

    void Update()
    {
        int agentCount = agentList.Count;

        // 创建对应数量的Native数组,存储射线命令、命中结果和命中状态
        NativeArray<RaycastCommand> raycastCommands = new NativeArray<RaycastCommand>(agentCount, Allocator.TempJob);
        NativeArray<RaycastHit> raycastHits = new NativeArray<RaycastHit>(agentCount, Allocator.TempJob);
        NativeArray<bool> hitFlags = new NativeArray<bool>(agentCount, Allocator.TempJob);

        // 为每个Agent生成射线命令
        for (int i = 0; i < agentCount; i++)
        {
            Vector3 startPos = agentList[i].position;
            // 射线从Agent位置向下发射,长度20
            raycastCommands[i] = new RaycastCommand(startPos, Vector3.down, 20f);
        }

        // 批量调度射线检测Job,64为批处理粒度,可根据性能调整
        JobHandle raycastHandle = RaycastCommand.ScheduleBatch(raycastCommands, raycastHits, 64);

        // 调度结果处理Job,依赖射线检测完成
        ProcessRaycastJob processJob = new ProcessRaycastJob
        {
            RaycastHits = raycastHits,
            HitFlags = hitFlags
        };
        JobHandle processHandle = processJob.Schedule(raycastHandle);

        // 等待所有Job执行完毕
        processHandle.Complete();

        // 主线程处理结果:访问Unity对象、打印日志
        for (int i = 0; i < agentCount; i++)
        {
            if (hitFlags[i])
            {
                Debug.Log($"Agent {i} 命中: {raycastHits[i].collider.name}");
            }
        }

        // 释放Native资源,避免内存泄漏
        raycastCommands.Dispose();
        raycastHits.Dispose();
        hitFlags.Dispose();
    }
}

[BurstCompile]
public struct ProcessRaycastJob : IJobParallelFor
{
    [ReadOnly] public NativeArray<RaycastHit> RaycastHits;
    public NativeArray<bool> HitFlags;

    public void Execute(int index)
    {
        // 仅判断是否命中,不访问Unity对象,完全在Job线程执行
        HitFlags[index] = RaycastHits[index].collider != null;
    }
}

核心注意事项

  • 批量处理射线:RaycastCommand.ScheduleBatch比循环单独调度效率高得多,适合大量射线场景
  • 值类型传递:用NativeArray<bool>存储命中状态,避免Job线程触发Unity对象访问
  • 资源管理:所有NativeArray必须调用Dispose()释放,否则会导致内存泄漏
  • Burst优化:给Job加上[BurstCompile]标签,大幅提升多线程执行速度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 13:01:02