Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

EDIT: I changed some code after getting advice from colleagues. However it still has problems occasionally, though the problems aren't as bad or frequent. Here's the new code I'm actually using: `

             //This is what randomly generates all the items.
void SpawnItems () {
    if (Application.loadedLevelName == "Menu" || Application.loadedLevelName == "End Demo" || Application.loadedLevelName == "Controls")
        return;
    //The bottom corner of the box we want to spawn items in.
    Vector3 spawnBoxBot = Vector3.zero;
    //Top corner.
    Vector3 spawnBoxTop = Vector3.zero;

    //If we're in the dungeon, set the box to the dungeon box and tell the items we want to spawn.
    if (Application.loadedLevelName == "dungeonScene") {
        spawnBoxBot = new Vector3 (8.857f, 0, 9.06f);
        spawnBoxTop = new Vector3 (-27.98f, 2.4f, -15);
        itemSpawn = dungeonSpawn;
    }

    //Spawn all the items.
    for (i = 0; i != itemSpawn.Length; i ++) {
        spawnedItem = null;
        //Zeroes out our random location
        Vector3 randomLocation = Vector3.zero;
        //Gets the meshfilter of the item we'll be spawning
        MeshFilter mf = itemSpawn[i].GetComponent<MeshFilter>();
        //Gets it's bounds (see how big it is)
        Bounds bounds = mf.sharedMesh.bounds;
        //Get it's radius
        //float maxRadius = new Vector3 (bounds.extents.x + 10f, bounds.extents.y + 10f, bounds.extents.z + 10f).magnitude * 5f;
        float maxRadius = new Vector3 (bounds.extents.x, bounds.extents.y, bounds.extents.z).magnitude;

        //If we're in the dungeon, certain items need to spawn on certain halves.
        if (Application.loadedLevelName == "dungeonScene") {
            if (itemSpawn[i].name == "key2" || itemSpawn[i].name == "teddyBearLW" || itemSpawn[i].name == "teddyBearLW_Admiration" || itemSpawn[i].name == "radio") 
                randomLocation = new Vector3(Random.Range(spawnBoxBot.x, -26.96f), Random.Range(spawnBoxBot.y, spawnBoxTop.y), Random.Range(spawnBoxBot.z, -2.141f));
            else 
                randomLocation = new Vector3(Random.Range(spawnBoxBot.x, spawnBoxTop.x), Random.Range(spawnBoxBot.y, spawnBoxTop.y), Random.Range(-2.374f, spawnBoxTop.z));                 
        }
        //Otherwise just spawn them in the box.
        else 
            randomLocation = new Vector3(Random.Range(spawnBoxBot.x, spawnBoxTop.x), Random.Range(spawnBoxBot.y, spawnBoxTop.y), Random.Range(spawnBoxBot.z, spawnBoxTop.z));   

        //Get a list of objects this item is hitting.
        Collider[] hit = Physics.OverlapSphere(randomLocation, maxRadius);

        //This is what actually spawns the item. If the space is clear, spawn the item. Otherwise we have to repeat the whole process again.            
        if (hit.Length < 1 || hit[0].name != "")
            spawnedItem = Instantiate(itemSpawn[i], randomLocation, Random.rotation);
        else
            i --;

        //If we spawned something, set it's name to what it's supposed to be. Removes the (clone) addon.
        if (spawnedItem != null)
            spawnedItem.name = itemSpawn[i].name;
    }
}`

I'm trying to figure out a way to randomly spawn items throughout my level, however I need to make sure they won't spawn inside another object (walls, etc.)

Here's the code I'm currently using (no longer using this, just keeping it for reference), it's based on the Physics.CheckSphere(); function. This runs OnLevelWasLoaded(); It spawns the items perfectly fine, but sometimes items spawn partway in walls. And sometimes items will spawn outside of the SpawnBox range (no clue why it does that.)

//This is what randomly generates all the items.
void SpawnItems () {
    if (Application.loadedLevelName == "Menu" || Application.loadedLevelName == "End Demo")
        return;

    //The bottom corner of the box we want to spawn items in.
    Vector3 spawnBoxBot = Vector3.zero;
    //Top corner.
    Vector3 spawnBoxTop = Vector3.zero;

    //If we're in the dungeon, set the box to the dungeon box and tell the items we want to spawn.
    if (Application.loadedLevelName == "dungeonScene") {
        spawnBoxBot = new Vector3 (8.857f, 0, 9.06f);
        spawnBoxTop = new Vector3 (-27.98f, 2.4f, -15);
        itemSpawn = dungeonSpawn;
    }

    //Spawn all the items.
    for (i = 0; i != itemSpawn.Length; i ++) {
        spawnedItem = null;
        //Zeroes out our random location
        Vector3 randomLocation = Vector3.zero;
        //Gets the meshfilter of the item we'll be spawning
        MeshFilter mf = itemSpawn[i].GetComponent<MeshFilter>();
        //Gets it's bounds (see how big it is)
        Bounds bounds = mf.sharedMesh.bounds;
        //Get it's radius
        float maxRadius = new Vector3 (bounds.extents.x + 10f, bounds.extents.y + 10f, bounds.extents.z + 10f).magnitude * 5f;
        //Set which layer is the no walls layer
        var NoWallsLayer =  1 << LayerMask.NameToLayer("NoWallsLayer");
        //Use that layer as your layermask.
        LayerMask layerMask = ~(1 << NoWallsLayer);

        //If we're in the dungeon, certain items need to spawn on certain halves.
        if (Application.loadedLevelName == "dungeonScene") {
            if (itemSpawn[i].name == "key2" || itemSpawn[i].name == "teddyBearLW" || itemSpawn[i].name == "teddyBearLW_Admiration" || itemSpawn[i].name == "radio") 
                randomLocation = new Vector3(Random.Range(spawnBoxBot.x, -26.96f), Random.Range(spawnBoxBot.y, spawnBoxTop.y), Random.Range(spawnBoxBot.z, -2.141f));
            else 
                randomLocation = new Vector3(Random.Range(spawnBoxBot.x, spawnBoxTop.x), Random.Range(spawnBoxBot.y, spawnBoxTop.y), Random.Range(-2.374f, spawnBoxTop.z));                 
        }
        //Otherwise just spawn them in the box.
        else 
            randomLocation = new Vector3(Random.Range(spawnBoxBot.x, spawnBoxTop.x), Random.Range(spawnBoxBot.y, spawnBoxTop.y), Random.Range(spawnBoxBot.z, spawnBoxTop.z));   

        //This is what actually spawns the item. It checks to see if the spot where we want to instantiate it is clear, and if so it instatiates it. Otherwise we have to repeat the whole process again.
        if (Physics.CheckSphere(randomLocation, maxRadius, layerMask))
            spawnedItem = Instantiate(itemSpawn[i], randomLocation, Random.rotation);
        else
            i --;

        //If we spawned something, set it's name to what it's supposed to be. Removes the (clone) addon.
        if (spawnedItem != null)
            spawnedItem.name = itemSpawn[i].name;
    }
}

What I'm asking for is if you know what's going wrong with this code that it would spawn stuff in walls. Or, if you could provide me with links/code/ideas of a better way to check if an item will spawn in a wall (some other function than Physics.CheckSphere).

I've been working on this for a long time, and nothing I try seems to work. Any help is appreciated.

share|improve this question
    
Is manually placing spawn points that your tool finds and picks from out of the question? –  Tetrad Sep 5 '12 at 20:46
    
It would be a lot better if it were completely random. If worst came to worst though I could do that. –  Timothy Williams Sep 17 '12 at 23:19
    
If you don't devise some sort of systematic approach for this, you're gonna have a bad time. Have you considered thinking about it as a high-res grid? If there's a wall inside any grid cell, it's a no-fly zone. Adjust the grid resolution to control how tightly any given item can hug the wall. –  michael.bartnett Sep 18 '12 at 9:16
    
I need to do something like that. Obviously this code isn't working. I'm not sure what to do though. –  Timothy Williams Sep 19 '12 at 22:04

3 Answers 3

up vote 2 down vote accepted

Coming back to this much later, I completely forgot about this question.

The problem ended up being caused by the artist I was working with, he set the meshes on the items to nearly 100x the size they visually were. This meant when I was trying to spawn items with the script above they were colliding with EVERYTHING in the level. After fixing the meshes on the items the above script worked perfectly fine.

share|improve this answer

I am not sure how you have your level set up completely, but would you be able to check for just a collision against a tagged wall?

if (hit.Length < 1 || hit[0].tag != "wall")
        spawnedItem = Instantiate(itemSpawn[i], randomLocation, Random.rotation);

This might not be possible of course if your level mesh is set up as a single object. If you can tag the walls this may give you a quick and dirty way to do it.

However, a better way might be to create the grid that michael.barnett suggested.

share|improve this answer

One thing is that the CheckSphere will return true if it hits more than one thing as well, so it may hit the ground and a wall and will still return true. So this is possibly the reason your items sometimes spawn sticking out of the wall.

What you could try is once you hit something, do a few ray casts in each direction with the ray starting in the center of the object and the distance set to a little over half the width/length of the object to determine if any walls or objects are nearby.

This way can also help you tell if your item will be stuck somewhere inaccessible as well

It may not be the most efficient way but I've done similar before and it seemed to work pretty good and fast for my purposes.

share|improve this answer
    
I've switched my code a bit. It still doesn't work though, I'll try this method and see if I get anything. –  Timothy Williams Sep 17 '12 at 23:23

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.