x


Use a vector3 position to calculate where a bomb falls

Hi everyone,

I've been working on a difficult problem since a few days and I'm bugged.

I'm trying to get a Vector3 position that will serve as a target. I'm trying to make something like a cannon fire at that precise position.

Here's my code right now:

using UnityEngine;
using System.Collections;

public class Mortar : MonoBehaviour 
{
	public float force;
	public Vector3 torque;
	public GameObject explosion;
	
	private Transform target;
	private Vector3 targetPos;
	
	void Start () 
	{
		Destroy(gameObject, 5.0f);
		
		rigidbody.AddForce(transform.forward * force, ForceMode.Impulse);
		
		rigidbody.AddForce(transform.up * force, ForceMode.Impulse);
		
		rigidbody.AddTorque(torque, ForceMode.Force);
	}
	
	void OnCollisionEnter(Collision collision)
	{	
		foreach(ContactPoint cp in collision.contacts)
		{
			if(cp.otherCollider.gameObject.tag == "Floor")
			{
				Instantiate(explosion, collision.contacts[0].point, Quaternion.identity);
				Destroy(gameObject);
			}
		}		
	}
	
	void ReceiveTarget(Vector3 targetReceived)
	{
		targetPos = targetReceived;
		Debug.Log("targetPos = " + targetPos);
	}
	
	void ApplyDamage()
	{
		
	}
}

Obviously, I'm still not done with getting my Vector3 from another script, but I'm working on that. The main problem is: when I get that info, how will I use it? I want my bomb, once fired, to do an arc from the canon tip to the target. I'm trying hard to figure how I can do this with the AddForce...

Anybody can help? Thank you.

more ▼

asked Apr 05, 2012 at 03:38 PM

Herve_Simard gravatar image

Herve_Simard
46 30 28 29

maybe there's something you can use from this : http://answers.unity3d.com/questions/235519/projectile-boomerang.html

Apr 07, 2012 at 02:16 PM alucardj
(comments are locked)
10|3000 characters needed characters left

2 answers: sort voted first

So if I understand you, you have two points ... the source and the target and you want to move an object from the source to the target in a "ballistic" fashion following a trajectory?

I think the answer to your question will presumably involve physics and math. You will want to calculate the vector of initial launch of the projectile and the force to be applied to it. The calculation of these factors will be based on the mathematics of Trajectory.

See:

http://en.wikipedia.org/wiki/Trajectories

more ▼

answered Apr 05, 2012 at 03:47 PM

kolban gravatar image

kolban
1.9k 2 11

That's a nice idea you got there.

I've done something similar based on a class project we made a few weeks ago, using what you just suggested:

using UnityEngine; using System.Collections;

public class Mortar : MonoBehaviour { public float force; public Vector3 torque; public GameObject explosion; public Transform target; public float speed; public Transform guntip; public AnimationCurve curve;

private Vector3 departPos;
private Vector3 destination;
private float currentTime = 0.0f;

void Start () 
{
    //Destroy(gameObject, 5.0f);

    rigidbody.AddForce(transform.forward * force, ForceMode.Impulse);
    rigidbody.AddForce(transform.up * force, ForceMode.Impulse);
    rigidbody.AddTorque(torque, ForceMode.Force);

    departPos = guntip.position;
}

void OnCollisionEnter(Collision collision)
{   
    foreach(ContactPoint cp in collision.contacts)
    {
        if(cp.otherCollider.gameObject.tag == "Floor")
        {
            Instantiate(explosion, collision.contacts[0].point, Quaternion.identity);
            Destroy(gameObject);
        }
    }       
}

void ApplyDamage()
{

}

void Update()
{
    currentTime += speed * Time.deltaTime;

    destination = target.position;

    transform.position = Vector3.Lerp(departPos, destination, curve.Evaluate(currentTime));
}

}

But it does not work. My mortar appears BEHIND the canon and does not move...

Apr 07, 2012 at 12:48 AM Herve_Simard
(comments are locked)
10|3000 characters needed characters left

I answered a similar question some time ago: http://answers.unity3d.com/questions/148399/shooting-a-cannonball.html
The code in that answer is in JS, thus I posted here a C# version.
In a brief, you should calculate the velocity necessary to reach the target, instantiate the projectile and set its rigidbody.velocity to the value calculated. If the target and the cannon are at the same height, the velocity magnitude can be calculated by sqrt(distance * g * sin(2 * elevation angle)). If there exists a small height difference between the cannon and the target, this can be compensated to some extent by a smart change in the distance value.
The function BallisticVel below receives the target transform and the elevation angle, and calculates the complete velocity vector (a vector with suitable direction and magnitude), including a linear compensation for small height differences (up to about 10% of the distance):

Vector3 BallisticVel(Transform target, float angle){
    Vector3 dir = target.position - transform.position;  // get target direction
    float h = dir.y;  // get height difference
    dir.y = 0;  // retain only the horizontal direction
    float dist = dir.magnitude ;  // get horizontal distance
    float a = angle * Mathf.Deg2Rad;  // convert angle to radians
    dir.y = dist * Mathf.Tan(a);  // set dir to the elevation angle
    dist += h / Mathf.Tan(a);  // correct for small height differences
    // calculate the velocity magnitude
    float vel = Mathf.Sqrt(dist * Physics.gravity.magnitude / Mathf.Sin(2 * a));
    return vel * dir.normalized;
}

// This is a test code: drag the target and projectile prefab to the appropriate
// fields in the Inspector, then press B to shoot. You can change the shootAngle,
// initially set to 30 degrees - the projectile slows down for higher angles, 
// and get faster for lower angles:

public Transform myTarget;  // drag the target here
public GameObject cannonball;  // drag the cannonball prefab here
public float shootAngle = 30;  // elevation angle

void Update(){
    if (Input.GetKeyDown("b")){  // press b to shoot
        GameObject ball = Instantiate(cannonball, transform.position, Quaternion.identity) as GameObject;
        ball.rigidbody.velocity = BallisticVel(myTarget, shootAngle);
        Destroy(ball, 10);
    }
}

This C# version was not tested, thus let me know if it has any errors.
NOTE: The projectile must not collide with the cannon, or it will never reach the target. You can have a cannon without collider, or with isTrigger=true, or attach this script to an empty object that will be the spawn point.

more ▼

answered Apr 07, 2012 at 01:52 AM

aldonaletto gravatar image

aldonaletto
56.8k 30 76 291

Seems like I'm getting somewhere!

Thanks to your effort, I've understood my mistake. First:

  • I've been trying to modify the direction of my mortar dynamically, meaning that I was trying in my script up above to change the direction in mid-air; this was NOT intended and assuredly not in my concept.
  • Reading both of your comments allowed me to understand that it was not my cannonball which I needed to modify, but the cannon which instantiate the ball.

So I've applied your script to my cannon. Although things seem to improve, it doesn't quite work well. Before, the bomb would spawn behind my cannons and would not move; now they spawn at the right place, but with no velocity whatsoever. Meh.

Here's the script of my canon (corrected):

using UnityEngine;
using System.Collections;

public class MortarGun : MonoBehaviour 
{
	public Transform gunTip;
	public Transform target;
	public GameObject mortar;
	public GameObject name;
	public float fireRate;
	private float shotTime = 0.0f;
	public float shootAngle;
	
	void Update () 
	{
		shotTime += Time.deltaTime;
		
		if(shotTime >= fireRate)
		{
			if(!(name.GetComponent("Tower") as Tower).canAim)
			{
				GameObject cannonBall = Instantiate(mortar, gunTip.position, Quaternion.identity) as GameObject;
				cannonBall.rigidbody.velocity = BallisticVelocity(target, shootAngle);
				shotTime = 0.0f;
			}
		}
	}
	
	Vector3 BallisticVelocity(Transform target, float angle)
	{
		Vector3 dir = target.position = transform.position; // get Target Direction
		float height = dir.y; // get height difference
		dir.y = 0; // retain only the horizontal difference
		float dist = dir.magnitude; // get horizontal direction
		float a = angle * Mathf.Deg2Rad; // Convert angle to radians
		dir.y = dist * Mathf.Tan(a); // set dir to the elevation angle.
		dist += height / Mathf.Tan(a); // Correction for small height differences
		
		// Calculate the velocity magnitude
		float velocity = Mathf.Sqrt(dist * Physics.gravity.magnitude / Mathf.Sin(2 * a));
		return velocity * dir.normalized; // Return a normalized vector.
	}
}

As you can see, the canon does the job of instantiating the cannonBall. But there's a twist: I used to add some properties to my mortar with which I played. Those were :

void Start () 
	{
		rigidbody.AddForce(transform.forward * force, ForceMode.Impulse);
		rigidbody.AddForce(transform.up * force, ForceMode.Impulse);
		rigidbody.AddTorque(torque, ForceMode.Force);
	}

If I remove them, the cannonBall no longer move with velocity, just falls softly in front of the cannon...

Apr 07, 2012 at 01:46 PM Herve_Simard

You must not apply any other force to the cannonball, or it will never reach the target! The cannonball is just a rigidbody driven by initial velocity and gravity - remove that code!
Your script actually doesn't work because you made a typo in the first BallisticVel line (changed a - signal to =). But there's another problems: you're instantiating the cannonball at gunTip, but the calculation is being done based on transform.position - unless the script is attached to gunTip, the result will be wrong.
To avoid this problem, I changed the function to use gunTip.position. I also fixed the typo, and made the cannonball be destroyed after 10 seconds (to avoid a scene crowded with lost cannonballs). That's the result:

using UnityEngine;
using System.Collections;

public class MortarGun : MonoBehaviour 
{
	public Transform gunTip;
	public Transform target;
	public GameObject mortar;
	public GameObject name; // name is a GameObject property - you should rename this variable
	public float fireRate;
	private float shotTime = 0.0f;
	public float shootAngle;
	
	void Update () 
	{
		shotTime += Time.deltaTime;
		
		if(shotTime >= fireRate)
		{
			if(!(name.GetComponent("Tower") as Tower).canAim)
			{
				GameObject cannonBall = Instantiate(mortar, gunTip.position, Quaternion.identity) as GameObject;
				cannonBall.rigidbody.velocity = BallisticVelocity(target, shootAngle);
				Destroy(cannonBall, 10); // cannonball disappears after 10 seconds
				shotTime = 0.0f;
			}
		}
	}
	
	Vector3 BallisticVelocity(Transform target, float angle)
	{
		Vector3 dir = target.position - gunTip.position; // get Target Direction
		float height = dir.y; // get height difference
		dir.y = 0; // retain only the horizontal direction
		float dist = dir.magnitude; // get horizontal distance
		float a = angle * Mathf.Deg2Rad; // Convert angle to radians
		dir.y = dist * Mathf.Tan(a); // set dir to the elevation angle.
		dist += height / Mathf.Tan(a); // Correction for small height differences
		
		// Calculate the velocity magnitude
		float velocity = Mathf.Sqrt(dist * Physics.gravity.magnitude / Mathf.Sin(2 * a));
		return velocity * dir.normalized; // Return the velocity vector.
	}
}
Apr 07, 2012 at 03:21 PM aldonaletto

Wow... it works! Thanks a lot ^^ Now I've got issues with my targetting system, but hey, at least I've got something :) Thanks again!

Apr 08, 2012 at 12:26 AM Herve_Simard
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x8928
x451
x33

asked: Apr 05, 2012 at 03:38 PM

Seen: 2921 times

Last Updated: Apr 08, 2012 at 12:26 AM