- Home /
Projectile launch insufficient velocity
I am making a canon in which the maximum range is set in the inspector and a target within that range is fired upon during the game. The canon must rotate to the right angle to account for gravity. How it is suposed to work: at start assume 45deg angle and find speed needed to shoot the set maximum range. Now if a target is within that range we will be guaranteed enough power to hit it with barrel angle.
Its not finding enough power to hit maximum range and therefore anything in between.
I used this for the math and I'm pretty sure I scripted it right http://en.wikipedia.org/wiki/Trajectory_of_a_projectile
See for youself, setup is simple:
Make a cube with this script on it.
Make another cube as a child. (no collider)
Set the child as the "barrel" var.
Set the maxRange variable to desired maximum range.
Set any object (at about the same height) as a target
Set a rigidbody as "projectile
The code may appear a bit long at a 1second glance but it isnt really and I've commented it.
The speed and dist(how far target is) are just temporary as the script adjusts them. Wanted to watch most variables so I didnt make them private.
var speed:float=10; //speed of projectile
var g = 9.81; //gravity
var dist:float = 200; //how far target is
var maxRange:float=200; //set your maximum range
var degrees:float; //launch angle in degrees
var rads:float; // radians
var currot:float=1; //how far we are rotated now
var rotspeed:int=1; //how fast we rotate the barrel
var turnspeed:int=10; //how fast base rotates
var target:Transform; //the target
var barrel:Transform; //part that aims vertically and bullets come out
var projectile : Rigidbody;
var reloadTime = 0.5;
var ammoCount = 20;
private var lastShot = -10.0;
function Start(){
//find speed needed to reach set maximum range at 45deg elevation
speed=Mathf.Sqrt(maxRange*g);
}
function Update () {
//aiming the base and range
if(target){
//change to local coordinates
var targetRelative = transform.InverseTransformPoint(target.transform.position);
//distance to target
var range=Vector3.Distance(transform.position,target.position);
//aiming the base and range
if(range<maxRange){
//distance to shoot is equal to how far away target is
dist=range;
if (targetRelative.x > .004)
transform.Rotate(0,turnspeed * Time.deltaTime,0);
if(targetRelative.x < -.004)
transform.Rotate(0,turnspeed * Time.deltaTime*-1,0);
}
}
//math to find angle needed to hit a target within maximum range
rads=.5*(Mathf.Asin((dist*g)/(speed*speed)));
degrees=rads*Mathf.Rad2Deg; //conversion to degrees
//rotate the barrel to the degrees needed
if(currot<degrees-.2){
barrel.transform.Rotate(Vector3.right*Time.deltaTime*rotspeed*-1);
currot=currot+rotspeed*Time.deltaTime;
}
else if(currot>degrees+.2){
barrel.transform.Rotate(Vector3.right*Time.deltaTime*rotspeed);
currot=currot-rotspeed*Time.deltaTime;
}
//fire when barrel is rotated
if(currot>degrees-.5&&currot<degrees+.5)
Fire();
}
//basically the rocket launcher from fps tutorial
function Fire(){
if (Time.time > reloadTime + lastShot && ammoCount > 0) {
// create a new projectile, use the same position and rotation as the Launcher.
var instantiatedProjectile:Rigidbody=Instantiate(projectile,barrel.transform.position,barrel.transform.rotation);
// Give it an initial forward velocity. The direction is along the z-axis of the missile launcher's transform.
instantiatedProjectile.velocity=transform.TransformDirection(Vector3(0,0,speed));
lastShot=Time.time;
ammoCount--;
}
}
Answer by RetepTrun · Nov 02, 2011 at 01:54 AM
Aha found it. ty anyway, sounds like good advise.
i tried some more extreme ranges and noticed eventually that even though the projuctile was rotated the right way that it wasnt actually ever traveling up at all, just faster forwards. I figured out it had been given the actual launch direction of the launcher base but not the barrel, which fooled me for awhile because the left-right direction would still be correct and the projectile still got some distance.
Now the thing is DEADLY, the only way to escape is to keep moving, get under the barrel, or run out of its range.
in the fire() function this is the correct code
instantiatedProjectile.velocity=barrel.transform.TransformDirection(Vector3(0,0,speed));
ah, I missed that in skim$$anonymous$$g the code before, was focused on your math. Good to know the integrator - which from what I've gathered since my answer is basically verlet - is not deviating so wildly after all.
Glad you fixed your problem, however you did it!
Answer by WillTAtl · Nov 01, 2011 at 09:56 PM
I'm not seeing an error in your math, so I'm forced to guess that any discrepancy is the result of integration errors. Not sure what integration method unity uses for it's physics calculations, but it will be based on updating every physics timestep, while the function you're using is the "perfect" prediction.
First, make sure you've got drag set to 0 in the projectile prefab's rigidbody settings; it's 0 by default, so the rest of this post assumes it was already off and you're still off the expected mark.
If that wasn't the problem, two possible ways to deal with this come to mind: first, and easiest, you could shorten the physics timestep; the smaller the steps, the more closely the resulting trajectory will correspond to the "perfect" mathematical trajectory. This will come with a performance hit, how much of one depending on how much is going on in the scene, but if the scenes are relatively simple, physics-wise, it might not be a problem.
Alternately, you could NOT use the physics system at all. Instead, write an update function for your projectile that solves the trajectory function for the current absolute time T every frame. This will be more expensive for the projectiles themselves, but won't have the same increased cost for all rigid bodies in the scene like shortening the timestep might. For how to write the update function, see this article which works through the math for setting up the functions based on initial position, velocity, and angle.
Good luck, hope this helps!