How to SHOOT an object on a curved path without using Rigidbody
Hey there,
Lets say im launching a cannon ball. It needs to shoot towards players facing point and slowly lose height and hit the ground eventually. Like this:
How do I set up the movement of cannonball object like this? The cannonball WILL NOT HAVE RIGIDBODY property. So I need to set position of cannonball on each Update().
Here is how I shoot cannonball with my standart first person controller:
void Update () {
if (Input.GetButton("Fire1"))
{
GameObject cannonBall= Instantiate(projectile, transform.position, transform.rotation);
}
}
And here is my movement script on cannonball. Currently it goes straight forward without hitting ground.
void Update () {
if (transform.position.y > 0)
{
transform.Translate(Vector3.forward * Time.deltaTime * 10);
}
}
Answer by Scoutas · Jan 09, 2017 at 07:04 PM
I would think that you would need to figure out the formula for the parabola path that you want your cannon ball to take. Then using it, you would increment the x value by some stepSize (e.g. Time.deltaTime) and plug it into the equation to get back the y value. Then put the cannon ball at those coordinates.
This way you would need to figure out a way to know when the cannon hit the ground so the ball would stop when it hits the ground.
You could use the formula that involves the top point of the parabola
y = a(x - x1)^2 + y1
where x1 is the x coordinate of the top point and y1 is the y coordinate of the top point. Or the one with intercepts
y = a(x - x1)(x - x2)
where x1 and x2 are the points at which parabola intecepts the x axis.
You'd need to fiddle around with these things to get things working for you the way you want to.
I think that the intecept form would work best, because you could figure out the intercept point behind your cannon and then just input the next intercept point, to get exactly what you would need. And the a
in that formula would be the tan(angle)
, where the angle is the angle that the cannon is rotated by from the x axis, anticlock-wise. (And because of the way that Unity handles angles, I think instead of tan(x), you would need to use ctg(x), but I'm not entirely sure about this one).
EDIT: @y11t_tr
Okay, so additional information. I tried implementing this in Unity, and it gave me quite a few problems.
First things first - a point directly behind the cannon is not the intercept of the ball movement parabola. That's a wrong assumption. Because of this, the usage of the intercept formula crumbles.
I tried figuring out a way to do it all without it, but just couldn't. Anyway, I decided that I would just find the formula of the parabola itself, but that brought another problem back. I only had two points and I needed three points to make what I had in mind work. So I figured I'd make some sort of a hack.
I have two points in the scene that the ball should go through. First one is the point, from where the cannon fires, the next one is the target point. So, I decided that I would put a third point, an extremely tiny distance away from the one that was in front of the cannon. That fixed the problem and now I had three points with which I could draw a parabola path.
Now, figuring out the parabola itself. I tried my luck at deriving the equations to do so, but to no avail. Anyway, a quick google search gave me some results.
To find the equation of the parabola, using three random points, you need to figure out y = ax^2 + bx + c
what the a, b and c is in this equation. Anyway, I found these equations:
Say we have three points (x1, y1), (x2, y2), (x3, y3).
denominator = (x1 - x2) * (x1 - x3) * (x2 - x3)
a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2))/denominator
b = (x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1) + x1 * x1 * (y2 - y3))/denominator
c = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3)/denominator
And now, all you need to do, is to put everything into code:
float GetDenominator(Vector3 point1, Vector3 point2, Vector3 point3){
return (point1.x - point2.x) * (point1.x - point3.x) * (point2.x - point3.x);
}
float GetA (Vector3 point1, Vector3 point2, Vector3 point3){
return ((point3.x * (point2.y - point1.y)) +
(point2.x * (point1.y - point3.y)) +
(point1.x * (point3.y - point2.y))) / GetDenominator (point1, point2, point3);
}
float GetB (Vector3 point1, Vector3 point2, Vector3 point3){
return ((Mathf.Pow(point3.x, 2) * (point1.y - point2.y)) +
(Mathf.Pow(point2.x, 2) * (point3.y - point1.y)) +
(Mathf.Pow(point1.x, 2) * (point2.y - point3.y))) / GetDenominator (point1, point2, point3);
}
float GetC (Vector3 point1, Vector3 point2, Vector3 point3){
return ((point2.x * point3.x * (point2.x - point3.x) * point1.y) +
(point1.x * point3.x * (point3.x - point1.x) * point2.y) +
(point2.x * point1.x * (point1.x - point2.x) * point3.y)) / GetDenominator (point1, point2, point3);
}
And the only thing left to do, is to write the movement script for the cannon ball. Good thing is, that using it this way, the target and the cannon can be anywhere on the same 2D plane and it would work. Anyways, cheers!
I really appreciate your effort. can you please explain how the movement script will work with your code?
Answer by y11t_tr · Jan 13, 2017 at 09:06 AM
Wow, thanks for the detailed answer. Just noticed someone actually replied! I will check this out tell you if it worked for me. Thanks!