- Home /
Firing only a single projectile at a time, then adding a second.
I know there are a lot of projectile scripts and questions out there but I could not find one to answer what I am after.
I have a point in the centre of the screen that projectiles get fired out of. This faces away from the camera.
At the moment, when I click and hold the mouse button, it puts the projectile prefab into the centre point. When I release the mouse button, the projectile fires. When the player presses and holds the mouse button again, the previous projectile is destroyed and a new one is put into the center of the screen. This is partly the functionality I am after as I don't want the player to keep firing as many projectiles as they want. I would like to add the bonus that after x amount of head shots, the player is awarded another projectile to their pool, so they can have a maximum of 2 projectiles in the scene at once. This continues up to a maximum of 5.
Here is where I handle the firing: I was thinking that the projectiles need to get pushed into an array and then it fires only those in the array but could not see how it would know which projectile to destroy or how many are in the scene.
public static int numberOfProjectiles;
public int shootForce = 90;
public Transform target;
public Vector3 firePosition;
public GameObject projectilePrefab;
public GameObject projectile;
public float shootForce;
public static bool canShoot = false;
void Start () {
numberOfProjectiles = 1;
firePosition = target.transform.position;
}
void Update ()
{
if (Input.GetMouseButton(0)) // aim while the mouse button is down
{
Destroy(projectile);
projectile = (GameObject)Instantiate (projectilePrefab, firePosition, firePosition.transform.rotation);
projectile.rigidbody.AddForce(-projectile.transform.forward * shootForce);
}
}
Then, when the projectile hits a collider on an enemy (Separate Script on the enemy):
void Update()
{
if(headShotCount==3) //not sure how to keep a record of how many times this can be incremented
{
ProjectileScript.numberOfProjectiles +=1;
}
}
void OnCollisionEnter(Collisions collision)
{
headShotCount +=1;
}
All help and advice appreciated!
Answer by wibble82 · Feb 11, 2014 at 10:59 AM
Hi there
There's a fairly classic solution to this 'recycling' problem. Typically it starts with:
the 'emitter' (i.e. your gun) having a list of currently active projectiles its fired
the 'projectile' knowing when it was fired, and who fired it
Projectiles typically 'die' for 1 of 3 reasons:
they hit something, and 'choose' to destroy themselves, and maybe trigger some game action like applicaton of damage
they reach a maximum life time (current time - fire time > x) and thus destroy themselves
the emitter wants to fire, and its list of currently active projectiles is longer than the maximum number of projectiles it supports, so it chooses to recycle one
So the basic procedure in your gun script should be:
//check if fire button pressed
if(pressed_fire)
{
//if we've hit the limit, destroy the oldest one (when a projectile dies it automatically removes itself from the list)
if (list_of_active_projectiles.count > maximum_active_projectiles)
kill_the_oldest_projectile();
//create a new projectile
new_projectile = Instantiate(my_projectile_prefab);
//... do whatever setup you do here ...
//tell the projectile who fired it, and add it to the active projectile list
new_projectile.emitter = this;
list_of_active_projectiles.Add(new_Projectile);
}
When a projectile is destroyed, it's script should automatically notify its emitter that it has been destroyed so that it is removed from the active projectile list.
So you're basically maintaining a list of projectiles your gun is responsible for. By doing this the gun is able to recycle existing projectiles by scanning that list and killing the oldest one.
Hope that helps :)
Answer by 8r3nd4n · Feb 11, 2014 at 11:41 AM
I can see how that works in principle but still a bit unsure as to where everything sits. The above would sit on the existing 'gun' object and manage the projectiles.
I don't get how the list (is it an IList in Unity?) takes care of the destroying of the objects (the kill_the_oldest_projectile(); method you have). At the moment, the projectile is just a gameobject with a collider and rigidbody. On the enemy is the hit collision points which destroy the projectile (I did it this way because all the animations sit on the enemy and it is easier to call different animation on collisions this way).
Also, where is the emitter property to sit? I coulnd't find any inbuilt unity ones.
Thanks again
I'd imagine you will have a 'Gun' script, which is on your gun, and a 'Projectile' script, which is on your projectile.
The Gun script has a member which is a List type (see System.Collections.Generic). This is the list of projectiles, and can be added to (when firing) using list.Add(anobject) or removed from when a projectile is destroyed using list.Remove(anobject).
Your Projectile script would have a member which is a Gun type, called 'emitter', which is set by the Gun script when firing.
The projectile script will have an 'OnDestroy' event, in which it gets the Gun script from its emitter, so that it can remove itself from the list.