0
\$\begingroup\$

The scenario:

I have an enemy tank (AI) chasing my friendly tank (player). When the enemy gets close enough he tries to shoot the player. Now the enemy prefab has an empty game object attached as a child which is used as the projectile (shell) spawn point. It's tilted 10 degrees up (X axis, the actual value in inspector is 350).

Example:

enter image description here

Now I'm trying to figure out what velocity or force must I apply to the projectile in order to hit the player. The angle is fixed (10 degrees) and is always the same. I have tried using the equation (from wikipedia): enter image description here

Which I solved for v and got:

enter image description here

and translated into code which looks like this:

private float requiredForceToHit(Transform target)
{
    float turretAngle = 360.0f - this.turretTransform.eulerAngles.x; //Turret is 10 deg tilted up (350 in inspector)
    float g = Physics.gravity.magnitude; //G force
    float y = 0.0f; //Height of the target
    float x = Vector3.Distance(target.transform.position, this.turretTransform.position); //distance to hit, slight off because turret is lifted up

    float tanG = Mathf.Tan(turretAngle);
    float upper = Mathf.Sqrt(g) * Mathf.Sqrt(x) * Mathf.Sqrt(tanG * tanG + 1.0f);
    float lower = Mathf.Sqrt(2 * tanG - ((2 * y) / x));

    float velocity = upper / lower;

    return velocity;
}

But the projectile falls short from the target. It does launch farther when farther away but the farther away the target the more distance between the point of shell impact and the actual target. What I'm trying to say is that it is pushing with greater velocity the farther away I am but it falls short.

What is wrong and how do I fix it?

Appendix:

The actual shooting code:

private void fire(float force)
{
    Rigidbody shellInstance = Instantiate(this.shell, this.turretTransform.position, this.turretTransform.rotation) as Rigidbody;
    shellInstance.velocity = this.turretTransform.forward * force;
}
\$\endgroup\$
  • \$\begingroup\$ turretAngle is in degrees, so you need to convert it to radians before passing it to Mathf.Tan. Rather than doing the math that way, and having to "just know" that 360 - this.turretTransform.eulerAngles.x is the angle, you could use the components of this.turretTransform.forward to calculate tanG directly. \$\endgroup\$ – Victor T. Apr 1 '17 at 21:01
  • \$\begingroup\$ Victory! Now it's working as it should. Can you please post this as an answer so I can accept it? :) \$\endgroup\$ – Majster Apr 1 '17 at 21:17
2
\$\begingroup\$

[Reposted as an answer, at the asker's request]

turretAngle is in degrees, so you need to convert it to radians before passing it to Mathf.Tan.

Rather than doing the math that way, and having to "just know" that 360 - this.turretTransform.eulerAngles.x is the angle, you could use the components of this.turretTransform.forward to calculate tanG directly. That would be

Vector3 forward = this.turretTransform.forward;
float tanG = forward.y / Mathf.Sqrt(forward.x * forward.x + forward.z * forward.z);
\$\endgroup\$
  • \$\begingroup\$ Thanks again. If it's not too much of a hassle would you mind also explaining why can you calculate the tanG directly like that? I know it's probably basic linear algebra but I can't seem to wrap my head around it. \$\endgroup\$ – Majster Apr 2 '17 at 7:09
  • \$\begingroup\$ Ok I figured it out. For anyone else interested: It's the basic tan(∂) = opposite_side / adjacent_side. And in this case the opposite side is the height forward.y and the adjacent side is calculated by using the pythagorean theorem. \$\endgroup\$ – Majster Apr 2 '17 at 9:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.