- Home /
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.
maybe there's something you can use from this : http://answers.unity3d.com/questions/235519/projectile-boomerang.html
Answer by aldonaletto · Apr 07, 2012 at 01:52 AM
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.
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. $$anonymous$$eh.
Here's the script of my canon (corrected):
using UnityEngine; using System.Collections;
public class $$anonymous$$ortarGun : $$anonymous$$onoBehaviour { 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 * $$anonymous$$athf.Deg2Rad; // Convert angle to radians
dir.y = dist * $$anonymous$$athf.Tan(a); // set dir to the elevation angle.
dist += height / $$anonymous$$athf.Tan(a); // Correction for small height differences
// Calculate the velocity magnitude
float velocity = $$anonymous$$athf.Sqrt(dist * Physics.gravity.magnitude / $$anonymous$$athf.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, Force$$anonymous$$ode.Impulse); rigidbody.AddForce(transform.up * force, Force$$anonymous$$ode.Impulse); rigidbody.AddTorque(torque, Force$$anonymous$$ode.Force); }
If I remove them, the cannonBall no longer move with velocity, just falls softly in front of the cannon...
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 $$anonymous$$ortarGun : $$anonymous$$onoBehaviour { 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 * $$anonymous$$athf.Deg2Rad; // Convert angle to radians
dir.y = dist * $$anonymous$$athf.Tan(a); // set dir to the elevation angle.
dist += height / $$anonymous$$athf.Tan(a); // Correction for small height differences
// Calculate the velocity magnitude
float velocity = $$anonymous$$athf.Sqrt(dist * Physics.gravity.magnitude / $$anonymous$$athf.Sin(2 * a));
return velocity * dir.normalized; // Return the velocity vector.
}
}
Hi! Would you $$anonymous$$d explaining how you achieved your solution?
I am new to the coding world, so I am struggling to understand some variables, such as 'GameObject name' and expressions as used in "if(!(name.GetComponent("Tower") as Tower).canAim)"
Thanks!
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!
Answer by kolban · Apr 05, 2012 at 03:47 PM
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:
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 $$anonymous$$ortar : $$anonymous$$onoBehaviour { 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, Force$$anonymous$$ode.Impulse);
rigidbody.AddForce(transform.up * force, Force$$anonymous$$ode.Impulse);
rigidbody.AddTorque(torque, Force$$anonymous$$ode.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. $$anonymous$$y mortar appears BEHIND the canon and does not move...
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
How can I add force in the opposite direction of the mouse? C# 0 Answers
How to add a delay to a bomb explostion 1 Answer
How to create a variable jump height 2 Answers