This is my spawning script belowwritten in c# The script should create objects randomly in the scene.
The issue is that I'm getting this error at runtime.
IndexOutOfRangeException: Array index is out of range.
CreateEasterEggs.MakeThingToSpawn () (at Assets/CreateEasterEggs.cs:52)
CreateEasterEggs.Update () (at Assets/CreateEasterEggs.cs:28)
Not sure what I have done wrong, thinking its something to do with the game object?
Thank you.
using UnityEngine;
using System.Collections;
public class CreateEasterEggs : MonoBehaviour
{
public float secondsBetweenSpawning = 0.1f;
public float xMinRange = -25.0f;
public float xMaxRange = 25.0f;
public float yMinRange = -5.0f;
public float yMaxRange = 0.0f;
public float zMinRange = -25.0f;
public float zMaxRange = 25.0f;
public GameObject[] spawnObjects; // what prefabs to spawn
private float nextSpawnTime;
void Start ()
{
// determine when to spawn the next object
nextSpawnTime = Time.time+secondsBetweenSpawning;
}
void Update ()
{
// if time to spawn a new game object
if (Time.time >= nextSpawnTime) {
// Spawn the game object through function below
MakeThingToSpawn ();
// determine the next time to spawn the object
nextSpawnTime = Time.time+secondsBetweenSpawning;
}
}
void MakeThingToSpawn ()
{
//Start the vector at an invalid position
Vector3 spawnPosition = new Vector3(0, 0, 0);
//while we are not in the right range, continually regenerate the position
while ((spawnPosition.z < 4 && spawnPosition.z > -4) || (spawnPosition.x < 4 && spawnPosition.x > -4))
{
spawnPosition.x = Random.Range (xMinRange, xMaxRange);
spawnPosition.y = Random.Range (yMinRange, yMaxRange);
spawnPosition.z = Random.Range (zMinRange, zMaxRange);
}
// determine which object to spawn
int objectToSpawn = Random.Range (0, spawnObjects.Length);
// actually spawn the game object
GameObject spawnedObject = Instantiate (spawnObjects [objectToSpawn], spawnPosition, transform.rotation) as GameObject;
// make the parent the spawner so hierarchy doesn't get super messy
spawnedObject.transform.parent = gameObject.transform;
}
}
IndexOutOfRange means that you tried to access to an element of an array that doesn't exist.
In your case as you are doing it with Random.Range (0, spawnObjects.Length); Then the only possible case is that your array is empty.
Try to Debug.Log(spawnObjects.Length): before the Instantiate and you will see that in fact your array of gameobjects is empty as It will return 0.
Related
Hi all I am developing an endless runner game and need help on solving an issue. My version of the endless runner is where the player moves along the z-axis while tiles spawning in-front of the player. The tiles have 3 lanes. So my issue is this. I have this spawning script which I got from researching the net and ran into the issue the script is written where the tiles moving under the player rather than player running forward. I tried to convert it so that that objects are spawned in front of the player (z-axis) but I didn't quite achieve what I intended for.
So my errors are,
objects (obstacles) are spawning behind the player and eventually stops
objects are spawned only in one lane.
So how do I how do I rectify above errors?
Here's my script.
public class Spawner : MonoBehaviour {
[Space(10)]
[Header("Obstacles:")]
public float objectSpawnWait;
public Vector3 randPos1;
public Vector3 randPos2;
public Vector3 randPos3;
public float spawnZ; //distance between player and the object
public float spawnDistance; //distance between object
public GameObject[] obstacles;
private Transform playerTranform;
void Start()
{
playerTranform = GameObject.FindGameObjectWithTag("Player").transform;
}
void Update()
{
if(playerTranform.position.z > spawnZ * spawnDistance)
{
StartCoroutine(SpawnObstacle());
}
}
IEnumerator SpawnObstacle()
{
if (obstacles.Length > 0)
{
int randomObstacle = Random.Range(0, obstacles.Length);
GameObject obstacle = Instantiate(obstacles[randomObstacle]);
obstacle.transform.SetParent(transform);
MoveObjectsToTheFront(obstacle);
}
yield return new WaitForSeconds(5);
}
private void MoveObjectsToTheFront(GameObject moveObject)
{
int randomPosNum = Random.Range(0, 2);
Vector3 randomPosition;
if (randomPosNum == 0)
randomPosition = randPos1; // Vector3(2, 0.5, 5)
else if (randomPosNum == 1)
randomPosition = randPos2; // Vector3(0, 0.5, 5)
else
randomPosition = randPos3; // Vector3(-2, 0.5, 5)
moveObject.transform.position = randomPosition * spawnZ;
spawnZ += spawnDistance;
}
}
Any help would be greatly appreciated. Thanks.
I am making an object spawn script in which on the start of the script the spawning function is called and in it is a for loop which creates an object each iteration. It first picks a random X position for it and then checks if it is in a range of another prefabs coordinates so they don't spawn too close or worse, one in each other. If it is in the same coordinates as another prefab it will return 0 and this same goes out for the Z axis too. It also picks a random Y axis rotation so it doesn't all face the same direction. After this it spawns the prefab and sets it's coordinates and rotation after which it check if the coordinates in the X or Z axis are 0, and if any of those two are 0 it goes back one iteration and the last object to be spawned is destroyed so it doesn't flood. This works perfectly but when you want to set it to spawn too much objects it floods the RAM because there is nowhere to spawn more objects. I tried finding the highest X position and highest Z position and multiplying them, and setting them both to positive, and then dividing them by the space between the prefabs but this doesn't work as it sets it to a really really high number. How would you fix this?
Script:
using UnityEngine;
using System.Collections;
public class PrefabSpawner : MonoBehaviour {
public int amountOfPrefabs;
public int maxAmountOfPrefabs;
private int currentSpawnedPrefab;
public float spaceBetweenPrefabs;
private float positionX;
private float positionZ;
private float maxPositionX;
private float maxPositionZ;
private float multipliedPosXZ;
private bool previousSpawnHadZero;
public GameObject prefab;
private GameObject point1;
private GameObject point2;
private GameObject currentSpawn;
private Vector2[] positions;
void Start () {
currentSpawnedPrefab = 0;
previousSpawnHadZero = false;
point1 = gameObject.transform.GetChild (0).gameObject;
point2 = gameObject.transform.GetChild (1).gameObject;
if (point1.transform.position.x > point2.transform.position.x)
maxPositionX = point1.transform.position.x;
else
maxPositionX = point2.transform.position.x;
if (point1.transform.position.z > point2.transform.position.z)
maxPositionZ = point1.transform.position.z;
else
maxPositionZ = point2.transform.position.z;
multipliedPosXZ = maxPositionX * maxPositionZ;
if (multipliedPosXZ < 0)
multipliedPosXZ += multipliedPosXZ + multipliedPosXZ;
maxAmountOfPrefabs = Mathf.FloorToInt (multipliedPosXZ / spaceBetweenPrefabs);
if (amountOfPrefabs > maxAmountOfPrefabs)
amountOfPrefabs = maxAmountOfPrefabs;
point1.GetComponent<MeshRenderer> ().enabled = false;
point2.GetComponent<MeshRenderer> ().enabled = false;
gameObject.GetComponent<MeshRenderer> ().enabled = false;
positions = new Vector2[amountOfPrefabs];
SpawnPrefabs (amountOfPrefabs);
}
void SpawnPrefabs (int amount) {
for (int i = 0; i < amount; i++) {
if(previousSpawnHadZero)
i -= 1;
currentSpawn = (GameObject)Instantiate (prefab);
positionX = GetRandomPositionX ();
positionZ = GetRandomPositionZ ();
currentSpawn.transform.position = new Vector3 (positionX, this.transform.position.y + currentSpawn.transform.localScale.y, positionZ);
currentSpawnedPrefab += 1;
if (positionX == 0 || positionZ == 0) {
previousSpawnHadZero = true;
currentSpawnedPrefab -= 1;
Destroy (currentSpawn);
}
if (positionX != 0 && positionZ != 0) {
previousSpawnHadZero = false;
positionX = 0;
positionZ = 0;
}
}
}
IEnumerator Pause () {
yield return null;
}
float GetRandomPositionX () {
//Finds a random position for the X axis and then checks it and returns either 0 if the position is taken or the position if not
}
float GetRandomPositionZ () {
//Finds a random position for the Z axis and then checks it and returns either 0 if the position is taken or the position if not
}
bool CheckPositionAvailable (float pos, int axis) {
//Checks if the position is available.
}
}
Code is really long to debug but the problem is clearly visible and is from the SpawnPrefabs function. Currently, when you instantiate a prefab, you check if the generated position is 0. If 0, you subtract 1 from the i in the for loop then destroy the instantiated object and then start the for loop again from the current loop-1.
So the combination of Instantiate, Destroy and repeating it over again in the for loop is causing the memory issue.
What to do:
You have to re-write the whole function and this will require modification in your whole code too. Do not instantiate and destroy object in that loop unless when needed.
1.In the Start() function, create one prefab.
2.Make it to be invisible in the scene by disabling its mesh/sprite renderer.
3.Use that prefab in the for loop to check if the generated position is valid. If it is valid, you can now create/instantiate an object in the loop.
This prevents instantiating and destroying objects in the loop when you only create objects when if (positionX != 0 && positionZ != 0) .
I am trying to spawn some GameObjects in game based on the current player position, essentially trying to make an infinite runner type of game...I made a function so I can spawn the pylons with it but for some reason the function gets called only once per frame, It does not get called the second time with a different parameter.
Why does the second call of the function not work?
This is my code:
public class CameraScript : MonoBehaviour {
public float cameraSpeed = 1;
public float horizontalSpeed;
private int spawnIndex;
public float spawnNormPylonDis;
public float spawnCoinPylonDis;
private int currPosition ;
public GameObject[] pilons;
public GameObject spawnMainPoint;
public Transform[] spawnPoints;
public Transform[] coinsSpawnPoint;
public float enamySpeed;
private int currentPoint;
public Transform[] pointPosition;
// Use this for initialization
void Start () {
//This spawns the Pilons.
spawnMainPoint.transform.position = pointPosition [0].position;
currPosition = (int) transform.position.z;
}
// Update is called once per frame
void FixedUpdate () {
spawnMainPoint.transform.position = Vector3.MoveTowards (spawnMainPoint.transform.position, pointPosition[currentPoint].position, Time.deltaTime * horizontalSpeed);
SpawnPylon (pilons[1],spawnPoints,spawnNormPylonDis,"Check function");
SpawnPylon (pilons [0], spawnPoints, spawnCoinPylonDis,"Check the second function");
GetComponent<Rigidbody> ().velocity = transform.forward * cameraSpeed;
//the next if statements make the Pilons spawn randomly and corectly.
if (spawnMainPoint.transform.position == pointPosition [currentPoint].position) {
currentPoint++;
}
if (currentPoint == pointPosition.Length) {
currentPoint = 0;
}
}
/*This function spanws the a GameObject randomly at a GameObject's position and it takes 2 arguments :
Argument 1: type GameObject
2: type Transform[]*/
void SpawnPylon (GameObject whatSpawn,Transform[] whereSpawn,float spawnDistance,string plm)
{
bool hasSpawnedPylon = false;
if (currPosition != (int)transform.position.z)
{
if ((int)transform.position.z % spawnDistance == 0)
{
Debug.Log (plm);
if (!hasSpawnedPylon)
{
//this makes the GameObject spawn randomly
spawnIndex = Random.Range (0, spawnPoints.Length);
//This is instantiationg the GameObject
Instantiate (whatSpawn, whereSpawn [spawnIndex].position, whereSpawn [spawnIndex].rotation);
//this makes shore that the GameObject is not spawned multiple times at aproximetley the same position.
currPosition = (int)transform.position.z;
}
}
}
else
{
hasSpawnedPylon = false;
}
}
}
Here I have a picture with the script in the inspector:
Script Inspector
And here is the console, trying to figure it out by using Debug.Log () for the calls of the function.
Using Debug.Log for the calls.
I tested it and it works fine under some conditions. The problem most likely is that your spawnNormPylonDis and spawnCoinPylonDis are public variables that are the same in the inspector, or spawnNormPylonDis is a multiple of spawnCoinPylonDis, pretty much with your code, you cannot have spawnNormPylonDis be 1. If they are then in the SpawnPylon function because it has already spawned one. You yourself commented.
//this makes shore that the GameObject is not spawned multiple times at aproximetley the same position.
currPosition = (int)transform.position.z;
I tested this with values of 2 and 3 and both functions got called, however, it would skip the second function if they were both divisible (6).
Therefore you got bottlenecked at this line of code because you set the currPosition after the first function call.
if (currPosition != (int)transform.position.z)
By making a basic wrapper function all is well in the world! So we set the currPosition after we checked both spawning calls, and voila, problem solved.
void SpawnPylon(int index, Transform[] spawnPoint, float dist, string debug)
{
if ((int)transform.position.z % dist == 0)
{
//Debug.Log(debug);
//this makes the GameObject spawn randomly
spawnIndex = Random.Range(0, spawnPoints.Length);
//This is instantiationg the GameObject
GameObject go = Instantiate(pilons[index], spawnPoint[spawnIndex].position, spawnPoint[spawnIndex].rotation) as GameObject;
go.name = string.Format("ID: {0}", index);
}
}
private void SpawnMultiplePylons()
{
if (currPosition != (int)transform.position.z)
{
SpawnPylon(1, spawnPoints, spawnNormPylonDis, "Spawn1");
SpawnPylon(0, spawnPoints, spawnCoinPylonDis, "Spawn2");
currPosition = (int)transform.position.z;
}
}
I tested this and it worked. I hope that it also works for you!
I'm having some trouble spawning a random asteroid from an array within a for loop.
The array is working now, however (I assume this is in the for loop somewhere) it wont alternate between the different game objects. whichever object spawns first, spawns every time, but each time you load the game it spawns a different one every time.
How do I get it to chose a new random object from the array after every spawn instance?
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour {
public GameObject[] asteroids;
public Vector3 spawnValues;
public int asteroidCount;
public float spawnWait;
public float startWait;
public float waveWait;
void Start () {
StartCoroutine (spawnWaves ());
}
IEnumerator spawnWaves () {
GameObject asteroid = asteroids[Random.Range(0, asteroids.Length)];
while (asteroidCount > 0) {
for (int i = 0; i < asteroidCount; i++) {
Vector3 spawnPosition = new Vector3 (spawnValues.x, Random.Range (-spawnValues.y, spawnValues.y), spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
Instantiate (asteroid, spawnPosition, spawnRotation);
yield return new WaitForSeconds (spawnWait);
}
}
}
}
you select the object to spawn outside the loop
GameObject asteroid = asteroids[Random.Range(0, asteroids.Length)];
needs to be here
while (asteroidCount > 0) {
for (int i = 0; i < asteroidCount; i++) {
GameObject asteroid = asteroids[Random.Range(0, asteroids.Length)];
I'm using this code to spawn a random object from an array:
using UnityEngine;
using System.Collections;
public class enemySpawner : MonoBehaviour {
public GameObject[] enemies;
int enemyNo;
public float maxPos = 6.9f;
public float delayTimer = 0.75f;
float timer;
void Start () {
timer = delayTimer;
}
void Update () {
timer -= Time.deltaTime;
if (timer <= 0) {
Vector3 enemyPos = new Vector3 (transform.position.x, Random.Range (5.0f, -5.5f), transform.position.z);
//enemyNo = Random.Range (0,8);
enemyNo = Random.Range (0, enemies.Length);
Instantiate (enemies[enemyNo], enemyPos, transform.rotation);
timer = delayTimer;
}
}
}
The problem is I want to do the same thing across different scenes. Each scene has a different amount of objects for the array (set in the inspector), so because they're not all the same I'm getting this error:
IndexOutOfRangeException: Array index is out of range.
Is there any way for me to do this differently? Or should I write a new script for each scene?
You need to get the current length of the array, so you can't get out of the current array range.
enemyNo = Random.Range (0, enemies.Length)