Problems with Projectiles

Hello,

I’m having some problems with a simple gun object I made for a 2D side-scroller. I mounted this object behind the character so that it looks like the projectiles are coming out the gun he is carrying. The gun itself is a cylinder (although I have also used an empty game object and gotten the same results). The script attached to the gun shoots instantiated bullets along the Z axis. The bullets themselves work fine (they have a five second lifespan and destroy themselves when they hit a target). The gun, however, is giving me sporadic results. Somewhere between one half and one third of the time, it shoots the bullets well BELOW the gun object. The gun itself isn’t moving in world space, yet the projectiles are not firing out of it, but again, beneath it.

Any help with correcting this problem would be very much appreciated. Please let me know if I need to provide more information.

There is a good possibility that your collider for your bullet is possibly reacting to the collider of your gun, especially if your bullet has a rigidbody.

Try using Physics.IgnoreCollision(gun.collider, gameObject.root.collider); on your bullet, and see if that doesn’t correct the problem.

-Raiden

1 Like

As mentioned, the bullets are probably hitting the collider around your player or gun. You can use Physics.IgnoreCollision, but this state information can be lost and it is a bit expensive. Instead, assuming you are instantiating prefabs for your projectiles, just move the instantiation point outside of your body or gun collider. That will ensure the collision never happens in the first place and if you have a decent amount of velocity on the projectile, you won’t be able to tell where it is actually originating.

Here’s an example:

var bulletClone : Rigidbody = Instantiate (this.bulletPrefab, firePos, this.bulletPrefab.transform.rotation);

firePos is a position outside of the collider.

Hey, guys. Thanks a lot for the input. At this point, I’m not sure whether or not it’s a collision problem. I re-built the gun with an empty game object (with no collider since it doesn’t need one technically) and I have a gun that works consistently – until I attach it to the character. I would be tempted to say that the bullets are colliding with the collider on the character mover, but I have moved the gun object to several different points well away from said collider and I’m still getting inconsistent firing results (although they are more consistent than they were before). Does the influence of the character mover’s collider extend beyond the actual collider object itself? Obviously, if it calculates in a radius that extends beyond what I can see, I need to take this radius into account. Just so I know: Could the problem be that the gun object/bullets are reacting adversely to being in a hierarchy, and if so, is there another (safer) way I can get the gun to travel along with the character?

As you can probably tell, I am a relative new-comer to game building and I’m still working on my scripting skills. HanuiTech: When you say firePos is a position outside the collider, do you mean that I should substitute a number value for firePos (or set firePos up as a variable with a number value at the beginning of my script)?

As a first step, as previously recommended, add some calls to Physics.IgnoreCollision between the collider of the round and that of the character and your gun (if any) to rule out an inadvertent collision. Then make sure that you are firing the rounds in the direction you think you are. For example, you may be firing them back into the colliders rather than the other way around.

By the way, in rereading your post. I assume that in your 2D game you have an texture image representing your sprite mapped onto a cube that is 1 unit x 1 unit by some small fractional unit deep (i.e. these are the scale settings in the transform section of the inspector contents for the object. Is this the situation?

You say that your other object is “behind” this sprite. If you look in the inspector you will see that the box collider will remain at a scale of 1x1x1 despite the change to the game object’s scale. The object firing the projectile behind your game object, may still be inside the box collider of your sprite game object. A quick way to tell is in the Unity editor, click on the box collider for your sprite game object. Then at the top of the Unity window, go to the Game Object menu, and click on Align View to Selected. Then in the pane of the editor that is showing the scene (not the game), you will see a drop down at the top of the pane that probably says “front”, change that to “top”. You should now be looking down on your game object. Click again on the game object’s collider back in the inspector pane which will highlight the collider in the scene view, rather than the game object. (You can scroll your mouse to zoom in and out, and click and drag to move the view around.) Now look where your projectile firing game object is. If it is inside the highlighted collider, then you know what the problem is. If not, report back and we can discuss further.

It probably couldn’t hurt to tell you a little about how I’ve set things up in my project…

I’m not doing a straightforward sprite-based 2D scroller. I’m actually planning on doing my characters in a 3D program as “paper-dolls”, a hierarchy of planes with body parts textured onto them. For now, I am in prototype mode and my “character” is nothing more than a plane created in Unity, rotated up so that it faces the camera and attached to a character mover. This plane has no collider on it (and my paper-doll characters, when complete, won’t have colliders on them either). For my character mover, I repurposed the one that came with Unity so that it moves in only one direction (perpendicular to the camera) and jumps. This controller has a rigid body collider. The gun I created is an empty game object (renamed “gun”) that has no collider on it. The bullets are spheres created in Unity each with a rigid body collider of its own (all are, of course, identical since they’re instantiated by the script attached to the gun). The scenery is made up of planes with alpha textures on them, also rotated up so that they face the camera. These do not have colliders on them at all. The ground plane does have a mesh collider on it (for obvious reasons), but probably isn’t the culprit since it doesn’t interfere with the gun firing properly when the gun isn’t attached to the character.

As I said, the gun only misfires when it’s attached to the character hierarchy and the only collider within this system is the rigid body attached to the controller. I am having some difficulty implementing the Physics.IgnoreCollision as part of my bullet script for syntax reasons (chalk this up to inexperience). Here is the line I added near the top of my bullet script:

Physics.IgnoreCollision(characterMover.collider, gameObject.collider);

This produces an error when I run the game. It says that characterMover is an “Unknown Identifier” (despite the fact that this is the name assigned to the object in the Hierarchy panel). I’m not sure how to get the script to find a particular object within the scene. How would I go about telling the bullet to avoid collisions with the characterMover’s collider?

Thanks again for your input and your patience.

Can you post your script so I can take a look?

Sure. Here’s the one attached to the bullet:

// This script gets attached to the Bullet object...
var hitClip : AudioClip;
		

function OnCollisionEnter(collision:Collision){
	
	Physics.IgnoreCollision(characterMover.collider, gameObject.collider);
	
	// The following three "if" statements check to 
	// make sure the bullets are destroying themselves 
	// when they impact things that AREN'T enemies...
	
	if(collision.gameObject.tag == "scenery"){
		
		Destroy(gameObject);
		
	}
	
	if(collision.gameObject.tag == "powerUp"){
		
		Destroy(gameObject);
		
	}
	
	if(collision.gameObject.tag == "food"){
		
		Destroy(gameObject);
		
	}
	
	// Now we get into what happens when a bullet 
	// impacts an object with the tage enemy...
	// (basically, it destroys the enemy, and itself,
	//  raises the player's score, and plays a sound...)
	if(collision.gameObject.tag == "enemy"){
		
		// This destroys the enemy target which was just 
		// been impacted...
		Destroy(collision.gameObject);
		Destroy(gameObject);
		playerHealth.score = playerHealth.score + 10;	
	// this replaces the enemy model with a prefab explosion
	var theClonedExplosion : Transform;
    theClonedExplosion = Instantiate(playerHealth.explosion,
            transform.position, transform.rotation);            
		audio.PlayOneShot(hitClip);
		
	}
}	

	// Allow the Bullet to remain in play for two seconds
	// provided it hasn't hit anything...
		function Update(){
		
		Destroy(gameObject,2);
	}

And this is the one attached to the gun:

// Attach this script to Gun object so that Bullets can
// be fired out of it...

var myBulletPrefab : Rigidbody;
var shootForce : int = 20;
var shootClip : AudioClip;

function Update () {
	
	
		if(Input.GetButtonDown("Fire1")){	
			
			var Bullet : Rigidbody = Instantiate(myBulletPrefab, transform.position, transform.rotation);
			// The following shoots the Bullet object in the Z axis
			// (change the axis to suit your needs)...
			Bullet.velocity = transform.TransformDirection(Vector3 (0,0,shootForce));
			
		
		}
	
	}

You need to make some changes to this code and then put it in the script that fires the round. I assume this is the game object that is your gun.

(...other code)

var bulletClone : Rigidbody = Instantiate (this.bulletPrefab, firePos, this.bulletPrefab.transform.rotation);

(...possibly other code)

var characterMoverObj: GameObject = GameObject.Find("characterMover");

Physics.IgnoreCollision(characterMoverObj.collider, bulletClone.gameObject.collider);
Physics.IgnoreCollision(this.gameObject.collider, bulletClone.gameObject.collider);

This code will tell the physics engine to ignore collisions both between the bullet and character’s collider. and the bullet and the gun’s collider. (I assume those are the only two collider’s involved other than that contained by the bullet.)

You’re getting that error because you don’t have a reference to the game object called “characterMover”. Declaring/using a variable with the same name as the game object doesn’t give you a reference to it. Also, you can’t put this code in a collision event handler, like OnCollisionEnter. That function is called in response to a collision. If you put the code there, you are asking the physics engine to ignore something that has already happened. Instead. this code should go in the script that fires the bullet.

This code is not optimal, and you should be able to fire the bullets from a point free of any collider. We can revisit once we troubleshoot what is going on. Give this a try, and let me know what happens.

One more thing, put the code below into the script attached to the bullet. If there isn’t one then create a new script, put this code into it, and then drag the script onto the bullet prefab instance in the Unity Editor.

function OnCollisionEnter(other: collision) {

  Debug.Log("I hit: " + other.gameObject.name);
  Debug.Log("I hit: " + other.gameObject.tag);

}

This won’t fix your problem but it will tell you what the bullet is hitting, and whether it is the collider of your character or the gun.

Also, make sure that the variable “shootForce” in your code is not zero. If it is then the bullet’s velocity will be set to zero, and it will just fall on the ground. This variable should be declared outside of any function in the script that fires the bullet like this:

public var shootForce: float = 0.0;

This will allow you to set its value in the Unity Editor, within the inspector pane that is populated when you click on your gun object. You can assign a value to it when you declare it, but better to make it initially zero and then assign a value to it in the editor.

Since you seem to be new to scripting, let me explain a few other things while we’re at it, in case you are not aware:

By declaring shootForce outside of a function, it becomes an instance member variable on the gun game object. This allows its value to persist across different time, and be accessible in the scripts functions, such as Update. You can actually have three different types of variables: 1) One that has local scope which is declared inside a function. This variable persists only during the function call. 2) One that has object instance scope. Its value persists as long as the game object exists. 3) One that has scope across all instances of a game object.

The other thing I wanted to point out is that OnCollisionEnter is an event handler. When you see a function or method prefaced with the word “On”, this normally means that the function is an event handler, meaning that it is called in the event something happens. In this case, that event is a collision. Each object that can has a collider (or is a trigger) can participate in a collision event, and the script attached to that object can, but does not have to, implement an event handler which will be called when the collision occurs. You should only put code pertaining to a collision event inside a collision event handler.

Once we solve your problem, I can give you a few more pointers on how to organize your code, but generally doing as you are below, where you have your bullet’s collision event handler, handling different types of events for multiple game objects is not good design. Basically the bullet should only worry about animating an explosion (if applicable), playing an explosion sound (if applicable), and destroying itself. The different objects being hit, which can and should also define an OnCollisionEnter function can handle their respective behaviors accordingly. This is called encapsulation. The practice allows you to hide the information and logic used to implement an object’s behavior from other object. This then makes it easier to extend your game’s behaviors, and reduces the likelihood of bugs. Doing as you are below would require adding more and more conditional statements to the event handling code in your bullet each time you add a new types of game objects and behavior. Because you are doing it in a big “logic switchyard”, any bug you introduce will have the potential to impact your whole game not just one object or behavior.

Well, unfortunately, I’m still getting the same result. Here is my gun code as it sits now…

// Attach this script to Gun object so that Bullets can
// be fired out of it...

var myBulletPrefab : Rigidbody;
var shootForce : float = 0.0;
var shootClip : AudioClip;

function Update () {
	
	
		if(Input.GetButtonDown("Fire1")){	
			
			var bulletClone : Rigidbody = Instantiate(myBulletPrefab, transform.position, 
			transform.rotation);
			// The following shoots the Bullet object in the Z axis
			// (change the axis to suit your needs)...
			bulletClone.velocity = transform.TransformDirection(Vector3 (0,0,shootForce));
			
			var characterMoverObj : GameObject = GameObject.Find("characterMover");
			
			Physics.IgnoreCollision(characterMoverObj.collider,
			bulletClone.gameObject.collider);
			// Physics.IgnoreCollision(this.gameObject.collider,
			// bulletClone.gameObject.collider);
			
			audio.PlayOneShot(shootClip);
		
		}
	
	}

As you can see, there are some differences from your example. When I used “this.myBulletPrefab” nothing was fired from the gun. I tried replacing “transform.position” with “firePos”, but Unity claimed “firePos” was an unknown identifier. Also, I remarked the code for ignoring collisions with the gun itself since the gun doesn’t have a collider.

I’m glad to know the syntax for designating a specific object from the hierarchy, but the collider on the character controller doesn’t seem to have been the problem. I have been testing the gun outside the hierarchy of the player character and it works fine. When I attach it to the character is when it starts to misfire, but I’m not actually moving it from its test position. It seems to me that, were it hitting the character mover’s collider it would have been doing so during the testing phase as well since its position isn’t changing. Based on the fact that it is only misfiring when attached to the character, could it be that the gun is inheriting some bad position/rotation info from its parent and is misfiring the occasional bullet as a result of that bad data?

Also, I wasn’t able to incorporate the debug code. Unity had problems with the line "function OnCollisionEnter(other: collision) ". For some reason, it didn’t understand “collision” and asked me if I meant “UnityEngine.Collision”.

That’s because Unity needs an abstract reference when declaring a variable. It’s always function OnCollisionEnter(other : Collision).

The lowercase one is an instance of a collision, not a declaration of the class.

Other than that, firePos IS an unknown identifier, as you don’t have a variable named firePos. If you want to use one, make firePos a transform variable, create an empty gameObject, move that gameObject to where you want the bullet to appear, and drag the transform onto the variable in the script. You’ll have to use firePos.position to get where it is, of course.

I’d have to take a look at the project to give a specific solution, though. Can’t see why it’s misfiring from over here.

myBulletPrefab and firePos are just placeholder variables, you’ll need to replace them with your projectile prefab and a the position you want to fire from (outside of the gun’s colliders–refer back to our discussion at the top of the thread on this).

Sorry, on the code snippet I sent, it should have been “Collision”, not “collision”, referring to the name of the Collision class of which other is an instance. Did you make this correction and then run the code? If so, what did the round hit if anything?

If you didn’t, then try it. You can get the debug log output from the Console from the Unit Window menu. Please post back with what you find.

Regarding your last question about bad data, if you put the gun inside of the character object (I thought you said it was just positioned behind it), then its transform is going to be relative to the parents, not the world, so yes this can have an impact.

Try changing this:

bulletClone.velocity = transform.TransformDirection(Vector3 (0,0,shootForce));

To this:

bulletClone.velocity = bulletClone.transform.parent.TransformDirection(Vector3 (0,0,shootForce));

This should give you a velocity vector along the parent’s Z axis in world space. Let me know what happens.

Thanks, guys. Yeah, I was able to get the debug code in there. Part of the reason it wasn’t working was the other collision check it was doing earlier in the script. I remarked this out long enough to run it with debug code active and the bullets were only hitting enemies (so apparently it’s not an issue with colliding with the player character controller).

Sorry if I was unclear on this. Yes, the gun has always been positioned behind the character and its controller. What I meant was, while I’m testing it, it is not a child of the character. When I make the character the parent of the gun, I am not moving the gun at all. It is after I perform this operation that I begin to get erratic results.

I tried changing the bulletClone velocity code as you suggested and found that the bullets no longer had any velocity (despite the fact that shootForce was still set to “10” in the inspector). (Specifically, it would appear as though nothing was happening at first and then all of the bullets would drift out from behind the character at a slow rate of speed and in both directions along the Z axis.)

Okay, at this point, can you send me your whole script, or scripts so I can take a look collectively. I can’t do much more without seeing everything that is going on.

What would be the best way to get it to you? I zipped up the entire project (14mb) but the forum here keeps telling me I need to select a post mode (?) when I try and attach it.

Hey guys,

I did a little experimentation this morning, creating a new scene with a ground plane, a first person character (from the Standard Assets) and the gun I’ve been using all along. The gun fires appropriately when attached to this new character in this fresh scene.

This, of course, got me to thinking there might be some things wrong in my original scene – specifically, the way I set up the character itself or the modified script I was using to move it around. Here is that script…

var speed = 6.0;
var jumpSpeed = 8.0;
var gravity = 20.0;

private var moveDirection = Vector3.zero;
private var grounded : boolean = false;

function FixedUpdate() {
	if (grounded) {
		// We are grounded, so recalculate moveDirection directly from axes
		moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0);
		moveDirection = transform.TransformDirection(moveDirection);
		moveDirection *= speed;
		
		if (Input.GetButton ("Jump")) {
			moveDirection.y = jumpSpeed;
		}
	}

	// Apply gravity
	moveDirection.y -= gravity * Time.deltaTime;
	
	// Move the controller
	var controller : CharacterController = GetComponent(CharacterController);
	var flags = controller.Move(moveDirection * Time.deltaTime);
	grounded = (flags  CollisionFlags.CollidedBelow) != 0;
}

@script RequireComponent(CharacterController)

As you can see, this is just a modified version of the FPS Walker script. I took out the piece of code “Input.GetAxis(“Vertical”)” from line 11 so that the character would only move on the horizontal axis. Could this be part of my problem, perhaps? Is there a better script for getting this sort of “side-scroller” movement onto a character (one that might be a little more “gun friendly”)?