How do I spawn multiple bullets with rigidbodies in the same spot without them colliding - unity3d

I am making a 2D game and have a basic weapon which I decided to call a pistol. I want to make a shotgun next and I have all of the work done except for the fact that they are all spawned in the same place and they all collide with each other.
I've had a few ideas like trying to turn off collisions for the rigidbodies (Didn't work), applying force without a rigidbody (Didn't work). I've done one game before this which was through a tutorial so this is my first real game and I just need help. If you need more details I can always send more. Thank you.

Jump into the Physics2D settings and make sure that the layer you’ve set for your “bullets” is not colliding with itself.
The one you’ll want to turn off for self collision is usually the one on the end, that intersects with itself on the row and column:

The script you need is the following line. In this line, Unity physics renders one collider ineffective against another.
Physics2D.IgnoreCollision(collider, ignoreCollider);
Also, with the algorithm below, you can neutralize all colliders at the moment of the bullet shot.
[SerializeField] private GameObject bulletType;
private List<Collider2D> _tempCollides;
void ShotBullets()
{
_tempCollides.Clear();
for (int i = 0; i < 4; i++)
{
// Instantiate and catch all colliders in a List
var collider = Instantiate(bulletType, AnyPlace, AnyRotation).GetComponent<Collider2D>();
_tempCollides.Add(collider);
}
foreach (var _collider in _tempCollides) // For Every Bullet Collider...
{
foreach (var _subCollider in _tempCollides) // .. Define to Ignore other Colliders..
{
if (_collider != _subCollider) Physics2D.IgnoreCollision(_collider, _subCollider);
}
}
}

Related

How to keep track of the damage taken?

So I'm making a simple 3D RPG game in Unity with a player and a bunch of enemies. What is the standard way to keep track of the damage taken in combat? I think the easiest way is to count damage everytime the attack animation is triggered, but how? How do I know whether an animation is triggered or not? Or is there any other way to do it? Please help, thanks in advance!
So you want to detect if the enemy hits you with a projectile/melee. The way to do that is attaching a collider to their weapon, you can do this by setting empty game objects as children of the weapon and attach individual collider components to them (Don’t do this unless you know how to make it not take multiple damages at once. Just for extra precision). Then what you want to do is for each/the collider hit the isTrigger check box so it has a check in it. Add a tag to the collider(s) that has a name like “damage” or “weapon”. Then open a script to attach to your player. Use OnTriggerEnter() to detect the weapon hitting your player:
...//the rest of your code before this.
public float health = 10f; //health value.
public float damageTick = 1f; //damage taken per hit
void OnTriggerEnter(Collider obj)
{
//for same damage per different weapon hit.
if (obj.GameObject.Tag == “damage”) //remember this is what the tag of the weapon was.
{
health -= damageTick;
//play the animation. You can do that.
}
//*optional* for different damage per weapon type.
if (obj.GameObject.Tag == “sword1”)
{
health -= sword1Damage; //make sure you have a variable for sword1Damage.
}
else if (obj.GameObject.Tag == “bow8”)
{
health -= bow8Damage; //make sure you have a variable for bow8Damage.
}
// add on to this if else, to make more weapons take different damage.
}
It's too expensive. If you have 10 enemies, then the calculations through the colliders will overload the system.
It's easier to calculate, when the user clicks on the attack button, create a primitive and see what objects are included in this primitive around it. Push them onto the stack. Further, if your attack is at a distance, you can count through the vectors of the nearest enemy, if the damage is massive, then you can set the hitting radius and inflict damage on all enemies in this zone using the observer pattern

Raycasting an instantly moved collider

I need to move some transforms with attached colliders to a specific position, then check if one of them is hit by raycast.
I've done that the naive way (pseudo code) :
foreach(object in objects){
actual_position = object.transform.position
object.transform.position = object.new_position
}
if(Physics.Raycast(...)) objectHit();
// Then I revert each of them them back to their actual_position
After testing multiple times with the same context (same positions between tests for each objects), the raycast sometimes miss, sometimes not (~50/50).
Done a bit of research and found that in the Raycast doc page :
If you move colliders from scripting or by animation, there needs to
be at least one FixedUpdate executed so that the physics library can
update its data structures, before a Raycast will hit the collider at
it's new position.
So I calmed my anger and started looking for a solution.
This thread has a way using a coroutine to wait the next tick :
Raycast doesn't work properly
I'm affraid it won't work for me, as I need the objects to get back to their real position instantly.
This process can happen multiple times per frame (each time a player fire his weapon)
Is there a way to force the colliders update ?
If not... should I make my own raycasts and colliders ? :(
Thanks
Another workaround is to deactivate and activate Gameobject (attached collider) immediately. In this case collider position will be updated in single frame.
Another solution is
Physics.autoSyncTransforms and Physics.SyncTransform
Maybe you can try this out (adding to your pseudo-code):
foreach(object in objects)
{
actual_position = object.transform.position;
object.transform.position = object.new_position;
StartCoroutine(CheckToRevertOnNextFixedUpdate(object, actual_position));
}
IEnumerator CheckToRevertOnNextFixedUpdate(object, actual_position)
{
yield return new WaitForFixedUpdate();
if(Physics.Raycast(...)) objectHit();
// Then I revert each of them them back to their actual_position
}
Essentially this delays your check to the next FixedUpdate() for each object - and reverts each of them if needed. I hope this is not overcomplicated, since you only add a few lines of code.
I'm also assuming that moving the object's position for 1 FixedUpdate() frame would not have a visual effect of the the object teleporting to the new position and back. However, you can always move the collider only, and then move the rest of the transform there after the FixedUpdate().
Performance-wise, the best method seems to be updating the RigidBody.position:
private Rigidbody Rigidbody;
void Start()
{
Rigidbody = gameObject.GetComponent<Rigidbody>();
}
void Upate()
{
//.... your code
Rigidbody.position = newPosition;
}
Much faster then deactivate/activate or Physics.SyncTransform().

Preventing colliders on the same rig from colliding with each other. But allowing them to collide with other rigs.

I have a prefab NPC which has a physics rig attached to it (to do some specific rag-doll stuff with). I need to avoid the various colliders on the same rig (arms, legs etc) from colliding with each other, but they have to be able to collide with the rigs of other instantiated NPCs.
Is there a way to do this? I know I can avoid all the colliders from colliding by putting them on a separate layer, but I cant create a new layer for every NPC.
Thanks
You can do by setting up IgnoreCollision on your NPC class if you have any
http://docs.unity3d.com/ScriptReference/Physics.IgnoreCollision.html
So simple loop through all colliders in the rig and set up to ignore each other
void Start() {
colliders = GetComponentsInChildren<Collider>();
foreach(Collider collider in colliders) {
otherColliders = GetComponentsInChildren<Collider>();
foreach(Collider otherColider in otherColliders) {
if (collider != otherColider) {
Physics.IgnoreCollision(collider, otherColider);
}
}
}
}
It looks like the only way to ignore collisions without using layers is to use Physics.IgnoreCollision() between a pair of colliders, for each pair.
You can write some code that would automatically register a newly instantiated game object and create these pairs between the new object and the other ones that were registered before, so you wouldn't need to call this method for each pair yourself.
Or, you can use this code that does that for you :) It has its own representation of layer to control how the objects should ignore each other.

Getting collisions for multiple object without the collision callbacks

I'm making a platformer (sidescroller), and right now I'm making a grenade-launcher for the player.
It spawns grenades which is a prefab, this prefab has a Circle Collider 2D which is the blast radius for the explosion.
When a grenade is spawned I run this (amongst other things);
// Add the initial force
rBody.AddForce(new Vector2(forceX, forceY) *300f);
Invoke("Explode", 2.5f);
I'm having trouble figuring out how I should handle the Explode function.
I would like to find all the GameObjects that are colliding with the Circle Collider 2D at that point, but I can't find a way to do it.
I would like to be able to do something like this (not real code but you understand what I'm trying to do)
void Explode () {
collidingObjects = circleCollider.getCollisions();
foreach(collidingObject as entity) {
if(entity = 'player')
player.pushLeftOrRight()
elseif(entity = 'enemy')
grenade.dealDamage(grenade.damage)
}
Debug.Log("Explode");
Destroy(gameObject);
}
I'm guessing that it wouldn't work so can anyone point me in the right direction?
In your grenade's script, use OnTriggerEnter or OnCollisionEnter to log collisions; basically just have a HashSet for each grenade that is updated and keeps track of what it is colliding with. Then Explode just has to iterate through this set when you call it.

unity3d 4.3 bullets coming back down

I am trying to build a 2D space shooter game where the player will remain constant at the bottom of the screen and will move left and right. When the player fires a bullet(projectile), the bullet is going up just fine, but it is coming back again. Also if two bullets collide, they react to the collision.
I have two questions here:
How can I ensure that the bullet does not come back? (One way is to destroy it after a few seconds, but not sure if this is the right way)
How do I avoid collision between the bullets.
Here is my code snippet:
void Update () {
if (Input.GetButtonDown("Fire1"))
{
Rigidbody2D clone = (Rigidbody2D)Instantiate(bullet, transform.position + transform.up, transform.rotation);
clone.velocity = transform.TransformDirection(Vector3.up * 20);
}
}
I am very new to Unity and somehow wrote this code by looking into Unity Forums.Any help will be very much appreciated.
Thanks
More details:
I have created the bullet and added Rigidbody2D and a BoxCollider2D for this object. Made the bullet object a prefab and I dragged it under the Player object. Now bullet is a child of the Player object. Attached the script above to the Player object.
To answer your immediate questions:
1) I am not too sure about how you have the scene setup or about using the Unity 2D tools but usually if your bullets are coming back down then I would assume that you still have gravity applied to the rigidbody -- so make sure that you have that unchecked.
2) With Unity3D for objects to interact with each other they need rigidbodies attached. This is vital, say, if you want your lasers to destroy Monster #1. However, you only need one rigidbody attached to an object to have a desired effect. I would suggest removing the rigidbody from your laser and attach rigidbodies to objects ( Monster #1 ) that you want to be affected by the laser fire. ( That should work, if not there are other options -- one using layers and ignoring particular objects on those layers ).
Tips:
Here are some extra things. When you are creating objects and they fly off screen over time they will build up. Imagine you are in a large battle and you instantiated hundreds of lasers -- it will eventually be an issue for performance. So always consider Destroying objects after a certain amount of time.
Also, after looking at your code, I can't tell whether the velocity of the object is based upon its current position and nothing is being added. What I think is happening is when you instantiate an object it may be moving up, but because there is no incrementer, the object ( as it gets higher ) slows until it is at a rate which it is falling. For example this
clone.velocity = transform.TransformDirection(Vector3.up * 20);
should probably do this:
clone.velocity += transform.TransformDirection(Vector3.up * 20);
Heres http://docs.unity3d.com/Documentation/ScriptReference/Vector3-up.html, to read up on velocity. The problem is is that you need to continuously apply a constant forward motion so things in motion will tend to stay in motion. If not gravity will pull it down.
Also, heres a bit of code that I've used in the past that's created a pretty cool shooting laser effect thing:
public class Laser : MonoBehaviour {
public int fireRate = 70;
void Start(){
InvokeRepeating("FireLaser", 0.01f, 0.009f);
Destroy( gameObject, 2.0f );
}
void FireLaser(){
transform.Translate( Vector3.up * fireRate * Time.deltaTime );
}
}
edit: it's 3 a.m. and I hate proofreading.