Auto target for FPS?

This is my implementation of auto targeting for FPS:

    for (float k = -0.1f; k < 0.2f; k += 0.1f)
    for (float j = -0.1f; j < 0.2f; j += 0.1f){
    new Quaternion().fromAngleAxis(j, Vector3f.UNIT_Y).fromAngleAxis(k, Vector3f.UNIT_X).mult(cam.getDirection(),rayDir);
    CollisionResults results = new CollisionResults();
    Ray ray = new Ray(cam.getLocation(), rayDir);
    shootables.collideWith(ray, results);
     //...
   }

So I basically cast 9 rays for simulating an “aiming frustum”, then I check collisions. It works, but I wonder if there is a better approach…

If you’re not dealing with too many targets at once, it could be an idea to compare angles between the direction of the player’s shot and the angle between a checked target and the player.

Rundown: The player shoots the gun, it doesn’t hit any target. Next we cycle through the possible targets (with some type of smart geometric indexing we could filter to only check in plausible areas, not behind the player etc.) Of all the potential targets, we calculate an angle between them and the player. If one or more of the targets are within the given angle of error, we select the closest one (by angle first, then distance second)

Here, I’ve scribbled down my idea onto a 2D overview
Imgur

Note however, this is entirely theoretical, I have not done something like this before.

For auto-targeting you should just get a list of close-by enemies and then do the computation from there. Almost every game should have an easy way of getting all entities within a rectangle / circle / cone which is independent of the scene graph, to be used for purposes such as this. Once you have the list of potential entities you can compare angles and all of that.

As mentioned in the other thread, ray casting is slow because it performs the collision on the triangle level and not entity level. The difference can be in several magnitudes.

2 Likes

Quite an interesting question. So far my targeting systems do random raycasts (or random with some limits like only upper hemisphere) - actually it’s surprisingly enough at least for debug purposes (as real gunners can’t change aim instantly anyway), but It’s always good to know how to potentially optimize in the future.

Find the vector to the target. Find your left vector. Dot them together and depending on the dot product, turn left or right some amount.

…that would simulate aiming.

Ahem… I’ve just reread Math for Dummies (since this would be the obvious reply) but still can’t figure out this.

left Vector = “x” of the Player position, I guess.

dot product:

xPlayer . (xTarget, yTarget, zTarget) returns… what? a Vector scaled by the player’ position? What do I do with that?

:chimpanzee_woot:

A vector is a direction, not a position. The dot product is related to the angle between two directions. So it’s a way to find out which direction to turn to aim.

If that’s a problem, there is a possibility to simply interpolate between current facing quaternion and target one (obtained from, say, LookAt method), I presume. That will automatically include direction information so author will have to calculate just the absolute angle to make it possible at some constant rotation speed.

There is no reason to do any angle calculations… the dot product is already the cosine of the angle…which magically enough is exactly what you need to figure out how fast to turn.

Left vector is the direction vector that faces left.

lefttVector = myRotation.mult(Vector3f.UNIT_X); // assumes z forward.

dirToTarget = targetPosition.subtract(myPosition).normalize();

dot = leftVector.dot(dirToTarget);

…positive values = turn left
…negative values = turn right.

Values are -1 to 1 with 0 being ‘object is directly in front’. -1 = object 90 degrees to right. 1 = object 90 degrees to left.

If you are in true 3D then you can also dot() the up vector also.

dot the forward vector if you want to see if something is behind you or not (negative is behind, positive is in front.)

Really surprise the dot product isn’t covered in the math for dummies tutorial as it’s one of the single most useful tools.

When in doubt, always blame @normen :smile:

That’s probably why my system uses something like this (don’t ask me where I got this from lol) so far:

float angleRAD = 2 * FastMath.acos
  (
        FastMath.abs
        ( ed.getComponent(e.getId(), Pose.class).getFacing().dot(dirQ) )
  );

99 times out of 100, that angleRAD is then fed back into a cos or sin somewhere in which case it was never necessary to have had the angleRAD in the first place.

Well I can show you how do I use it then:

float angleDEG = FastMath.RAD_TO_DEG*angleRAD;
Quaternion result = new Quaternion();
// rate calc
float rotSpeed = ed.getComponent(e.getId(), ShipPropulsion.class).getRotationSpeed();
float timeToComplete = angleDEG / rotSpeed; // secs
float donePart = Math.min(1f, tpf / timeToComplete);

// interpolation
Quaternion current_facing = pose.getFacing();
result.slerp(current_facing, dirQ, donePart);
// setting pose
Vector3f loc = pose.getLocation();
Pose newpos = new Pose(loc, result);
ed.setComponent(e.getId(), newpos);