Finding the Closest Actor to a Given Vector and/or Rotation

I have the need for a bit of code that will find the closest actor to a given vector or rotation. Basically, I want to be able to look in a direction and the actor closest to that direction is chosen even if the chosen actor is in the opposite direction.

I have a reference to all the actors that are capable of being targeted, I just need a way to pick the one closest to the given vector/rotation.

You can do this a few ways. One of them would to be use a sort of pawn sense. What I would look into would be line traces. You’d basically shoot the trace to each of the actors from the player and get the dot product to see the angle between the player’s forward vector and the direction of the trace and see if it’s some value between 1 and 0. But if it’s 0, that means the lines are perpendicular, so maybe choose a different value like 0.45 as your lower bound of the dot product’s result for a valid “look at”. Let me know if that works or if you need any clarification!

Perhaps one of these, or combination of would do the trick?

Didn’t feel like setting up an actual example, since I believe you have pretty much all you need. You can get a vector location from a references you already have. Let me know if you need more an example and I will put something together. :sloth:

This solution was terrifyingly easy to implement, but how would i go about sorting the values to pick out the one closest to zero without excluding negative numbers using the ABS node, resulting in a target from behind getting chosen when their ABS value is smaller.

If you’re worried about the distance between the player and a valid actor, you can write a function that returns that actor of the shortest distance away. You just loop through those valid actors and check their distances and keep track of the smallest distance and the actor that distance is paired with and then return the actor that’s closest.

I’m not too concerned about the distance between the player and the intended target, but when using ABS to compare the values, I’m running into an issue where I will look just to the side of the intended target and the chosen target ends up being behind me instead.

I think I have an idea of what’s going on but could you show me the code segment where you’re doing your calculations

Sure thing.

Here is the code segment that’s running the math for the line traces:

Here is the code segment that’s running the math for finding the closest to zero:

Ok I see and just for some more clarification, I drew up an example of what we’re looking for. I have the green circle is the player and the direction they are facing. We want the valid candidates to be only what’s in front of the player (in the blue box) and the selected actor to be the closest of those candidates (in the purple box)?

Let me know if that checks out

the valid candidates for selection can be any of the possible targets, whether they are behind the player or to their side, but the target we want is the target closest to their direction. If the player isn’t looking directly at or next to a target, the next valid target is chosen.

You keep saying direction, but then mentioning that the rotation doesnt matter.

Thats because what you acrually want is the location.
You want a look at - to the actor to be chosen.

Alternatively, if you socathoa it, then something like Dot will give you the + and - you need to determine everything. But, you have to base your math on the result of the main actor forward vecor and the other actor Locations (not rotations).

There is technically no need to line trace, or anything, except for math and knowing your trig.
But… you can’t relay on a loop for this to work either since unreal engine and loops dont really jive.

I would suggest this as a pseudocode/setup:

Add a collider to the main acotor (a cylinder) in the size you want to scan objects for.
Add an event to the actor. Get all actors (of class) within the collision of the cylinder (use sweep).

Check how many actors there are - if more than 10, you have to make something that is async or not on the game thread or the loop will probably fail.

If less than, you do the maths and store the result to a soft variable of type actor (so you store a ref to the closest actor).

As the loop progresses, only the closest actor is stored up for you - and you can further code up ways to manipulate “who” is closest, or if they are facing behind or in front of the actor’s location, etc.

The limitations to this are the number of actors involved.

But you can also restrict that by making your collider a different shape or size, or chaning the collision channels for the actors so as to only have some respond.

You can’t have the loop do crazy maths though - like look at is altready expensive as it is, so go with the sinpler things whenever possible.

The real reason blueprint loops fail is that it’s thread blocking, and therefore a large delay will cause the engine to claim the loop is infinite…

1 Like

While I do know about the collider method, it doesn’t quite work for the scenario I need. What I want is the ball to bounce toward a target you can control without having to look directly at the target 100% of the time.

Yes, you’re right, I should specify that I want the player’s forward vector to control what target you want the ball to go after. Rotation entirely matters here, but the location of the other targets doesn’t. The rotation of the player should control what target is chosen next regardless of the location.

For example, I want to target someone sitting between two other targets, I just need to look directly at them and it will function.

The current iteration gives these results, with certain scenarios resulting in targets being chosen that aren’t even on the screen simply because the ABS of the DOT product ended up being smaller than the ABS Dot product of the target I was looking at.

I apologize for confusion that was caused.

As for the amount of targets, there will only ever be 10 at any given time with the amount being reduced as the game progresses, however, they can be anywhere in the map.

The ball starts in the center, picks its first target, and uses the Floating Pawn Movement component to add an input to the current forward vector while using a RInterp To node to control it’s movement to direction of the target slowly increasing it’s Interp Speed to prevent going in circles when positioned just right.

The player can use their own forward vector to control what target is chosen next by looking in their direction, with the location not mattering, the target of the ball will change to whatever target is closest.

sorry I know it’s a bunch of back and forth. I just want to make sure I’m helping solve the correct problem. Could you do a super simple sketch or a few showing the different scenarios with a brief description just so I can understand what you’re going for just because I think words can only go so far. (we’re gonna get you through this!) :slightly_smiling_face:

Sure thing, sorry for the delay.

In this case, the player want’s to curve the ball towards the intended target by aiming just off to the side of the target. However, there was another target behind them that ended up aligning with their forward vector more closely than that of the intended target. Because of the way that finding the closest value to zero works by comparing them using their absolute values, the target then becomes the target behind the player instead of in front of them. This is not what should happen, and the ball should have gone to the intended target.

In the next instance, the player wants to fire the ball to the intended target behind them, but the absolute value ends up being negative. The ball still goes towards them as there are no other valid targets that line up with the player’s forward vector. This is as intended.

In the third instance, the player is hitting the ball the same way as Instance 2, however a new player is in the way and the ball instead goes to them. This is what should happen as their value was prioritised for being closer to zero, but was a positive value. This is not what currently happens, and the ball will still go to the intended target when it should have gone to the new target.

And just to make it clear and without confusion, it should go without saying that looking directly at the intended target should make the ball go towards them. The problems start showing up when you start trying to interfere with the ball’s trajectory by attempting to curve the ball or fling it behind you.

Ok I think I understand a bit better. So right off the bat, I think the reason that the ball shoots off behind the player sometimes when it shouldn’t (when the forward vector and direction of the trace to the actor behind the player align) is due to you getting the absolute value of the dot product. The sign of the dot product is crucial because it determines the direction of the vector given two points relative to the player’s forward vector (the player’s location and the target actor’s location)

Here’s an image to show how the signs are important.

Notice that the values fluctuate between -1 and 1 where 1 means same direction and -1 means opposite direction. You’re going to see the -1 when the actor is behind the player. So you’ll want the values to be somewhere between 0 and 1 where 0 is 90 degrees in either direction in front of the player and 1 is directly in front of the player. That will at least filter out your possible actors.

Then I’m not sure if you want to get the closest target to the player’s position or the closest target that the player is looking based on rotation. Like a target may be 10 meters away, but has a dot product result of 1 (you are looking directly at the actor) and another actor is in view that is 5 meters away but the dot product gives you something like 0.4 (you are sort of looking at it but it’s a little bit to the left of the screen). So you’ll want to choose your final target based on those criteria.

Let me know if any of that was helpful or if you need to give or need any other clarification! :slightly_smiling_face:

So instead of doing all this complicated math to figure it out, all I really needed was a Greater Equal node coming off the DOT product and comparing it to my current largest value like the attached image?

pretty much! It should be a lot of the same logic with different values. You just iterate (loop) through all of the actors and filter them based off of their criteria. You can do this in one pass.

You loop through the list of actors and if the dot product is greater than 0 (or maybe whatever your fov is), then you can save a reference to that actor in a local variable along with the distance between that actor and the player if you’re measuring a valid target actor in that regard. But if you’re trying to figure out what actor the player is staring at the hardest (if it’s more in the center of the player’s view), then you choose the largest result of the dot product and return that actor that is paired with that result. And if that’s the case, you likely don’t even need to do any line traces which will save you heavy on computational power. But go for functionality first and then worry about optimizing it after!