- Home /
How to randomly generate pickups
This is driving me crazy. I'm trying to convert UnityScript to C# for a tutorial I'm working on. I got pretty far until I had to do arrays - something I haven't been good at since I started programming. I keep getting an error and don't know how to fix it. Here's my code:
using UnityEngine;
using System.Collections;
public class PickupController : MonoBehaviour
{
//the pickup prefab assigned via the Inspector
public GameObject pickupPrefab;
private GameObject spawnedPickup;
//the number of pickups to have around the level at any one time
public int numberOfPickups = 2;
// the ARRAY of spawnpoints that our pickup will be spawned at
private GameObject[] spawnPointList;
// array of which spawn points are currently available for spawning at
private ArrayList spawnIndexAvailableList;
// variable to hold the total number of spawn points, saves having to recalculate
private int numberOfSpawnPoints;
void Awake()
{
// retrieve GameObjects tagged as 'SpawnPoint' within the 'PickupSpawnPoints' GameObject which this script is a Component of
spawnPointList = GameObject.FindGameObjectsWithTag("SpawnPoint");
// retreive number of spawn points
numberOfSpawnPoints = spawnPointList.length;
// make sure number of pickups doesn't exceed number of spawn points
if (numberOfPickups > numberOfSpawnPoints) numberOfPickups = numberOfSpawnPoints;
// make all spawn points available by setting each index to true
for (int i = 0; i < numberOfSpawnPoints; i++)
{
spawnIndexAvailableList[i] = true;
}
// spawn X amount of pickups according to numberOfPickups
for (int j = 0; j < numberOfPickups; j++)
{
SpawnPickup();
}
}
void SpawnPickup()
{
// generate a random integer to use as the index to select a spawn point from the list
int randomSpawnIndex = Random.Range(0, numberOfSpawnPoints);
// while the selected spawn index is unavailable regenerate another one
while (!spawnIndexAvailableList[randomSpawnIndex])
{
randomSpawnIndex = Random.Range(0, numberOfSpawnPoints);
}
// retrieve the position and rotation of the pickups spawn point
Vector3 spawnedPickupPosition = spawnPointList[randomSpawnIndex].transform.position;
Quaternion spawnedPickupRotation = spawnPointList[randomSpawnIndex].transform.rotation;
// instantiate (create) the pickup prefab with the above position and rotation
spawnedPickup = Instantiate(pickupPrefab, spawnedPickupPosition, spawnedPickupRotation)as GameObject;
// set the spawned pickup as a child of the 'PickupSpawnPoints' gameobject that this script is a Component of
// this is so we can use SendMessageUpwards within scripts attached to the pickupPrefab to call functions within this script
spawnedPickup.transform.parent = spawnPointList[randomSpawnIndex].transform;
// set the name of the pickup as its index
spawnedPickup.name = randomSpawnIndex.ToString();
// make the spawn index unavailable to prevent another pickup being spawned in this position
spawnIndexAvailableList[randomSpawnIndex] = false;
}
}
This is what I have up to this point in the tutorial. Hopefully once I get the arrays fixed I can get the rest of the tutorial done tonight. Any suggestions?
Answer by supernat · Sep 16, 2013 at 01:21 AM
private ArrayList spawnIndexAvailableList;
You need to initialize the ArrayList before you can use it. Everything that is not a native type (int, float, bool, etc) must be constructed in C# (technically I think native types are as well, but the compiler handles that for you...I think):
private ArrayList spawnIndexAvailableList = new ArrayList();
ArrayList also needs to have items added to it using spawnIndexAvailableList.Add() if you construct it empty. If you know the size of the ArrayList ahead of time, you can create it as follows (I'm trying to tie it into your code):
ArrayList spawnIndexAvailableList = new ArrayList(numberOfSpawnPoints);
This code line would go in your Awake() method right after you set numberOfSpawnPoints.
Okay! Great! That definitely cleared a few of my errors. The final error I'm getting says "The !' operator cannot be applied to operand of type object'" for my while statement in SpawnPickup(). I thought that is how you were supposed to set up a while statement to randomly generate the prefab. I'm guessing I'm missing something in my syntax?
I may be wrong on this, but the compiler is probably trying to deter$$anonymous$$e the type of the element based on how your code is structured. So if you say "spawnIndexAvailableList[x] = true", it knows it is a boolean, but (!...) I guess can be used for non-bool types. Try "while (spawnIndexAvailableList[x] == false)" ins$$anonymous$$d. It could also be some quirky operator order of precedence issue, so "while (!(spawnIndexAvailableList[x]))" may also solve the problem.
I tried "while (spawnIndexAvailableList[x] == false)" and I now get the error: "Operator ==' cannot be applied to operands of type object' and bool'" Using "while (!(spawnIndexAvailableList[x]))", I get the error: "The !' operator cannot be applied to operand of type `object'" like before.
I'm wondering if there is a better way to write this that doesn't use the while loop but I really can't think of anything at the moment. $$anonymous$$aybe I just need to walk away for a little bit.
Thanks for you help though supernat! I appreciate! :)
Thanks for Josh's clarification in his answer on this one. I haven't really worked with ArrayList much. It would probably make more sense to replace the ArrayList with just a simple boolean array. You aren't really using ArrayList's full potential of storing different types and having dynamic insertion and removal features.
private bool[] spawnIndexAvailableList;
...
// ...down in your Awake method...
// retreive number of spawn points
numberOfSpawnPoints = spawnPointList.Length;
spawnIndexAvailableList = new bool[numberOfSpawnPoints];
Now, you don't need to cast anything, because you're working with a native array. The only obvious thing is you can't easily remove or insert new items into the array like you can with an ArrayList, so you need to consider that.
Well I tried the above method and now I'm getting a new error: "Assets/Scripts/PickupController.cs(28,54): error CS1061: Type UnityEngine.GameObject[]' does not contain a definition for length' and no extension method length' of type UnityEngine.GameObject[]' could be found (are you missing a using directive or an assembly reference?)"
Don't even know what to do with this. Any suggestions?
Answer by josh-horsley · Sep 16, 2013 at 09:31 PM
With an ArrayList, it only knows that it's holding objects but doesn't know exactly what it's holding. If your spawnIndexAvailableList will only ever contain a list of boolean values, try explicitly casting to a bool in your while loop. Something like this:
// while the selected spawn index is unavailable regenerate another one
while (!(bool)spawnIndexAvailableList[randomSpawnIndex])
{
randomSpawnIndex = Random.Range(0, numberOfSpawnPoints);
}
That helped greatly! Thank you! Now I'm getting a warning for my number of spawnpoints: "Assets/Scripts/PickupController.cs(21,21): warning CS0649: Field PickupController.numberOfSpawnPoints' is never assigned to, and will always have its default value 0'"
When I run the game now I don't see any of my pickup models. I have the spawnpoints placed right in front of the player so they would show in the camera view.
Does this have to do with numberOfSpawnPoints not being initialized at start?
Hmm...I copied your code and opened it in $$anonymous$$onoDevelop. The only thing I saw with a warning was the ArrayList, spawnIndexAvailableList, which I think supernat already helped with. I would compare your current code with what you have posted here, because numberOfSpawnPoints looks fine from what I see.
Answer by YoungDeveloper · Sep 18, 2013 at 11:03 AM
Check out this topic, maybe it will be helpful. http://answers.unity3d.com/questions/534933/random-spawn-random-prefab.html
Thanks! I'll take a look and see where it takes me. I think I may have to start over from scratch and see where the problem lies.
Your answer