- Home /
Trying to respawn prefabs after destroying them with a reset button
Hello All, I am a scripting newbie and I'm running into some serious problems. What I am doing is that at the start of the scene/level a grid of 9 prefab(Cubes) Instantiates. Also on the screen I have a "Reset" GUI button that is supposed to destroy all the prefabs(Cubes) and then respawn them. There needs to be a slight time delay between the time the cubes are destroyed from clicking the reset button to when the cubes respawn, so it the user can visually see it. I can't use Application.Loadlevel on the Reset button either, as the parameters of this project forbid me from doing such. I tried calling the function used to spawn the cubes in the script for the reset button, either its not working or since there is no time delay I can't see it happening. The following is my code:
Cube Spawning Script:
//the WoodCube Prefab assigned in the inspector
public var thePrefab:GameObject;
//the # of WoodCubes that will be spawned
public var numberOfCubes:int = 9;
//the ARRAY of spawnpoints that our cube will be spawned at
private var spawnPointList:GameObject[];
//array of which spawn points are currently available for spawning at
private var spawnIndexAvailableList:Array = [];
//variable to hold the total number of spawn points, saves having to recalculate
private var numberOfSpawnPoints:int;
function Awake()
{
//retrieve GameObject tagged as "SpawnPoint" within the "CubeSpawnPoints" GameObject which the script is a component of
spawnPointList = gameObject.FindGameObjectsWithTag("SpawnPoint");
//retreive # of spawn points
numberOfSpawnPoints = spawnPointList.length;
//make sure number of cubes doesn't exceed number of spawn points
if (numberOfCubes > numberOfSpawnPoints) numberOfCubes = numberOfSpawnPoints;
//make all spawn points available by setting each index to true
for (var i:int = 0; i < numberOfSpawnPoints; i++)
{
spawnIndexAvailableList[i] = true;
}
//spawn X amount of cubes according to numberOfCubes
for (var j:int = 0; j < numberOfCubes; j++ )
{
SpawnCube();
}
}
function SpawnCube()
{
//generate a random integer to use as the index to select a spawn point from the list
var randomSpawnIndex:int = Random.Range(0, numberOfSpawnPoints);
//while the selected spawn index is unavaiable regenerate another one
while (!spawnIndexAvailableList[randomSpawnIndex])
{
randomSpawnIndex = Random.Range(0, numberOfSpawnPoints);
}
//retrieve the pos and rot of the cube's spawn point
var spawnedCubePosition:Vector3 = spawnPointList[randomSpawnIndex].transform.position;
var spawnedCubeRotation:Quaternion = spawnPointList[randomSpawnIndex].transform.rotation;
//instantiate (create) the WoodCube prefab with the above position and rotation
var spawnedCube:GameObject = Instantiate(thePrefab, spawnedCubePosition, spawnedCubeRotation);
//set the spawned cube as a child of the "CubeSpawnPoints" gameObject that this a Component of
//this is so we can use SendMessageUpward within scripts attached to the WoodCube prefab to call functions within this script
spawnedCube.transform.parent = spawnPointList[randomSpawnIndex].transform;
//set the name of the cube as its index
spawnedCube.name = randomSpawnIndex.ToString();
//make the spawn index unavailable to prevent another cube being spawned in this position
spawnIndexAvailableList[randomSpawnIndex] = false;
}
Here is the Reset button script: //Includes both Back and Reset GUI Buttons var spawnpoint:GameObject;
function OnGUI()
{
//Back Button takes you back to Main Menu
if (GUI.Button(Rect(50,50,200,100),"Back"))
Application.LoadLevel("MainMenu");
//Reset Button destroys cube grid and reloads
if (GUI.Button(Rect(1430,50,200,100),"Reset"))
Destroy(spawnpoint);
GUI.color = Color.green;
GUI.Button(Rect(50,50,200,100),"Back");
GUI.Button(Rect(1430,50,200,100),"Reset");
}
var CubeController : CubeController;
function Update()
{
CubeController.Awake();
}
Obviously I'm writing in JavaScript as I'm not well versed in C# just yet. I'm really new at coding and pick things up fairly quickly, but I'm having a hard time doing this. Any help would be greatly appreciated. Thank you Community!
Awake() is meant to be called only once - when the script is being loaded - so you may want to rethink the structure of your code in regards to this.
As for your cubes see$$anonymous$$gly not disappearing, you have CubeController.Awake() in your Update function, which means it's being called once every frame - your cubes are constantly respawning. I'm not sure if the Destroy() function is working properly because I don't know what spawnpoint refers to.
Assu$$anonymous$$g your Destroy() is working, starting at line 15, try this:
yield WaitForSeconds (2);
CubeController.SpawnCube();
And of course remove CubeController.Awake() from Update().
Thanks for replying Quillicit. Not having the CubeController.Awake() in the Update() makes sense now, since you explained that. Calling on the SpawnCube() makes more sense. The destroy function is working perfectly, once I take that Awake Function out of the Update(). "spawnpoint' refers to the gameObjects that the cubes are spawning on. They are children to one GameObject.
After making your suggested corrections I encountered an error: "Script error (ResetBT): OnGUI() can not be a coroutine." I have no idea what that means. Any thoughts? Thanks a million. Little by little I'm understanding coding. Just not as advanced as I'd like to be.
Ah, right, WaitForSeconds is a coroutine, which can't be in the OnGUI. I use C# and WaitForSeconds has to be in an IEnumerator there, so the javascript kinda threw me off. Put those two lines of code into a separate function and call that function within the OnGUI. That should resolve the error.
Ok, well I did create a new function, like you said, and called it after Destroy(spawnpoint); However, I was greeted with another lovely error, lol. Here is my script for the reset function as it stands:
//Includes both Back and Reset GUI Buttons var spawnpoint:GameObject; var CubeController : CubeController; function OnGUI() { //Back Button takes you back to $$anonymous$$ain $$anonymous$$enu if (GUI.Button(Rect(50,50,200,100),"Back")) Application.LoadLevel("$$anonymous$$ain$$anonymous$$enu");
//Reset Button destroys cube grid and reloads
if (GUI.Button(Rect(1430,50,200,100),"Reset"))
Destroy(spawnpoint);
welcomeBackCubes();
GUI.color = Color.green;
GUI.Button(Rect(50,50,200,100),"Back");
GUI.Button(Rect(1430,50,200,100),"Reset");
}
function welcomeBackCubes() { if(Destroy(spawnpoint))
{
yield WaitForSeconds (2);
CubeController.SpawnCube();
}
}
The error i got was this: Assets/Scripts/ResetBT.js(26,19): BCE0026: 'void' cannot be used in a boolean context. I'm probably just brainfarting and the answer is easy, but do you know what to do here? Thanks!
You've already got the if parameter in your GUI, so you don't have to check in welcomeBackCubes whether or not you've destroyed them. Just put curly brackets around Destroy(spawnpoint) and welcomeBackCubes(). If one happens, the other happens.
The error is because Destroy(spawnpoint) is not a boolean, so the compiler can't evaluate the if statement in welcomeBackCubes().
Answer by Quillicit · Jan 17, 2014 at 10:01 AM
Alright, here's your CubeController:
#pragma strict
var theCube:GameObject; //Cube prefab
var cubesContainer:GameObject; //Cube container prefab
var spawnedCube:GameObject; //Individual spawned cube instantiated from theCube
var allCubes:GameObject; //Cube container instantiated from cubesContainer
var spawnPointPositionsList : Vector3[]; //Array of positions for cubes
var spawnPointRotationsList : Quaternion[]; //Array of rotations for cubes
var spawnIndexAvailableList : boolean[]; //Array of booleans to check for available spawn points
var numberOfCubes:int = 9;
var randomSpawnIndex:int;
function Start () {
spawnPointPositionsList = new Vector3[numberOfCubes]; //Initialize array of cube positions
spawnPointRotationsList = new Quaternion[numberOfCubes]; //Initialize array of cube rotations
spawnIndexAvailableList = new boolean[numberOfCubes]; //Initialize array of booleans
PopulateSpawnPointList (); //Assign spawn point values to arrays
SpawnAllCubes (); //Spawns initial set of cubes
}
function SpawnAllCubes(){
allCubes = Instantiate (cubesContainer, cubesContainer.transform.position, cubesContainer.transform.rotation) as GameObject;
allCubes.name = "allCubes";
for (var i = 0; i < numberOfCubes; i++)
{
spawnIndexAvailableList[i] = true;
}
for (var j:int = 0; j < numberOfCubes; j++ )
{
SpawnCube();
}
}
function SpawnCube(){
randomSpawnIndex = Random.Range(0, numberOfCubes);
while (!spawnIndexAvailableList[randomSpawnIndex])
{
randomSpawnIndex = Random.Range(0, numberOfCubes);
}
spawnedCube = Instantiate (theCube, spawnPointPositionsList[randomSpawnIndex], spawnPointRotationsList[randomSpawnIndex]) as GameObject;
spawnedCube.transform.parent = null;
spawnedCube.transform.parent = allCubes.transform; //Make spawnedCube a child of allCubes, so destroying allCubes destroys all spawned cubes
spawnedCube.name = "cube" + randomSpawnIndex.ToString();
spawnIndexAvailableList[randomSpawnIndex] = false;
}
function PopulateSpawnPointList(){
for (var n = 0; n < numberOfCubes; n++) {
var spawnPosX = n*10;
var spawnPosZ = n*10;
spawnPointPositionsList[n] = new Vector3(spawnPosX, 0, spawnPosZ);
var spawnRotX = 0;
var spawnRotY = 0;
var spawnRotZ = 0;
spawnPointRotationsList[n] = Quaternion.Euler(spawnRotX, spawnRotY, spawnRotZ);
}
}
And here's your Reset:
#pragma strict
function OnGUI(){
GUI.color = Color.green;
if (GUI.Button(Rect(100,50,200,100),"Reset"))
{
Destroy(GameObject.Find("allCubes"));
welcomeBackCubes();
}
}
function welcomeBackCubes()
{
yield WaitForSeconds (2);
GameObject.Find("Main Camera").SendMessage("SpawnAllCubes"); //"Main Camera" is whatever GameObject the CubeController script is attached to
}
First off, I just want to say that you are a rockstar for writing this code out for me. There is one problem though. When I hook up all the objects with the script, etc and run it, Unity freezes/crashes. I know that this usually happens when you have a Loop that is never ending. I'm gonna look to see what may be causing it. Once again, You are a rockstar! If you have any thoughts, let me know. Otherwise, I'll post a message when I figure out what the problem is.
I have no idea how this happened, but we lost a line of code. At line 24 of the CubeController we should have this:
allCubes.name = "allCubes";
Good god do I hope we're done now.
Hmmmm....I added that line as well, but it still crashed my friend. I'm guessing that it is one of the loops (While?) that is doing it since I have had that happen to me in the past. Just an FYI, When the scene loads up there are no cubes on the screen, which means, either they are not spawning before the crash happens or they are not at all. I'm going to look at the code, maybe put some Debug lines in to see what is getting executed before the crash. You have been a great help thus far, I really appreciate it.
$$anonymous$$ake sure you drop a cube prefab in for theCube and an empty game object prefab for cubesContainer. Also, make sure the name in line 15 of the Reset script is the same as the object you have the CubeController script attached to (in place of "$$anonymous$$ain Camera").
Thanks friend, that did the trick! I appreciate it. If I could give a thumbs up I would.
Your answer
Follow this Question
Related Questions
Is there a way to reset prefabs to script variables in code? 1 Answer
Respawning Navmesh and Prefabs 0 Answers
Spawn a Prefab when it is destroyed 3 Answers
Re-setting scenario after respawn 2 Answers
Show prefabs instantiated at Start() in the editor? 2 Answers