
複数の敵の全てからレイを飛ばすとき、敵のリストを持つクラスのUpdate()で、1フレームにつき数体ずつ実行してみます。
[SerializeField] int cap = 3; // 一度に処理する敵の数
// ---
void Update()
{
    // 敵がいるとき
    if (agents.Count != 0)
    {
        s += Time.deltaTime;
        text.text = num.ToString();
        int cap2 = cap;
        // 容量より敵が少ないとき
        if (cap > agents.Count)
        {
            cap2 = agents.Count;
        }
        for (int n = 0; n < cap2; n++)
        {
            
            Vector3 pos = agents[index].transform.position;
            Vector3 dir = player.position - pos;
            RaycastHit hit;
            // レイを飛ばす
            if (Physics.Raycast(pos, dir, out hit, Mathf.Infinity))
            {
                Debug.DrawRay(pos, dir*hit.distance, Color.red); // hit.distanceは不要
            }
            // 3秒ごとに敵を削除
            if (s >= 3)
            {
                s = 0f; // 一体ずつ削除する
                Destroy(agents[index].gameObject);
                agents.RemoveAt(index); // リストから削除
            }
            else
            {
                index++;
            }
            // 敵がいなくなったら
            if (agents.Count == 0)
            {
                break;
            }
            // リストの最後の敵のとき
            if (index >= agents.Count)
            {
                index = 0;
                num++;
            }
        }
        /*
        // 時間をリセット
        if (s >= 3)
        {
            s = 0f;
        }*/
    }
}
1フレームで実行したい数だけ繰り返し処理をします。その中で敵を破壊するときはリストからも削除します。
冒頭のGIF画像では、敵の処理が一巡した回数を左下に表示しています。シーン上の敵の数が減ったり一度に処理する敵の数が増えると、この増加の速度が上がります。

レイを飛ばすだけでなく、プレイヤーとの距離を計算するなど、個々の敵の処理を数フレームおきに行って負荷が軽減するのを期待しています。繰り返し処理を一旦ストップして他の処理をさせることもできます。



