Not all Linq clauses are created equal (for example, a Where() is much faster than an OrderBy). Where things can really get expensive, though, is in method chaining. Each call to a Linq clause puts a copy of the source of that expression on the heap. This is actually necessary because Linq is not destructive, like say myList.RemoveAt(1);
So a simple Linq clause isn’t a huge problem in an Update loop (except for OrderBy, OrderBy should NEVER be called every frame, the garbage collector will bog your game down fast!), but that also depends on how many scripts will be using Linq in the Update loop…
I once foolishly wrote a FindNearestTarget() method for a game… it had three possible results: If a player was in range, it will ALWAYS select the player. If an npc detects a unit from another faction, the nearest of those units is targeted, and if nothing is in range, null…
So I wrote a simple Linq expression for this:
private GameObject FindNearestTarget()
{
return FindObjectsOfType<BaseController>().
Where(o=>o.Team!=Team).
Where(r=>Vector3.Distance(d.transform.position, transform.position)<patrolRange).
OrderBy(t=>t.Team).
ThenBy(d=>Vector3.Distance(d.transform.position, transform.position)).
FirstOrDefault();
}
So in this one method chained Linq statement, I’ve got 5 distinct piles of results put into the heap where they will be disposed of by the GC all at once.
First, we get all the BaseControllers (could be PlayerController or AIController, each has a common BaseController ancestor)
We then ensure that it’s not this unit, and filter out units that are out of patrol range.
Since the player is team 0, The OrderBy(t=>t.Team) ensures that all Players are the first things in the list. This ensures that the Player will ALWAYS be selected if he is in patrol range, even if an enemy NPC is closer.
Then the sorted list is subjected to a ThenBy sort… the ThenBy preserves the order of the Faction, but where there are multiple factions, it sorts based on the new field, in this case the distance from the enemy to the player.
Finally, we return either the first element in that list or null.
So silly me, I’m testing this with four enemies, with 2 in each enemy faction and one player (who doesn’t call this method at all)… The game is performing brilliantly, lag free, Then I got past the prototyping phase and I was dealng with 100 enemies in a randomly generated gaming envionment. Things started out great until you actually started playing, and the frame rate dropped from 200+_ to about 6… well… more like the high teens except when the Garbage Collector did it’s thing.
Point being, be careful. Profile, even if it is a Debug/timestamp type of debug (Log with current time on the logged script in the Debug).