In general, I never use prefabs in doing bullets. I always simply attach a bullet to the barrel of the gun and make it inactive. Then I instantiate the bullet in that spot, at that rotation and make it active. If I then only want that bullet to exist for a few seconds, i put Destroy(newBullet,5) in the gun’s script.
public class GenericGun : MonoBehaviour {
public float fireRate = 5;
public float bulletDecay = 5;
private float lastShot = 0;
public GameObject bulletPrefab;
void Start(){
if(bulletPrefab) bulletPrefab.SetActive(false);
}
void Update(){
if (Input.GetButtonDown("Fire1")) Shoot();
}
public virtual void Shoot(){
if(!bulletPrefab) return;
if(Time.time > fireRate + lastShot){
GameObject bullet = (GameObject)Instantiate(bulletPrefab, bulletPrefab.transform.position, bulletPrefab.transform.rotation);
bullet.SetActive(false);
if(bulletDecay > 0) Destroy(bullet, bulletDecay);
lastShot = Time.time;
}
}
}
Very simple creator. Duplicate the bullet on the end of the gun, make it active, and tell it to destroy it’s self. There are a few changes to this, that you will notice. I changed the name, I made gave it a prefab so you can drag and drop a bullet onto the prefab for the gun and I used a term here… Virtual. Which I will discuss later.
OK, other than that, let’s change the way you think just a little.
first, lets simply create a generic bullet. This is a simple set of instructions that can be applied to any object that moves through space and hits something.
public class GenericBullet : MonoBehaviour {
public float damage = 1;
public float speed = 10.0f;
public bool useGravity = true;
public float damper = 0; // slows the bullet down over time.
private Vector3 gravity = Vector3.zero;
void Start () {
if(collider) Destroy(collider);
}
// Update is called once per frame
void Update () {
DoMovement();
}
public virtual void DoMovement(){
speed = speed - damper * Time.deltaTime;
if(useGravity) gravity = gravity + Physics.gravity * Time.deltaTime;
Vector3 direction = (gravity + transform.forward * speed) * Time.deltaTime;
Ray ray = new Ray(transform.position, direction);
RaycastHit hit;
if(Physics.Raycast(ray, out hit, direction.magnitude)){
HitTarget(hit.collider);
}
}
public virtual void HitTarget(RaycastHit hit){
Destroy(gameObject);
Debug.Log("Hit Object: " + hit.collider.ToString());
hit.collider.transform.root.gameObject.BroadcastMessage("ApplyDamage", this.damage, SendMessageOptions.DontRequireReceiver);
}
}
You will notice some simple things, and some things you probably haven’t thought about. First, NO COLLIDERS… Physics is great and all that, but a simple collision system is far better than letting the big world handle yet another bullet from a gun crazy super spy.
So every update, we check for the bullet’s movement and see if it hit something. If so, we simply run a command that says we hit something. Very generic.
Now, lets change some more about how you think… The term “Vritual” means that this method can be replaced later down the road. This means that you can morph this whole class into another thing all together. You will notice that the DoMovement and HitTarget methods are virtual. This means you can simply rewrite them if you desire. If you don’t you can still call them as if they were there.
Next, look at the current HitTarget method. You will notice that we first destroy the bullet, so that it wont affect anything else. Next, we use BroadcastMessage on the root of the collider. BoradcastMessage calls a method from that object, or any child in that object. So if you have a piece of glass in your scene, it will cause damage to the glass. If you have a monster, it will cause damage to the monster. and so on. All you have to have for the whole thing to work is a method on the other side called ApplyDamage. and it has to recieve a float.
Next lets morph (yes morph, as in Polymorphism, look it up, it’s all there) this whole class into a special class. One for your LightSpell_Shoot.
public class LightSpell_Shoot : GenericBullet {
public override void HitTarget(RaycastHit hit){
Destroy(gameObject);
Destroy(hit.collider.transform.root.gameObject);
Debug.Log("Boom!!!!");
}
}
First, instead of MonoBehaviour, we are using GenericBullet, the class we created before. Also, notice that I don’t rewrite the update, or various other things. The GenericBullet should take care of these. I did however, provide it with a new HitTarget. This one is simple… DESTROY EVERYTHING… muahahahawwwwawwaw…
From above… you can use the GenericGun also and overwrite the Shoot, or whatever you need. They are now core classes that you use to make things. In the editor, you make a gun, want or whatever, you make the bullet it shoots, you apply base scripts, or update them to your needs make, press a button and it makes everything work.