Need help with interception of accelerated target

Started by
16 comments, last by Max Power 7 years, 4 months ago

Actually, an initial distance should be very easy to include by adding "p" to the equotion

| (P + V*t + A/2 * t^2) | - (v*t + 1/2 * a * t^2) = 0

making it

| (P + V*t + A/2 * t^2) | - (p + v*t + 1/2 * a * t^2) = 0

I have a feeling that a vectorial offset from the rotation-center will be harder to achieve. But its effect on "t" doesn't necessarily depend on the direction after all, if I can somehow find a "scalar expression" for it...

Advertisement
I just don't understand what your situation is. It would be good if you could make a diagram.

First of all: yay, you are still around :D

Sure, I could make a diagram, but I want to try to better explain the situation first.

I am using the "intercept"-algorithm (3D space, my 2D trip was a short one...) mostly for humanoid characters holding guns in their hands now, so they can predict target and projectile movement and fire in the right direction.

As the origin (the position that the target position is relative to and the point around which the character can rotate when trying to aim) I use a point on the character's up-axis, because it doesn't change when he turns left/right or looks up/down.

My first problem was that it makes little sense and looks terrible when projectiles spawn at this point (inside the character) without an initial distance that matches the distance from origin to muzzle more or less precisely. But as I noticed myself (see previous post), this problem was rather trivial.

The next problem is that a gun's muzzle isn't always located on a line between origin and target. It can be held at hips' height, for example, and the muzzle can be shifted to the right. This is the "vectorial offset" I was talking about. If I neglect this and fire projectiles from origin + initial distance, it still looks terrible, like the character is shooting out of his stomach or something...

If I could, I would spawn every projectile directly from the muzzle, but I need a solution that works with my interception-function, so I think the best I can do is to get this "offset to the side" into it somehow. I mean, if I procedurally tweak my animations a little, especially the blend/aim-spaces that are used for looking up and down, I may even be able to force the offset onto them, so it always looks exactly right. But even without that it should look good enough most of the time.

And, by the way, I intend to make projectiles always fly in the direction of the target-location, even if that means their velocity doesn't match the barrel-orientation 100%, because that's the best I could come up with. This would probably all be much cleaner, if I could use the gun's muzzle as origin. But what good is a computed aim-rotation for a gun that can't rotate freely by itself?...

So, the way I see it, this offset is completely independent of the final computed aim-direction (it's always the same...), but its impact on the computed time of interception varies with distance. And that's pretty much all I've got so far :/

This situation is kind of tricky. Besides the offset, you have the problem that turning is not instantaneous. Ideally you would be able to query the animation system to determine how long it would take to shoot the gun towards a particular location. If you get that, you can use it to solve the equation

time_to_shoot_in_the_direction_of(current_target_position + t * target_velocity) + time_for_bullet_to_reach(current_target_position + t * target_velocity) = t

[EDIT: I modified the equation because it wasn't quite right.]

You can solve for t numerically, either using bisection or using some faster method, like Newton-Raphson. Once you have your t, you know where to aim.

Is this workable in your case?

Actually, I'm not (currently...) worried so much about turning, because I simply update the aim-direction every few frames and have the character turn towards it until they match before letting him shoot. I know it's not perfect, but so far it has been good enough. I'm more concerned about this offset...

Just so I know what approximations might be acceptable, can you give me an idea of the scale here? Like how far is your target typically, how big is this offset and how fast do the target and the bullet move?

Well, it's a top-down kind of game where you control your units like in an RTS. Environments are procedurally generated and stretch over multiple stories. There will be narrow indoor and expansive outdoor areas. So I can't really say there's going to be a typical scale. Combat can take place at close or long range. Weapons should feature as much variety as possible, so there will be relatively slow grenade-like projectiles and very fast beam-like projectiles with anything in between. Some are affected by gravity, others aren't, and some will probably accelerate or decelerate in target/forward-direction. My characters/units are mostly average humanoids with varying size and speed. I made a pretty powerful morphing system with instanced skeletal meshes and I plan on getting the most out of it :p . So, mutants that engage you in melee and run very fast are going to be a thing, as well as slow and big androids.

So, the more accurate, the better, I guess.

By the way, I think I'm having some trouble with the polynomial-root-finder algorithm that you posted a long time ago. I never really noticed before, but right now I am very focused on aiming, shooting, obstacle-checks and things like that, and so I am having a closer look at it. It works very reliable at medium or short distance. But when a character is close to the maximum distance that he can hit a target at (due to gravitation), the root-finder goes crazy and produces very incosistent results.

This is the code:


class Polynomial {
	TArray<float> *coef;

public:
	Polynomial(TArray<float> *C)
	{
		coef = C;
	}

	int degree() const {
		return int(coef->Num()) - 1;
	}

	double value(double x) const {
		double result = 0.0;
		for (uint8 i = 0; i != coef->Num(); ++i)
			result = result * x + (*coef)[i];
		return result;
	}

	double derivative(double x) const {
		double result = 0.0;
		for (uint8 i = 0; i < (coef->Num() - 1); ++i)
			result = result * x + (*coef)[i] * (degree() - i);
		return result;
	}

	bool find_a_root(double *output_root) const {
		double root = 100.0*(-.5 + double(rand()) / RAND_MAX);
		double old_value = 0.f;
		for (int i = 0; i<1000; ++i) {
			double new_value = value(root);
			if (i>10 && fabs(old_value) <= fabs(new_value))
				break;
			root -= new_value / derivative(root);
			old_value = new_value;
		}
		*output_root = root;
		return value(root) < 1e-5;
	}

	bool find_a_root_with_retries(double *output_root) const {
		for (int i = 0; i<4; ++i) {
			if (find_a_root(output_root))
				return true;
		}
		return false;
	}

	void remove_root(double root) {
		double a = 0.0;
		for (uint8 i = 0; i != coef->Num(); ++i) {
			(*coef)[i] += a;
			a = (*coef)[i] * root;
		}
		coef->RemoveAt(coef->Num() - 1);
	}
};

TArray<float> find_all_real_roots(Polynomial p) {
	TArray<float> result;

	while (p.degree() > 0) {
		double root;
		if (!p.find_a_root_with_retries(&root))
			break;
		result.Add(root);
		p.remove_root(root);
	}
	return result;
}

I think I have made one or two small changes, but nothing that should have any actual effect. I can post a video later. I just need to find some capture software first.

Basically, when characters get in range of the target, they start twitching like mad, changing their aiming-pitch every frame, even though distance and other parameters stay the same (stationary target). So I looked into it and noticed that the algorithm either produces no positive roots at all, 1 or 2 (like I would expect), or even more than 2, which doesn't make any sense at all to me. The larger root is more (but not completely) consistent than the smaller. The smaller goes up and down like crazy.

This twitching goes on for some distance towards the target and then stops when close enough. From then on the roots seem to be perfectly consistent. Is this bound to happen? Do I need more retries maybe?

This topic is closed to new replies.

Advertisement