Hi everyone! I have couple of questions since I’m a beginner in Unity and I’ve recently started to learn it.
I want to make a gun shooting like this:
That could be achieved by instantiating objects (bullets) in front of the gun and then applying a velocity to them, right?
I tried to instantiate an object in front of the gun and then set it’s velocity to some value, but I’m getting an error “object reference not set to an instance of an object”. This is a line with the error:
Rigidbody bulletRigid = Instantiate(BulletObject, transform.position, transform.rotation) as Rigidbody;
Does anyone know why is this happening?
Could I just set the bullets to destroy themself after 2 seconds as soon as they are fired or is it a better idea to use an object pooling so when I’m using e.g. assault rifle, my scene won’t get full of bullet objects.
I have an empty object in my inspector that’s holding a script that is managing spawning of the enemies. The script has function “public void EnemyKilled()” and I want to call it from another script. How can I get a reference to another object from the inspector? I tried with using “public Gameobject object” but it only allows me to get the prefabs from assets folder. I also tried to add a tag to the empty object and then use “object = GameObject.FindGameObjectWithTag” which works fine and I can call the function but is there a better way?
Sorry for lots of questions but that’s bugging me right now and I really want to do it right. Thanks!
You’re going about it the wrong way. You’re trying to instantiate a Rigid body, which is only a component. Instead, you need to instantiate an entire GameObject.
Best way is to:
Create a new GameObject in your scene. Assign it some particle effects, a rigid body, a collider, everything a good, proper bullet needs. Maybe a mean name, too.
Make a Prefab out of it. You do that by dragging your bullet game object from the scene (or better, hierarchy view) into the Assets folder. Make a new folder for it to better organize it.
In your script that spawns bullets, make a new “public GameObject bulletPrefab;” variable. Assign this via Inspector by directly dragging your prefab from the assets, into the variable field in the script.
Change your spawning code to:
GameObject newBullet = Instantiate(bulletPrefab, transform.position, transform.rotation) as GameObject;
// apply velocity or direction by accessing it’s components:
newBullet.GetComponent().velocity = …
// if your prefab has a custom script on it or whatever:
newBullet.GetComponent().someVariable = …
3) Question is not exclusive. You can use both object pooling, and an object "lifetime" if you wish or whatever. Object pooling is a bit more advanced, you can work on that after you've got the basic spawning and mechanics down. As to the lifetime, there's two ways to go about it (the way I see it):
- **Easy way** - is to simply have a script on your bullet prefab, when you spawn the bullet you access the script and set a lifetime variable, the script counts down and destroys the game object when time reaches zero
- **Hard way** - If you have an object pool done, you already have reference list to all existing bullets in the scene. Use a comparable "List<float>" structure that keeps each bullet's lifetime stored, by index. Implement a function to retrieve a bullet (enable, reset location, set velocity and direction, set lifetime). Implement an Update function which goes through all listed float numbers. If some are below zero, find bullet object by index and disable it.
4) Yes there is a better way. When you declare "public GameObject", you _should_ be able to drag'n'drop a scene object in there anyway. From there just GetComponent<YourScriptOrWhatever>().EnemyKilled(). *Alternatively*, you can declare a "public YourScriptOrWhatever" variable. You can *also* just drag a gameobject into this field, if it contains your script component. This enables you to skip the "GetComponent" part.
I never use "tags" or even worse, finding by name string - it seems clunky and slow, and perhaps meant only for very rapid prototyping or quick testing, before being replaced with actual solid references.
Well, that's it, let me know if you need any further help, or if something was unclear.
The easiest method : after instantiating you simply do GameObject.Destroy(instantiatedPrefab, tumeToDestroy) ;
If you have a prefab with a code in the assets folder, you cant simply put a gameobject inside its variable
Shooting with actual gameobjects is a bad practice, you should use a raycast instead, it wont use up as many resources and gravity wont matter
Would I have to spawn objects and applying force to them to create the same effect like in the video?
I see. Thanks, will try to change it in my script
I’ll try firstly with destroying the objects after some time.
I tried to set “public WaveManager waveManager” (name of the script and the class in another file attached to empty object named WaveManager). I wouldn’t let me drag the empty object with the script to another script that is using that class. After that like I said, I tried to put GameObject as a variable so I could drag the empty object and use GetComponent so I could call the function there but it only let me drag prefabs placed in the assets folder. No scene objects which is really weird. I will try for sure some other stuff since I find using tags tedious.
@gorbit99 I already have it done with a raycast but the problem is I don’t know how to e.g. create a shotgun with 6 shots. My enemy prefab has a small cube as a child object which is just a point which has line renderer set up along with light and particle system component. While shooting, I’m just enabling a line renderer and other stuff to get that effect of shooting but what to do when I need to set 6 ray casts? I mean on having that same effect applied 6 times at once.
Oh, and thank you guys for helping me out. Much appreciated!
As to 1), yes pretty much - do it with some given fire rate, and direct it properly according to the mouse position and you more or less have the effect like in the video.
Weird, this should be working … could you perhaps post a screenshot or two of your setup, and a few lines of code off the scripts, just to see what’s happening? You should be able to drag a scene object into another script (which is also in the scene).
Is this related to your previous question, for example doing a shotgun blast?
I would first set up some sort of master ProjectileManager or similar script. Enemies and players would simply call ProjectileManager.DoProjectileShot(vectorOrigin, vectorTarget); or
ProjectileManager.DoScatterShot(vectorOrigin, vectorTarget, numberOfShots);
And then the Projectile manager would be responsible for properly spawning the effects, performing raycasts and calling the damage-related functions on enemies and player and so on.
As for the exact implementation of a scatter effect, I’d probably get a direction vector from origin and target, normalize it, initialize an array of vectors (by the number of shots fired), and then each would be the direction vector + small rotation applied to it, by random picked x, y and z rotation values.
Then do a raycast using those vectors to determine start and end points of the trail renderer (or whatever your VFX is), and also test the raycast hit’s target gameobject to see if it’s an enemy or destructable object or whatever.
This is the part that I don’t know how to make. I understand the whole procedure of setting the origin point, doing a raycast, getting hti point and showing the line renderer. All good. But how to do it 3-4 times at once if I’m only having one single line renderer component. I just can’t show one line renderer, hide it, then change it’s end point and show it again. I want to have multiple lines shown at once.
I’m using this script from Unity’s Survival Shooter:
void Shoot ()
{
// Reset the timer.
timer = 0f;
// Play the gun shot audioclip.
gunAudio.Play ();
// Enable the light.
gunLight.enabled = true;
// Stop the particles from playing if they were, then start the particles.
gunParticles.Stop ();
gunParticles.Play ();
// Enable the line renderer and set it's first position to be the end of the gun.
gunLine.enabled = true;
gunLine.SetPosition (0, transform.position);
// Set the shootRay so that it starts at the end of the gun and points forward from the barrel.
shootRay.origin = transform.position;
shootRay.direction = transform.forward;
// Perform the raycast against gameobjects on the shootable layer and if it hits something...
if(Physics.Raycast (shootRay, out shootHit, range, shootableMask))
{
// Try and find an EnemyHealth script on the gameobject hit.
EnemyHealth enemyHealth = shootHit.collider.GetComponent <EnemyHealth> ();
// If the EnemyHealth component exist...
if(enemyHealth != null)
{
// ... the enemy should take damage.
enemyHealth.TakeDamage (damagePerShot, shootHit.point);
}
// Set the second position of the line renderer to the point the raycast hit.
gunLine.SetPosition (1, shootHit.point);
}
// If the raycast didn't hit anything on the shootable layer...
else
{
// ... set the second position of the line renderer to the fullest extent of the gun's range.
gunLine.SetPosition (1, shootRay.origin + shootRay.direction * range);
}
}
EDIT: I have no idea why the indentation is all messed up.
This is because this script is specifically designed to do only one line renderer.
If you want multiple effects, you can’t “show” one line renderer multiple times - that’s not how computer graphics work
Your scene and everything in it will get rendered out in full once all of your scripts have done executing. So if you want multiple effects, you need to duplicate and position multiple objects which draw 1 effect each.
So, in super-simple example, simply make more gunLine objects, like
gunLine1, gunLine2, gunLine3 etc…
Then modify each slightly after a shot so they seperate out, like a shotgun spread.
Though, word to the wise: Do not try to learn programming or advanced concepts by going through somebody else’s (usually advanced) solutions of (usually advanced problems). The example projects are there just to help you out in some details, some syntax, some approaches or minor guidance. If you are not capable of producing something alike the example project yourself, you’ll just needlesly get lost in an already pre-made solution.
My advice: Take it slow. Take the example project’s assets so you don’t have to worry about artistic side of things, and try to build your own project from ground up. Set up player controls, set up some way to handle the shooting mechanics, set up a script that will spawn effects when you shoot, etc - you will get much farther and learn so much more, than trying to tweak an existing project (which wasn’t designed to be upgraded with arbitrary ideas).
Yeah, that’s why I didn’t get it how to make such a system with multiple lines.
I didn’t just copy this script for shooting from the example project. I watched the video and tried to get all its parts in my head so I can re-create the same thing anytime, which I did: https://drive.google.com/open?id=0B4fbai3YdzuYSGMxTEtWcXhRNG8
I’m trying to make my first project (or game) so I can learn Unity. I already know C++ and C so classes and objects are all good so far. I agree with your point, I will never try to just copy some solution and place it in my script without knowing anything about it.
I managed to spawn a bullet, check if it collides with an enemy and hurt him. I can’t believe everything works good
Then I tried to spawn 2 bullets. First problem was they got spawned on the same position and their colliders detected each other and they got immediately destroyed so I had to change second’s bullet position a little bit. All work now but I want to make them rotated like 30-40 degrees from each other. I tried with this:
GameObjectbulletShot=Instantiate(bulletObject,transform.position,transform.rotation)asGameObject;
bulletShot.GetComponent<Rigidbody>().velocity=100f*transform.forward;
Vector3pos=transform.position;
pos.x+=0.25f;
// tried here to change the forward vector so it could face different rotation
Vector3rot=transform.forward;
rot.y+=40f;
bulletShot=Instantiate(bulletObject,pos,Quaternion.LookRotation(rot))asGameObject;
bulletShot.GetComponent<Rigidbody>().velocity=100f*transform.forward;
The problem is, bullets are still facing the same direction, their position is just slightly different. Do you maybe know why?
Btw I tried to start a conversation with you so I don’t flood this topic anymore but it won’t let me send anything to you Could I maybe add you on the skype?
EDIT: Actually, nevermind. I DID IT https://drive.google.com/open?id=0B4fbai3YdzuYZWdGbXI0RWsyOW8
That is done with multiple rays so it’s really precise. I did some debugging to see how transform.forward works and applied some changes to it so everything works perfectly now!
There is a better way to solve the collision problems like that BTW.
In your inspector (for anything), you can see Layers. Create layers “Bullets”, “Enemies”, “Player”. Assign the prefabs/objects as needed.
Then, in Project settings → Physics, you will find “Layer collision matrix”. You can set the layer “bullets” to collide with “enemies” and “default”, but not with other bullets or player.
It helps with performance too, since a lot of collision checks get skilled.