Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by superdupergc · Jul 01, 2013 at 05:29 AM · collisionrandom

Help detecting collisions on complex objects with teleportation

I've been working on this all day and I need some help. I'm trying to spawn a bunch of buildings randomly in an area, but they keep spawning on top of and inside each other. Here's an album with my code and a screenshot of the spawning behavior:

http://imgur.com/a/E3kM2

Each building is a single color, made up of multiple box colliders with kinematic rigidbodies with IsTrigger unset. I randomly generate the building then send it to the TestCollision function. To test for collision, I create a new gameobject with a kinematic rigidbody, a trigger boxcollider, and this teleport tester script (code in the album). Then I disable the original game object, wait for a fixed update, and check the allClear variable.

The problem is, it doesn't detect collisions most of the time. When I spawn 100 buildings, it will detect maybe two collisions (triggering a retry), but it won't detect the dozen or so other collisions and buildings end up on top of one another.

Does anyone know what might be causing this? I'm guessing it's got something to do with that I'm putting the placeholder game object into other colliders which aren't moving, but I tried doing a WakeUp on the placeholder's rigidbody and that didn't work.

Comment
Add comment · Show 5
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image SinisterRainbow · Jul 01, 2013 at 05:55 AM 0
Share

So it finds no collisions? Why are you using a placeholder btw, why not just test the ToSpawn object directly? On appearance, it seems like doing a lot of extra work.

As for detection, if it's not detecting, and the collision boxes are set correctly, it may (guess work) have something to do with how the backend is implemented. $$anonymous$$y guess is if you spawn inside something else, it won't detect. You can try moving the new object a bit and see if it causes a triggers, tho my guess is if it's not clear in the first place, istrigger will never fire. actually, you can try moving the new object a good distance > any possible box collider size, then move it back to the original position, that should trigger it.

avatar image SinisterRainbow · Jul 01, 2013 at 05:56 AM 0
Share

note, if you move it, throw it in a coroutine so it takes a frame to move it out and a frame to move it back in. or better, spawn it say 200m away or whatever > max box collider size, then the next frame move it to the position you want and check for collision.

avatar image superdupergc · Jul 01, 2013 at 06:03 AM 0
Share

Thanks for your response. I tried testing the ToSpawn object directly, after looking at the Collisions table, I saw that a new object with a kinematic rigidbody, trigger collider setup should trigger vs any object type, even static collider objects. I didn't want to mess with those values and risk corrupting the original ToSpawn object.

The collision boxes (placeholder object) seem to be set up perfectly around the buildings (ToSpawn object), which I disable in order to prevent them from colliding with the collision box. The buildings aren't just spawning inside each other, they're spawning partially intersecting. I expected it to trigger then.

Would it be feasible to move the buildings around like you suggest? I feel like if I waited several frames to do that for each building, it could take forever. It seems like this should work easily and that I'm just doing something stupid.

avatar image SinisterRainbow · Jul 01, 2013 at 06:12 AM 0
Share

In a coroutine you aren't waiting several frames, you are just delaying each spawn by one frame. So say, if you spawn 25 buildings per frame, and take 10 frames to spawn 250 buildings, by the 11th frame all will have been tested.

avatar image superdupergc · Jul 01, 2013 at 02:52 PM 0
Share

SinisterRainbow - I think I'm fundamentally misunderstanding how coroutines work. I will read up on the documentation, but if you know of a good guide, I'd love to see it.

2 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by aldonaletto · Jul 01, 2013 at 04:54 PM

I used a similar trick to detect objects inside a given volume, but had to force collision calculation with a simple trick: assign transform.position to rigidbody.position. Take a look at my answer to this question.

EDITED: Complementing @SinisterRainbow's answer: since the collision detection function is a coroutine, you should chain the main loop to it. Chaining coroutines is much like a regular function call: control is transferred to the called routine and only returns to the caller when the routine ends. But there's a problem: a coroutine can't return any useful value (coroutines always return IEnumerator). In C# you could use the out or ref keywords to get the return value in a variable passed by reference, but in JS the only way is to use a class variable (class variables are always passed by ref). The JS code could be something like this:

 class AllClear { // declare the AllClear class
   result: boolean; // this variable will receive the returning value
 }
 
 private var allClear = AllClear(); // create a variable of type AllClear

 // SpawnBuildings is a coroutine
 function SpawnBuildings(howMany: int): IEnumerator {
   while (howMany > 0){
     var toSpawn = SelectRandomBuilding(); // randomly select a building 
     do {
       var pos: Vector3 = CalculateRandomPosition(); // draw a random position
       yield TestCollision(toSpawn, pos, allClear); // chain to the test collision coroutine
     } while (allClear.result == false); // repeat until clear position is found
     SpawnBuilding(toSpawn); // spawn the building
     howMany--; // decrement counter
   }
 }
 
 // TestCollision is a coroutine
 function TestCollision(model: GameObject, position: Vector3, isClear: AllClear): IEnumerator{
   isClear.result = false; // initialize result
   // do the collision test, then assign the result to isClear.result
   if (model doesn\'t collide with anything) isClear.result = true;
 }

NOTE: A couroutine always returns IEnumerator, but you don't need to explicitly declare its return type in JS (opposite to C#): the compiler automatically infers this when you use a yield statement inside a function. Despite this, I declared the IEnumerator type just to state that the functions above are coroutines.

Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image superdupergc · Jul 01, 2013 at 05:57 PM 0
Share

So here's what I wrote based on your answer. What's weird is that it actually does detect the collisions, but only way after my TestCollision function is complete. If I go to the inspector and manually search through my objects, I can see that the ones intersecting have AllClear unset.

Debug.Log("allclear is false!") is never called.

 private function TestCollision (ToSpawn : GameObject){
     
         //get max bounds of object and all decendents
         var BoundingBox = new Bounds(ToSpawn.transform.position, Vector3.zero);
          
          var ChildColliders = ToSpawn.GetComponentsInChildren(Collider);
         for (var ChildCollider : Collider in ChildColliders) {
                BoundingBox.Encapsulate(ChildCollider.bounds);
         }
         
         ToSpawn.SetActive(false);
         
         var Placeholder = new GameObject();
         Placeholder.transform.position = BoundingBox.center;
         Placeholder.transform.localScale = BoundingBox.size;
     
        
         var ph_box : BoxCollider = Placeholder.AddComponent(BoxCollider);
         ph_box.isTrigger = true;
         
            var ph_rigid : Rigidbody = Placeholder.AddComponent(Rigidbody);
         ph_rigid.is$$anonymous$$inematic = true;
         ph_rigid.position = Placeholder.transform.position;
     
                 
         //add teleport manager
         var ph_tptest = Placeholder.AddComponent(TeleportTester$$anonymous$$anager);
     
         StartCoroutine(WaitForFUpdate());
         
         //test
         var AllClear = ph_tptest.allClear;
         if (!AllClear){
             Debug.Log("allclear is false!");
         }
         
         //cleanup
         Destroy(Placeholder);
         ToSpawn.SetActive(true);
     
         return (!AllClear);  //if we're all clear, we do not have a collision
     }
avatar image SinisterRainbow · Jul 01, 2013 at 07:12 PM 1
Share

You may be assu$$anonymous$$g the Coroutine pauses the calling method, it doesn't. the coroutine should be thought of as sending it to another thread that may or may not be running, or better, sends it to a queue to execute 'later', and the caller just 'queues' it and keeps executing.. So the the co should be a self sufficient unit..when it has data 'later' it will let you know by calling another function or setting a class-scope variable or the like.

avatar image superdupergc · Jul 01, 2013 at 07:19 PM 0
Share

Hm, so my approach of calling the TestCollison function normally, and having it delete the object was better?

So reddit suggested I use the dirty solution of checking my bounding box against all other bounds in the scene... It works, but it's slow and I don't like it.

 private function TestCollisionBounds (ToSpawn : GameObject){
 
     var BoundingBox = Bounds(ToSpawn.transform.position, Vector3.zero);
     
     var ChildColliders = ToSpawn.GetComponentsInChildren(Collider);
     for (var ChildCollider : Collider in ChildColliders){
         BoundingBox.Encapsulate(ChildCollider.bounds);
     }
     
     BoundingBox.size += Vector3(1,0,1); //add a buffer of 1 on each side, so we can walk through
     
     ToSpawn.SetActive(false);
     
     var AllColliders = GameObject.FindObjectsOfType(Collider);
     for (var ChildCollider : Collider in AllColliders){
         if (BoundingBox.Intersects(ChildCollider.bounds)){
             return true;
         }
     }
     
     ToSpawn.SetActive(true);
     
     return false;
 }
avatar image SinisterRainbow · Jul 01, 2013 at 07:24 PM 0
Share

and aldonaletto - that's a nice way to do it, and may have saved me future thinking about the (other thread's topic) :) so thumbs up.

avatar image SinisterRainbow · Jul 10, 2013 at 12:39 AM 1
Share

you should select aldonaletto's answer and use his solution. there is no need to check against all bounding boxes. You're turning an 0(1) problem into an 0(n). if you use my suggestion to move the collision box out and back again it should work, aldonaletto also used anotehr technique slightly better - which he posted the link to.

Show more comments
avatar image
2

Answer by SinisterRainbow · Jul 01, 2013 at 03:56 PM

I don't know a good guide, but I'll try to explain simply. I think formatting is better in the answer section so I put it in here.

Coroutine's are perfect for doing heavy work broken up into several frames.

Examples:

I use them for cross-fading music, moving objects, and even to create a tiled game board with thousands of pieces in front of the player, but I only spawn a few pieces per frame. So instead of a loading-time/game hiccup by trying to do a heavy job at once, it keeps the framerate smooth by breaking it down into simple executions spread out over many frames..

To use it:

Basically inside a coroutine you create a loop, and at the end of that loop tell it to wait for the next frame (or you can have it wait based on time). .

So code for spawning your buildings may look like this (C#):

 public class Buildings {
  
   public int m_iMaxBuildings;
 
  public Init() {
   m_iMaxBuildings = 250;
   StartCoroutine(SpawnBuildings());  //<-- this is how you start it
  }    
  public IEnumerator SpawnBuildings() {
     Debug.Log("I will only print once"); //<--before the loop
     for (int i=0; i < m_iMaxBuildings; ++i) { // <-- start the loop, any kind of loop.
         SpawnASingleBuilding();
         yield return null;   // <-- here it pauses this function
         Debug.Log("This is the next frame"); // <-- it will start here next frame
     }                //<--end of for-loop, you can put more or do nothing else-->
      yield break;  //<--this is NOT necessary, i put it here to show you how to if 
                    //   you need to abort early, it will terminate the the function
  }

  public void SpawnASingleBuilding() {
       // ... your code here ..
  }
 };  //end class

On a side note, I also use it to delay actions once in awhile like playing particle effects for example. You can have as many yield... statements as you want as well.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image SinisterRainbow · Jul 01, 2013 at 04:02 PM 0
Share

btw, so psuedo code for what I was talking about with your project:

 ...
 public IEnumerator SpawnBuildings() {
    while (bSpawningBuildings) {
        SpawnABuildingALittleDistanceAway();
        yield return null; //pauses until next frame
        $$anonymous$$oveBuildingToDesiredPositionAndCheckForCollision(); //finishes the action
    
    }
 }
 ...
avatar image superdupergc · Jul 01, 2013 at 04:02 PM 0
Share

Oh that's awesome. Thank you for explaining that - I actually noticed a big frame hiccup when it spawns the buildings.

avatar image SinisterRainbow · Jul 01, 2013 at 04:19 PM 0
Share

sure thing, tell us if it worked, would be good to know for sure.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

17 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Respawn random objects 1 Answer

Colliders and waypoints... 2 Answers

Make a random choice on collision enter - c# 1 Answer

Why is my Rigidbody2D not moving? (C#) 1 Answer

Random Movement collision bug 3 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges