The scripting engine of Skyrim (and Fallout 4) has an interesting function called FindClosestActor(x,y,z,radius). If you call it with x,y,z center coordinates and a radius, it returns the closest Actor (entity) in the given radius and if it fails to find any, it returns nothing.
The most common use-case would be for such a well-named function is to find Actors around the Player in a specific radius. Lo and behold, Player is also an Actor therefore you always get Player as the result of the function, making it completely impractical.
There are exactly two functions that can be used for finding an Actor in a given radius. Their (pseudo-)signature is the following:
FindClosestActor(x,y,z,radius) -> Actor | None
FindRandomActor(x,y,z,radius) -> Actor | None
Question: How can I find the closest Actor to the player in a close to optimal (least function calls) way using FindClosestActor
and optionally FindRandomActor
? How can we overcome the defective behavior of FindClosestActor
?
Method I refuse to utilize
It relies on random too much. What if it was badly written internally? I think the only useful property of this algorithm is that if there are more than 1 Actor most of the time, it returns a non-Player Actor with 2 function calls with a 75+% reliability.
closestActor = FindRandomActor(playerX,playerY,playerZ,radius)
for i in 0..iterationLimit
tmp = FindRandomActor(playerX,playerY,playerZ,radius))
if distance(tmp, player) < distance(closestActor, player)
closestActor = tmp
Idea #1:
Legend:
A1, A2: Actors where A2 is closer to the Player than A1
R: position where we find the closest actor
RP: Distance between R and P
P: Player
B: circle around P at distance "base radius"
- Let R be an arbitrary midpoint between P and (circle) B and RP is the distance between R and P.
- We run FindClosestActor(R, RP) and rotate R by some degrees (50° increments seem reasonably round) around P and repeat the process until we arrive to the original R position. During this process, we collect Actors and select the one that is the closest to P (which is A2).
- If we reached the minimum Actor-Player distance limit, we return with the closest Actor we have at the moment.
- Let R be the midpoint between A2 and P and repeat from step 2.
There are two issues with this algorithm.
- The degree increment means I can't perfectly cover the whole circle
- It looks pretty brute force. Even for 2 Actors, you might need 8 calls which is a lot
Idea #2:
Still not convinced that such a nondeterministic algorithm would be reliable but at least this one spends calculation time on really close Actors first.
closestActor = None
for i in MinRadius..MaxRadius
for j in 0..iterationLimit
tmp = FindRandomActor(playerX,playerY,playerZ, i))
if tmp is not player
closestActor = tmp
break "for i..."