Basically, anything you would normally have to do for costly queries. Lots of optimizations, staggered updates, asynchronous updates, etc.
For the optimization path, do you do any checks before performing the cone overlap? While overlaps are one of the cheaper physics queries, they still have a decent overhead if overly large. While I’m not privy to the innards of PhysX, it’s fairly clear they already have heavy amounts of spatial optimizations. So you’d have to either whittle down the overhead from your PhysX requests, or reduce the amount of requests performed altogether.
Depending on how you built it, a cone can be a very expensive collision primitive. An actual convex mesh in the shape of a cone will be insanely more expensive to use than a plain sphere. It would likely be faster to overlap a sphere and discard results outside of a certain dot product (the cosine of your cone half-angle).
If you’re tracing the World Dynamic channel and you have lots of actors that shouldn’t be considered for homing, then you’re getting overhead from useless checks. You would likely want to create your own collision channel and only enable it for the actors you do want missiles to home in on.
On the game side of things, it could be worth manually iterating your actors rather than using an overlap. If you have a limited subset of actors to home in on, you could maintain an array as you’ve said and just iterate through it. If you have a limited radius, compare against distance squared first. Then filter out using a cheap dot product check equivalent to your cone (be sure to cache your cosine to avoid recalculating it on each cone check). Then do any extra checks you might have, unless they happen to be cheaper than the dot product.
You could also use a spatial structure, yeah. For a 3D scenario, you’d be looking for an octree, not a quadtree. The engine includes a generic octree you can use, TOctree in the conveniently named GenericOctree.h file. It’s not a simple concept to wrap your head around, but essentially what you would be doing is inserting all your actors in the octree, then insert a node for eahc missile of the size you want to check, and loop through the children of that node. For lots of moving items, you’d have to rearrange the tree regularly, which might or might not turn out to be a gain in the end.
There’s the simple solution of staggering updates. Let’s say you want each missile to update its homing once per second, then you’d set up their tick so that it only occurs that often. In order to avoid sudden spikes from lots of missiles updating in the same frame, you’d need some sort of mechanism to stagger those updates, likely a manager or some wrapped value that is assigned to each missile in turn.
A centralized missile manager would also allow you to time box your updates. Say you want missile update to cost at most 2ms per tick, have your missile manager keep track of when its tick starts, start looping through the missiles, and stop as soon as the alloted budget has elapsed. Since world time is only updated between ticks, you’d have to use platform time:
uint32 CycleEnd = FPlatformTime::Cycles() + uint32((kMaxTimeSliceMS*1.0e-3) / FPlatformTime::GetSecondsPerCycle());
while( FPlatformTime::Cycles() < CycleEnd )
{
UpdateNextMissile();
}
Lastly, there’s async updates so you don’t end up stalling the main thread while these updates occur. This could be tricky, because a lot of functions are not safe to call outside of the game thread. A hardcore approach would involve batching all your missile updates in a separate thread, double buffer this so the game thread can continuously update positions and other relevant information, then lock and flip the buffer whenever you’re done with an update. This is obviously glossing over a lot, but I need to get back to work and I’m thinking it probably won’t come to that.
Also, it’s worth mentioning that PhysX traces all have async equivalents, such as UWorld::AsyncOverlap. I haven’t used those yet but it looks straightforward enough.