Multiple Colliders on Complex Object - unity3d

I have designed a complex city with thousand of objects like roads, sideways, buidlings, trees, etc. and imported to Unity3d
I want to put colliders over them, so that when player hit them, it should face collision and should not passes though them
Though it has many objects, if i put one by one collider to each object, it will take so much time. Is there any other way i can just select all of them and put collider.
Also, if i select all object and put colliders (Mesh Collider). it is not adding to the object
Please help

Editor Scripting to the rescue. I would write a tool similar to this example. It uses a Menu Item which can be selected via Window -> Collider Tool. It then runs our custom method to find all meshes, which we want to add a collider to, then adds one and also logs which GameObjects were changed.
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
public static class ColliderTool
{
[MenuItem("Window/Collider Tool")]
public static void RunTool()
{
List<MeshFilter> meshes = findObjectsThatNeedColliders();
for (int i = 0; i < meshes.Count; i++)
{
GameObject go = meshes[i].gameObject;
// Add a collider to each mesh and record the undo step.
MeshCollider collider = Undo.AddComponent<MeshCollider>(go);
// Use the existing mesh as the collider mesh.
collider.sharedMesh = meshes[i].sharedMesh;
Debug.Log("Added a new collider on: " + go.name, go);
}
Debug.Log("Done");
}
private static List<MeshFilter> findObjectsThatNeedColliders()
{
// This list will be filled with all meshes, which require a collider.
List<MeshFilter> meshesWithoutCollider = new List<MeshFilter>();
// Get all meshes in the scene. This only returns active ones.
// Maybe we also need inactive ones, which we can get via GetRootGameObjects and GetComponent.
MeshFilter[] allMeshes = GameObject.FindObjectsOfType<MeshFilter>();
foreach(MeshFilter mesh in allMeshes)
{
if(mesh.GetComponent<Collider>() == null)
meshesWithoutCollider.Add(mesh);
}
return meshesWithoutCollider;
}
}
You might need more complex rules about which objects require a collider and which type it should be, but a simple tool can still save you a lot of time before hand tweaking everything.
You should also consider making this selection based. The Selection class can give you a list of all selected objects. Some ideas:
Add a MeshCollider to all selected objects, if one doesn't already exist.
Add a BoxCollider to selected objects and scale it to an approximate size depending on the transform size or bounding box of the MeshRenderer.
My solution is based on your question about how to add a collider to many objects in a large scene. However, this might not be the overall best solution. Maybe too many MeshColliders hurt physics performance. You will most likely want to approximate most of the colliders with boxes and spheres, but of course you can still write a tool to help you with that.

Related

Unity - atoms - how do I get two atoms to stick to each other and move as one GameObject?

I am making a chemistry game in Unity where each atom is represented as a 3D GameObject sphere. I want the user to be able to drag an atom around and if it enters some set radius of another item that it can combine with, the two atoms "stick" together (or become "suctioned" together) and become one entity that can be dragged around and interacted with.
How it looks now:
How I want it to look after interaction:
Now comes the hard part trying to figure out how to do this. First, I attached a script to the Oxygen atom (red sphere). I want to see if the Hydrogen atom entered some radius. If it does, I create a new GameObject, make both the oxygen and hydrogen children of that object, give the new GameObject a rigidbody and collider, and turn off the rigidbodies of the children. So the problem with this is that once I do that, both spheres fall through the ground. Also, they still remain as separate spheres and don't look "stuck" together. If I drag the red sphere around, the white doesn't follow and vice versa.
Any help would be greatly appreciated.
void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.name == "HydrogenPrefab(Clone)")
{
Debug.Log("Hydrogen entered");
GameObject HOCombo = new GameObject();
//put both atoms under the same parent
collision.gameObject.transform.parent = HOCombo.transform;
this.transform.parent = HOCombo.transform;
//remove the rigidbodies
this.GetComponent<Rigidbody>().isKinematic = true;
collision.gameObject.GetComponent<Rigidbody>().isKinematic = true;
// make the parent a rigidbody;
HOCombo.AddComponent<Rigidbody>();
HOCombo.AddComponent<MeshCollider>();
}
}
It looks like a Fixed Joint could suits you.
Also make sure that you get the right object when you Raycast it. You'll probably need to move the children to a layer ignored by your raycast or use RaycastAll to get all hits (not just the first one) and manage to find the desired parent from there.

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.

Make rigid body bounce off the screen edge

I'm currently working on an object that involves bubble-like movement. This object has a rigidbody and a sphere collider.
I use the AddForce method every 1-3 seconds to make it move continuously and slowly.
Now I'd like to know how to make the rigidbody move in the opposite direction (a.k.a bounce off) when they reach the screen edge already. I have already computed the screen edges using ViewportToWorldPoint method.
One ineffective solution that I thought of is to put empty game objects with collider at the edges but that won't work in my case since I'm building for mobile devices which have different screen resolutions/sizes.
Anyone know a good solution for this?
I'm not sure i got the idea. But i think i had the same problem when i was writing an old mobile game.
I had the same idea you did, use empty game objects with box collider on the edges, but then i thought, this isn't responsive, so i wrote this code:
public class Walls_c : MonoBehaviour {
public Transform righttop;
public Transform rightbottom;
public Transform lefttop;
public Transform leftbottom;
// Use this for initialization
void Start () {
righttop.transform.position = Camera.main.ViewportToWorldPoint(new Vector3(1,1,0));
rightbottom.transform.position = Camera.main.ViewportToWorldPoint(new Vector3(1,0,0));
lefttop.transform.position = Camera.main.ViewportToWorldPoint(new Vector3(0,1,0));
leftbottom.transform.position = Camera.main.ViewportToWorldPoint(new Vector3(0,0,0));
}
}
With this, i always get the corners of the screen. It's no fancy... but it works.
Let me now if it works.
In order to get a reflection effect, you need Material. Attach a bouncy material to the edges(gameObject) and let the physics calculate what should be the reaction of collision.
Create a Physics 2D material and set the bounceness to some appropriate value say 0.2.
Regarding your issue:
One ineffective solution that I thought of is to put empty game
objects with collider at the edges but that won't work in my case
since I'm building for mobile devices which have different screen
resolutions/sizes.
If you are working with UI component then dealing with boundaries should not be a problem (since it anchors with different resolution) but if it is not the case you can create a script CameraResizer and an enum Anchor (Left, Right, Top, Bottom) and using the same way ViewportToWorldPoint you can align your empty gameObject (boundary) to any screen size by attaching it the gameObject.
Hope it helps!

Disable or enable collisions based on object tag Unity 2d

I want to disable or enable collision with object in unity 2d game based on its tag. Lets say I have object with tag "foo1" and objects with tag "foo2". If user choose to collide with objects "foo1" then it should not collide with objects "foo2".
How could I achieve this? I tried this:
void OnCollisionEnter(Object other)
{
if (other.tag == "foo1")
collider.enabled = false;
}
But this is not working for two reasons. First object has to have isTrigger set to true (this could not be set for objects that serves as ground) and if I disable entire collider then object will fall through ground.
I am new to unity and I will study it in more details but I am asking for quick help and maybe idea how to do this?
Instead of doing this via tags, you might want to have a look at layers.
By assigning different objects to different layers, you can set them to either collide with each other, or ignore any potential collisions. You can achieve this at
Edit->Project Settings->Physics
where you can edit the layer collision matrix, to enable or disable collisions between layer elements.

How to detect that my object is completely inside a box?

I'm developing a game that you drag and drop objects into boxes and I have no idea what's the best and most efficient way to detect whether my objects are in a box.
I'm well aware of colliders and I'm using BoxColliders and triggers to find out whether my object is touching a box but I want to detect the moment when my object (which we can assume to be sphere for sake of simplicity but later will be a mesh) is completely inside my box trigger/collider.
I read about "Contains" method of colliders but IIRC they just check if one single point inside that collider but I'm interested to know if the whole object is inside the collider.
Thanks in advance folks.
Short answer: If you want 100% accuracy, your algorithm will never be better than O(|V|) (worst case) where V = {all vertices in mesh}, meaning you'd run .Collides() over every vertex and break if you find one that is outside your container.
Longer answer: Several methods exist to subdivide mesh surfaces, examples include: KD-Trees, OcTrees. These are beyond the scope of an SO answer to provide a full implementation, I suggest you see the wiki pages for details.
You could use these methods to divide your mesh up in to smaller sets of vertices. To speed up your algorithm you would start at the root of your subdivision tree and test if that node is contained in your container box. Keep working through the tree until you find a node that is not contained by your box. This will allow your "contains" test to fail faster but ultimately you'll wind up testing every vertex if your box contains your mesh.
Caveat: This solution does not work if your mesh is animated. In that case your best bet is to use the bounds around things like arms, feet, legs, etc and use that information to cull your Contains() tests. Again, you'll end up having to test every vertex if the mesh is fully inside your box.
All boxes have a boxCollider. If an object touches the second box, the object must be inside the first box.
This is not a good solution but, maybe it will be usefull.
Use Renderer.bounds property to get bounding box of your object.
Depending on what object you have and how accurate you want to check it to be inside a collider you might than use one of the simple ways to determine that.
for a more refined and cleaner approach. this would be perfect for what you are doing .
you can check the distance between the object you are dragging and the box .
the box has a x,y,z value which represents its position in space.
so when you drag your gameobject it may be just 0.2 on the x,y, or z away from the centere of your box. so just use this method to calculate the distance between your dragged object and the box.
var other :Transform;
function Update()
{
var dist = Vector3.Distance(other.position, transform.position);
// while dragging
if(dist <10)// 10 being on all 3 axiz .
{
//dragged object.position = box position
}
if (dist == 0)
{
print("i am in the centre of the box");
}
}
thus your gameobject will be in the box .
The box within a box solution above is a good option, but if that won't work (due to variably sized/shaped objects) you might be able to accomplish something with Physics.Raycast or Collider.Raycast. I had a similar problem where I needed to test if arbitrary points were contained inside colliders (many of which were unusual blobby concave objects).
The basic idea is a "bed of nails" approach where I cast rays toward the point from multiple directions. If I hit the outside collider on all of the rays, then I can be pretty confident that the point is contained inside the collider (but still not completely certain). Here's a pic:
In this picture, we're trying to see if the blue point is inside the yellow collider. The GREEN arrows represent successful raycasts (the yellow collider is hit), and the PINK one is unsuccessful (the yellow collider is NOT hit).
Here is a code snippet illustrating this:
public static class CollisionUtils {
private static readonly Vector3[] raycastDirections;
// These are the directions that we shoot rays from to check the collider.
static UltrasoundCollisionUtils() {
raycastDirections = new Vector3[5];
raycastDirections[0] = new Vector3(0,1,0);
raycastDirections[1] = new Vector3(0,-1,-0);
raycastDirections[2] = new Vector3(0,0,1);
raycastDirections[3] = new Vector3(-1.41f, 0, -0.5f);
raycastDirections[4] = new Vector3(1.41f, 0, -0.5f);
}
public static bool IsContained (Vector3 targetPoint, Collider collider) {
// A quick check - if the bounds doesn't contain targetPoint, then it definitely can't be contained in the collider
if (!collider.bounds.Contains(targetPoint)) {
return false;
}
// The "100f * direction" is a magic number so that we
// start far enough from the point.
foreach (Vector3 direction in raycastDirections) {
Ray ray = new Ray(targetPoint - 100f * direction, direction);
RaycastHit dummyHit = new RaycastHit();
// dummyHit because collider.Raycast requires a RaycastHit
if (!collider.Raycast(ray, out dummyHit, 100f)) {
return false;
}
}
return true;
}
}
One way you could adapt this algorithm is rather than use Collider.Raycast, do a Physics.Raycast. If the rays hit anything other than your collider, then you know that your target object isn't entirely in the collider.
Add a BoxCollider which surrounds the whole of the object you are testing for and check its bounds min and max are contained within the BoxCollider its entering ... this may not suit for complex mesh objects but you may be able to get away with it and its cheap
Simply,
You can place a box Collider at the bottom of your container.. If your sphere or whatever object touches that then it is completely inside the container..
There is one method though....not that accurate but will work :
Make four empties with collider(Circle / Box) like four wheels of a car and make the object parent to these empty objects with collider.
Then assign every collider a bool whether it is touched or not....
Count the number of colliders touched along with the actual mesh collider...Roughly estimates the orientation of the overlap. If it is 2 that means touched or overlaped from sideways.
Ex: If two collider + the mesh collider is colliding which means it is overlapped sideways...
I solved it using bounds.contains(vector 3 point).
I placed a single point on the object to be detected, and once it was inside the checking limits, I was able to acknowledge its presence.
public class PointInsideBound : MonoBehaviour
{
public Collider BoundCollider;
private Transform pointToCheck;
private void OnTriggerEnter(Collider other)
{
if (pointToCheck == null)
{
//There is a point on top of the collided object. Getting the reference here.
pointToCheck = other.transform.GetChild(0);
}
}
private void OnTriggerStay(Collider other)
{
if (pointToCheck == null)
{
return;
}
if (BoundCollider.bounds.Contains(pointToCheck.position))
{
Debug.Log(" Point Inside the boxcollider");
BoundCollider.enabled = false;
}
}
}
You should use a collider. This is description. http://docs.unity3d.com/Documentation/ScriptReference/Collider.html