- Home /
Spawning object at random, collision-free position
Hello, Is there any way to make an object "scan" a certain area (like a circle around him) and then spawn at a random position within that area that is free of collisions? Imagine as if it's a wizard teleporting around the screen. Note that this is for a 3D game.
Also, say I want this object to spawn on elevated platforms and even on the vertical sides of walls as well. How would I handle that?
Answer by duck · Apr 27, 2010 at 12:12 PM
You could do this by checking the spherical area around the target position first, using Physics.OverlapSphere.
Eg:
var checkResult = Physics.OverlapSphere( targetPosition, checkRadius );
if (checkResult.Length == 0) {
// all clear!
Instantiate( wizardPrefab, targetPosition, Quaternion.identity );
}
Note however that OverlapSphere only tests against the bounding boxes of other colliders, so if you are using complex scenery objects with mesh colliders, this solution probably won't work for you.
As a more accurate alternative, you could create a special "Teleport Tester" prefab. This would be an invisible GameObject, with a sphere collider attached, but that sphere collider should be set to isTrigger = true. It should have a script on it which sets a boolean flag as to whether any collisions have occurred. Call the script "TeleportTester". Eg:
// -- TeleportTester.js -- var allClear = true;
function OnCollisionEnter() { allClear = false; }
You could then instantiate this "Teleport Tester" prefab first, then allow one physics update step to elapse (using WaitForFixedUpdate), then test the "collided" variable to see whether any collisions were reported. If not, then you can instantiate the real wizard object in that position. You would of course want to Destroy() your tester instance afterwards too. Something like this:
var testerPrefab : TeleportTester; // drag tester prefab into this var var wizardPrefab : Wizard;
function TeleportWizard( targetPos : Vector3 ) : Wizard {
// test whether the target area is all clear:
var tester = Instantiate( testerPrefab, targetPos, Quaternion.identity );
yield new WaitForFixedUpdate();
if (tester.allClear) {
// all clear for wizard to appear!
var wizard = Instantiate( wizardPrefab, targetPos, Quaternion.identity );
return wizard ;
} else {
// maybe the calling function should pick a new spot and try again
return null;
}
}
Hope this helps!
(usual disclaimer - code untested, for illustrative purposes only)
I've been trying your script and i like the idea of sending a teleporter to check first but i keep getting an error that says Assets/Enemy Stuff/Zombie Spawn Script.js(4,49): BCE0018: The name 'EnemyPrefab' does not denote a valid type ('not found'). where whatever i put in there isnt a valid type. I'm doing this for zombies so i changed all the wizards to zombies basicaly and i'm having trouble
Just a note: if you have isTrigger=true, then the function is not OnCollisionEnter, it is OnTriggerEnter(var c:Collider). This took a while to figure out for a newbie.
Answer by Dascu · Apr 27, 2010 at 05:08 PM
Thanks for the reply. I'll try it out sometime. However, I've been looking into the scripting references, Raycasting in particular.
I've thought about the following possible solution: - Cast out rays in a sphere around the object. - Store the ones that collided and are within a certain distance into an array. - Randomly pick a position from this array and then use Physics.CheckSphere (a little "above" the position) to see if it's free. - If so, mark it as a teleport position, if not choose a new random position from that previous array.
I've never worked with raycasting before though. Do they work on MeshColliders? Do they pass through character/enemy objects? How would I handle casting them out in a sphere (I imagine I would need some mathematical formula)? Would this method not be too tasking on the CPU?
Would be nice if you (or anyone else) could answer those questions and/or point out if my proposed method could work or if it would be impractical.
Answer by unibacon · Jun 08, 2016 at 10:19 PM
@duck Hi I know this thread is really old but I came across it when trying to spawn in GameObjects without being stuck in one another. So my question is how would one do the first method in a for loop? I am really new to unity so i'm having a though time with this concept.
Answer by mightybob · Jun 08, 2016 at 10:36 PM
I would go about it by teleporting a trigger object around the area (using Random.Range in the coordinates) and if it collides, try again. If it doesn't collide, then that area is clear and then teleport the wizard.
Your answer
Follow this Question
Related Questions
Respawn random objects 1 Answer
Spawning if there is space 1 Answer
Trigger Spawning? 1 Answer
Spawner continuing after boss dies 1 Answer
I can't get Destroy(collision.gameObject) to work? 2 Answers