I've tried a lot of different things. Assigning the array elements just in the editor. Assigning the elements on boot using the Await(). Changing what script calls the functions. What GameObject has the attached script. How the Vector2 is called. How the array is initialized. I can't figure out what I'm missing.
GameRules Script
using System.Collections.Generic;
using UnityEngine;
public class GameRules : MonoBehaviour
{
public GameObject[] rightSwitchSpawns = new GameObject[7];
public GameObject[] leftSwitchSpawns = new GameObject[7];
public GameObject rightSwitchPrefab;
public GameObject leftSwitchPrefab;
void Awake(){
rightSwitchSpawns = GameObject.FindGameObjectsWithTag("RightSpawns");
leftSwitchSpawns = GameObject.FindGameObjectsWithTag("LeftSpawns");
}
// Start is called before the first frame update
void Start()
{
RandomLeft();
RandomRight();
}
public void RandomLeft()
{ Debug.Log("This Left array length is " leftSwitchSpawns.Length);
int leftRandom1 = Random.Range(0, leftSwitchSpawns.Length -1);
Debug.Log("left 1 index is " leftRandom1);
Vector2 leftOne = new Vector2(leftSwitchSpawns[leftRandom1].transform.position.x,leftSwitchSpawns[leftRandom1].transform.position.y);
leftSwitchPrefab = Instantiate(leftSwitchPrefab, new Vector2(leftOne.x,leftOne.y), Quaternion.identity);
int leftRandom2 = Random.Range(0, leftSwitchSpawns.Length -1);
while(leftRandom2 == leftRandom1)
{
leftRandom2 = Random.Range(0, leftSwitchSpawns.Length -1);
}
Vector2 leftTwo = new Vector2(leftSwitchSpawns[leftRandom2].transform.position.x,leftSwitchSpawns[leftRandom2].transform.position.y);
leftSwitchPrefab = Instantiate(leftSwitchPrefab, new Vector2(leftTwo.x,leftTwo.y), Quaternion.identity);
Debug.Log("Left 2 index is: " leftRandom2);
int leftRandom3 = Random.Range(0, leftSwitchSpawns.Length -1);
while(leftRandom3 == leftRandom1 || leftRandom3 == leftRandom2)
{
leftRandom3 = Random.Range(0, leftSwitchSpawns.Length -1);
}
Vector2 leftThree = new Vector2(leftSwitchSpawns[leftRandom3].transform.position.x,leftSwitchSpawns[leftRandom3].transform.position.y);
leftSwitchPrefab = Instantiate(leftSwitchPrefab, new Vector2(leftThree.x,leftThree.y), Quaternion.identity);
Debug.Log("Left 3 index is: " leftRandom3);
}
public void RandomRight()
{
int rightRandom1 = Random.Range(0, rightSwitchSpawns.Length -1);
Debug.Log("This Right array length is " rightSwitchSpawns.Length);
Vector2 rightOne = rightSwitchSpawns[rightRandom1].transform.position;
rightSwitchPrefab = Instantiate(rightSwitchPrefab, new Vector2(rightOne.x,rightOne.y), Quaternion.identity);
Debug.Log("Right 1 index is: " rightRandom1);
int rightRandom2 = Random.Range(0, rightSwitchSpawns.Length -1);
while (rightRandom2 == rightRandom1)
{
rightRandom2 = Random.Range(0, rightSwitchSpawns.Length -1);
}
Vector2 rightTwo = rightSwitchSpawns[rightRandom2].transform.position;
rightSwitchPrefab = Instantiate(rightSwitchPrefab, new Vector2(rightTwo.x,rightTwo.y), Quaternion.identity);
Debug.Log("Right 2 index is: " rightRandom2);
int rightRandom3 = Random.Range(0, rightSwitchSpawns.Length -1);
while (rightRandom3 == rightRandom1 || rightRandom3 == rightRandom2)
{
rightRandom3 = Random.Range(0, rightSwitchSpawns.Length -1);
}
Vector2 rightThree = rightSwitchSpawns[rightRandom3].transform.position;
rightSwitchPrefab = Instantiate(rightSwitchPrefab, new Vector2(rightThree.x,rightThree.y), Quaternion.identity);
Debug.Log("Right 3 index is: " rightRandom3);
}
public void DestroyRightSwitches(){
Debug.Log("Right Switches Destroyed");
Destroy(rightSwitchPrefab);
}
public void DestroyLeftSwitches(){
Debug.Log("Left Switches Destroyed");
Destroy(leftSwitchPrefab);
}
}
PlayerMovement Script
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : GameRules
{
private float speed = 5f;
private float jump = 5f;
private Rigidbody2D rb;
private bool isPlaying = false;
private Transform trans;
// Start is called before the first frame update
void Awake()
{
trans = gameObject.GetComponent<Transform>();
rb = gameObject.GetComponent<Rigidbody2D>();
rb.simulated = false;
}
// Update is called once per frame
void Update()
{
if(Input.GetMouseButtonDown(0)){
if(isPlaying == false){
isPlaying = true;
rb.simulated = true;
rb.velocity = new Vector2(speed,0f);
}
else{
rb.velocity = new Vector2(speed,jump);
}
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Wall")
{
OnDeath();
}
if(collision.gameObject.tag == "RightSwitch"){
speed = -speed;
rb.velocity = new Vector2(speed,0f);
DestroyRightSwitches();
RandomRight();
}
if(collision.gameObject.tag == "LeftSwitch"){
speed = -speed;
rb.velocity = new Vector2(speed,0f);
DestroyLeftSwitches();
RandomLeft();
}
}
void OnDeath(){
isPlaying = false;
rb.simulated = false;
trans.position = new Vector2(0,0);
DestroyLeftSwitches();
DestroyRightSwitches();
RandomLeft();
RandomRight();
}
}
The specific error is
IndexOutOfRangeException: Index was outside the bounds of the array. GameRules.RandomLeft () (at Assets/Scripts/GameRules.cs:28) GameRules.Start () (at Assets/Scripts/GameRules.cs:20)
But if you look at the debug statements. At initial runtime the array is full with a length of 7, Gives you the indexes of each point. and then it runs again for some reason with a length and index of 0. Then the error shows up.
The errors I Get in picture form
CodePudding user response:
Your arrays are declared as public
. In Unity3d's MonoBehaviour
it means that these fields are serialized. If you have this script attached to the game object on the scene or to some prefab that is instantiated after, serialized values will be taken from this game object (you can see it in the inspector). It means that if there will be empty arrays in the serialized object, the length of your arrays will be 0 at runtime.
CodePudding user response:
The issue is that I have the Playermovement script deriving from my GameRules script so in the hierarchy the player movement script also has empty arrays attached to the game object.