Get gameobject of unity collider when it is attached to a rigidbody - c#

I have a game object that has a rigidbody and then a group of sub game objects with sprites and colliders where each collider is attached to the parent's rigidbody.
This works well for the physics and collisions as the entire group of objects will bounce and collide off of the scenery.
However, when two groups collide I want their to be damage on one of the individual sub game objects.
I have a OnCollisionEnter2D(Collision2D coll) on each of the sub objects(Which have the collider on them) however, when they collide with another group using coll.gameObject the returned game object is always the parent and not the individual sub object.
Long Story Short:
Is there any way to get the game object of a collider when it is attached to another game object with a rigid body?
Note: I have seen some solutions that use a ray cast to find the object but it seems like a lot of unnecessary work.
Note 2: I have also seen options that use trigger but i prefer the collision as it handles physics as well.
private void OnCollisionEnter2D(Collision2D coll)
{
Debug.Log(coll.gameObject.name); // Showing the parent
ShipPiece sp = coll.gameObject.GetComponent<Piece>(); // Looking for the individual piece
if (sp != null)
{
// Apply the damage to the other piece based off the weight of this piece
coll.gameObject.SendMessage("ApplyDamage", weight*10);
}
}
Obviously I can can the first Piece in the collision as it is the class where OnCollisionEnter2D exists, but I cannot figure out a way to get the second Piece which its colliding into.

You're trying to get the gameObject property of the Collision2D object when you really want the gameObject properties of the Collider2D itself. Collision2D has the collider and otherCollider properties that you can use:
private void OnCollisionEnter2D(Collision2D coll)
{
Debug.Log(coll.collider.gameObject.name);
Debug.Log(coll.otherCollider.gameObject.name);
...
}

Related

Is there any way to get an object that can push/move a character controller?

I know you can use rigid body on two objects for collision and so on. I can do that just fine but I’m trying to do this without needing one on my player object.
But if I have a player object that is using only a character controller, is there any way to “push” them around when colliding with other objects?
As the CharacterController inherits from Collider you could do this if the other objects have a (kinematic) Rigidbody - at least one Rigidbody is required so the collision itself is detected (not sure on this though, might work without, the CharacterController is a special case) - and then use Physics.ComputePenetration in order to calculate the distance and direction you have to move your player in order to move it out of the hit collider => pushing it away.
[RequireComponent(typeof(Rigidbody))]
public class PushCharacter : MonoBehaviour
{
[SerializeField] Collider ownCollider;
void Awake ()
{
if(! ownCollider) ownCollider = GetComponentInChildren<Collider>();
}
void OnCollisionStay(Collision collision)
{
if(collision.collider is CharacterController character)
{
Physics.ComputePenetration(ownCollider, ownCollider.transform.position, ownCollider.transform.rotation, character, character.transform.position, character.transform.rotation, out var direction, out var distance);
character.Move(direction * distance);
}
}
}
Note also
One of the colliders has to be BoxCollider, SphereCollider CapsuleCollider or a convex MeshCollider. The other one can be any type.
Which limits the objects you can use as the pushing objects since the CharacterController is none of those (even though it kinda acts like a Capsule).
However - just as a heads-up - as soon as there are multiple pushing objects involved this could get quite complex!
Yes, of course it is possible to do it without using built in colliders and rigid bodies. They are just script after all.
One way to do this, is to see if one of the outer bounds of the player object are within Vector3-radius and Vector3+radius then apply force to the RigidBody or move the players Vector3.
There are countless possibilities for how to do this but the easiest way is definitely using colliders and RigidBodies..

Collisions between objects?

My problem looks like this:
I have one stationary object wall and second object that is moving projectile. I want projectile to stop when it collides with wall. But ewery my attempt ended with projectile passing through wall.
Only script that affects movement of projectile:
public Transform trans;
void Update()
{
trans.Translate(0, 0, speed * Time.deltaTime, Space.Self);
}
All compomponents of projectile:
All components of wall:
Note: I have correctly set up layers in project settings.
I have tried many combinations of rigit boddies, colliders, layers and so on, but projectile always passed through wall.
In general, your presented setup is right. The contacting object have a Rigidbody component, and the objects you can collide have at least a collider (not a trigger).
First possible problem: your Rigidbody is set to Kinematic. Did you enable all collision modes in Project Settings > Physics > Contact Pairs Mode?
Second problem is the use of transform.Translate in the Update. Translate will ignore physic and just move the object when you tell it to do, and Update may be out of sync with the physic loop, where it would be recommended to use FixedUpdate. Even using FixedUpdate, Translate will not do the right job. It will force the object to move and the physic can complain or not about that (it can move the object back, glitching, or it can just ignore and let the object pass).
The right way to move a Kinematic rigidbody is through rigidbody.MovePosition, as stated in the Unity docs. For non-kinematic objects, you can use AddForce. Some tutorials also teach to set velocity of Rigidbody, which is not recommended because it can have undesired effects. Do it if you know the side effects and really want them.
I had a similar issue before. May I suggest destroying the projectile instead? You will then have to use OnCollisionEnter().
First, create a script and attach it to your projectile game object. After that, give your wall a tag, like 'wall'. Then, do something like this:
void OnCollisionEnter(Collision collision)
{
// Gets information about the game object the projectile collided with
GameObject objectCollided = collision.gameObject;
if (objectCollided.tag == "wall'){
// Do something with either the wall/enemy
}
// Destroy the projectile
Destroy(gameObject);
}
Note: If the intent was not to destroy the projectile but rather sticking to the wall, I suggest you to use detect collision using Raycast. Raycast has a hitInfo parameter and stores information about a gameObject that it hit, as well as the where did the Ray hit the gameObject.
Thus you can use this to move your projectile accordingly. In my previous projects, I used the Rigidbody component of my projectile and used .AddForce() to shoot it out, then detect collision with OnCollisionEnter().
Maybe you could do the same, but have a separate function to remove that force on entering a collision. I never tried it so I do not know if it will work.
Transform.Translate overrides the physics engine of unity. If you want to take advantage of the rigidbody and collider components of your gameObjects, you need to use rigidbody.Velocity or (as unity recommends in the docs) rigidbody.AddForce, and make sure you set IsKinematic to False on both rigidbodies, so that they can interact with one another physically.

How to check Collision detection for GameObjects of same prefab (Unity)

(For 2D Project)
I created a gameObject and made it a prefab.
Now when the game starts, the prefab is used to instantiate gameObjects and they all should check if they collide with one another.
I tried other unity's collision methods but it didn't work.
They either kept colliding with themselves (their own rigidbody) or it didn't work at all.
I'm new to unity and learning things. I searched every where but didn't get my question solved. I'll appreciate any help, Thank you!
Prefab is loaded and Instantiated as such..
GameObject tile = Instantiate(Resources.Load("Prefabs/Tile") as GameObject);
Its a basic gameObject having SpriteRenderer 2D.
I used Box Collider 2D and Rigidbody 2D components on that prefab -
Inspector
A simple script which has OnTriggerEnter2D(Collider2D other) function to check if it collides..
using UnityEngine;
public class TileCollider : MonoBehaviour {
public Rigidbody2D triggerBody;
void OnTriggerEnter2D(Collider2D other) {
if (triggerBody == null)
return;
if (other.attachedRigidbody == triggerBody) {
Debug.Log("Collision!");
}
}
}
I tried it without any if statements - It triggers collision for the Rigidbody2D of the gameObject (itself)
I passed the Prefab itself to check the collision for - Script in Inspector.
This is where were things get bad. It looks for the rigidbody of its own gameObject but I wanted it to search for other cloned gameObjects from same prefab.
The first thing to look at to solve the problem is to check if your prefabs have tags attached to them.
Assuming you have the TileCollider script attached on your prefab which it looks like it is in the inspector, you are checking if the other.attachedRigidbody is its own rigid body (triggerBody). And an object cannot collide with itself. You should probably check if its own rigid body is not the other.attachedRigidbody. If its not its own rigidbody then you have collision with another GameObject!
I hope I understood your question correctly, Thanks!
There looks to be quite a few errors with your code. First, you've got a triggerBody but it doesn't look like it's assigned. Hopefully you're assigning this manually as part of the prefab arrangement, but you could guarantee this by doing that hookup in Start and throwing an error if it fails to get the Rigidbody, like:
public Rigidbody2D triggerBody;
void Start()
{
if(triggerBody == null) // Would happen if it's not set in the prefab
{
triggerBody = gameObject.GetComponent<RigidBody2D>();
}
if(triggerBody == null) // Would happen if there is no Rigidbody2D attached at all!
{
Debug.LogErrorFormat("Failed to find a Rigidbody2D to use with {0}!", gameObject.name);
}
}
Another issue is that you're asking for collisions, but your code is looking for triggers. Here's a link to an article, but the short version is that if you're checking OnTriggerEnter then at least one of the colliders involved needs to have the IsTrigger option ticked:
Another issue is that you're bailing on the operation if the triggerBody is null. As I mentioned at the start, you're not explicitly setting the triggerBody in your code, so if it's also not set in the prefab then you'd abort here even if the collider options were set correctly.
Finally, and probably most importantly, is this snippet doesn't make sense:
if (other.attachedRigidbody == triggerBody) {
Debug.Log("Collision!");
}
What you're saying here is that you want there to be a collision if the other rigidbody is the same as the local rigidbody. This would ensure the behavior you described in your post,
They either kept colliding with themselves (their own rigidbody) or it didn't work at all.
You're only calling it a collision if they're colliding with themselves! The way to check if it's NOT self-colliding is to make sure the other.attachedRigidbody is NOT equal to the local triggerBody!
What you would want instead would be:
if (other.attachedRigidbody != triggerBody) {
Debug.Log("Collision!");
}

Child Objects Not Following Parent Object On Frequent Teleportation

Game Screen
Teleportation Code
Child Objects And Their Original Location
I'm new to Unity, and so after taking just some regular online courses for Unity2D I wanted to mess around with adding in different features, the first of which I decided to do was something like in Portal, where a projectile spawns two connected portals you can teleport between. However, I've run into an issue. When I'm teleporting my character, sometimes, usually when I'm teleporting too quickly but can happen at any time, the child objects to the Player game object tend to shift, and I don't understand why. **I'd like to:
Know why the offset between the parent and child objects are changing through teleportation.
Know how to fix this issue, preferably in code I can easily understand as a beginner to Unity. Also preferably in a way that doesn't involve me constantly appending the child objects to the parent object through transform position with the added offset, though if it's the simplest solution I'm not against trying it.**
Something worth noting is that the offset change is different as well, I have a Child Object called Feet which detect the Ground for jumping, which seems to remain at the location of the previous portal when it first breaks. However, another child object called Gun which is where the projectiles spawn from seem to only move down a little bit, meaning there's inconsistency in how they are offset when they break. It might be because the Feet has a collider, but I'm unsure, don't know enough, and only felt it was worth mentioning.
[SerializeField] GameObject otherPortal;
Portal otherPortalComponent;
BoxCollider2D boxCollider2D;
bool firstEntered = true;
// Start is called before the first frame update
void Start()
{
boxCollider2D = GetComponent<BoxCollider2D>();
otherPortalComponent = otherPortal.GetComponent<Portal>();
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (boxCollider2D.IsTouchingLayers(LayerMask.GetMask("Player")) && firstEntered)
{
Teleport(collision.gameObject);
otherPortalComponent.SetFirstEnteredFalse();
}
}
private void Teleport(GameObject obj)
{
obj.transform.position = otherPortal.transform.GetChild(0).transform.position;
}
public void SetFirstEnteredFalse()
{
this.firstEntered = false;
}
private void OnTriggerExit2D(Collider2D collision)
{
this.firstEntered = true;
}
To simplify the question, the position of the child objects relative to the parent changes when I instantly change the parents position sometimes, why does this happen and how do I fix the issue without simply using transform.position in an Update method to constantly append the child to the parent, if possible.
I would look at your OnTriggerEnter2D method's if statement for a solution.
private void OnTriggerEnter2D(Collider2D collision)
{
if (boxCollider2D.IsTouchingLayers(LayerMask.GetMask("Player")) && firstEntered)
{
Teleport(collision.gameObject);
otherPortalComponent.SetFirstEnteredFalse();
}
}
Because you are using OnTriggerEnter this method will only be called with your feet since your player's main collider isn't a Trigger. This means that your collision variable that you call your Teleport method on is actually your feet object, not your player's body object. So you are changing the offset of your feet from your player in your Teleport method.
I would try changing your collision method to OnCollisionEnter2D(Collision2D)
which would pick up your player's base collider when it enters and not the feet collider.
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.GetComponent<Player>() && firstEntered)
{
Teleport(collision.gameObject);
otherPortalComponent.SetFirstEnteredFalse();
}
}
Since the Player script is on the same object as your base player collider you can do a simple GetComponent<Player>() call to check if its the player object. Though you could still use the Layer to check if you want.

Detecting if two game objects are overlapping / intersecting Unity

I have what I think is a straight forward question, but my lack of unity knowledge is hindering me.
I have primitive type game objects (e.g. a cube / capsule / sphere) rotated at various angles in my scene. They are already instantiated.
I then add a new game object primitive type to the scene and I want to know if this new game object overlaps / intersects the current primitive types in the scene.
To do this I have been using the gameobject1.GetComponent<Collider>.bounds.Intersects(gameobject2.GetComponent<Collider>.bounds)
However this doesn't work because the bounds is a bounding box so even if a game object isn't directly touching one of the primitive type game objects visually, if it's in it's bounding box, it returns that as true (i.e. they intersect) which is not what I want:
I'm sure there is another way of doing this in unity but I just don't know what I need to do!
Any help would be appreciated. Thanks
Use MeshCollider, instead of BoxCollider
void OnCollisionEnter(Collision collision)
{
foreach (ContactPoint contact in collision.contacts)
{
Debug.DrawRay(contact.point, contact.normal, Color.white);
}
}
You could use a MeshCollider instead (as long as your objects are simple) then set the MeshCollider IsTrigger property to true.
Then in code you can do:
void OnTriggerEnter(Collider col)
{
}
or
void OnCollisionEnter(Collision col)
{
}
When ever an object enters the collider, the above function will be called and you can do what you need to there.
Edit: Your objects will need a rigidbody added to them for the collision to work

Categories