Strange Unity Error: "IndexOutOfRangeException: Array index is out of range"

    public Sprite[] Preview1;
     .
     .
     .
    void PreviewLetter()
      {
        print("Preview1 Length: "+Preview1.Length);
        if (Line == 1) Preview.sprite = Preview1[Loc1];
        if (Line == 2) Preview.sprite = Preview2[Loc1];
        if (Line == 3) Preview.sprite = Preview3[Loc1];
        if (Line == 4) Preview.sprite = Preview4[Loc1];
      }

I’ve initialized Preview1 in the inspector, and it contains 75 objects. When I first access the PreviewLetter function, I get Preview1.Length = 0 … which is, I’m assuming, generating the error. However: The function actually works, and prints a second line. Here’s what my console looks like:

I have absolutely NO IDEA why the zero length is showing up at all; the variable isn’t changed anywhere in the code, and the function continues to work, despite the error. I’d like to eliminate the error. Anyone have any clues??

It looks like you’re trying to access an object in an array that doesn’t exist, you can try this to find out what’s missing:

void PreviewLetter()
    {
        print("Preview1 Length: " + Preview1.Length);
        if (Line == 1)
        {
            try
            {
                Preview.sprite = Preview1[Loc1];
            }
            catch
            {
                Debug.Log("Preview1[" + Loc1 + "] does not exist");
            }
           
        }
        if (Line == 3)
        {
            try
            {
                Preview.sprite = Preview3[Loc1];
            }
            catch
            {
                Debug.Log("Preview3[" + Loc1 + "] does not exist");
            }
        }
        if (Line == 4)
        {
            try
            {
                Preview.sprite = Preview4[Loc1];
            }
            catch
            {
                Debug.Log("Preview4[" + Loc1 + "] does not exist");
            }
        }
    }
[/script]

The problem is that the array actually has 75 members (set in the inspector), but comes up as zero length, then comes up as Length 75, as shown above. The member being accessed is there, it exists (I see it on the screen). The image is displayed properly; I’m just getting the error message as well.

Are you certain you have just one of these components in the scene? Is it possible that you have another one somewhere with nothing in the list that would cause the first message & error?

Try including “GetInstanceID()” in your print statement to see if it’s two unique objects.

Ok, when I printed the InstanceId, I get this:

Preview1 Length: 0 31742
UnityEngine.MonoBehaviour: print(Object)

IndexOutOfRangeException: Array index is out of range.
RegisterYourName.PreviewLetter () (at Assets/Scripts/RegisterYourName.cs:170)

Preview1 Length: 75 31756
UnityEngine.MonoBehaviour: print(Object)

Additionally, I’m also receiving a NullReferenceException: Object reference not set to an instance of an object
RegisterYourName.Update () (at Assets/Scripts/RegisterYourName.cs:124)

The line reads as follows:

            if (Temp == "@")
              {
                if (Name.Length >= 1)
                  {
                  }
              }

Name has been defined as a string, and has a length of 2 (at the time I’m running this). The variable is declared locally, not public.

Ok, it WAS another DERP. The only one in the scene, huh? You were right. There was an object with the same piece of code - one I’d had earlier, but had never removed for whatever reason, and the two pieces of code were warring with each other. Getting rid of the obsolete reference solved both problems. Thanks once again!

1 Like

Another (seemingly minor) question:

I have a parallax script, as follows:

using UnityEngine;
using System.Collections;

public class ParallaxScroll1 : MonoBehaviour
  {
    public Renderer Foreground;
    public Renderer Background;
    public Renderer Cloud1;
    public Renderer Cloud2;
    public Renderer Cloud3;
    public Renderer Middle;
    public Renderer Stripe;
    public float BackgroundSpeed = 0.02F;
    public float CloudSpeed      = 0.06F;
    public float ForegroundSpeed = 0.06F;
    public float MiddleSpeed     = 0.06F;
    public float StripeSpeed     = 0.06F;
    public float Offset = 0;
    Variables VarRef;
    // Use this for initialization
    void Start()
      {
        VarRef = gameObject.AddComponent<Variables>();
      }
    // Update is called once per frame
    void Update()
      {
        VarRef.Load();
        float BackgroundOffset = Offset;
        float CloudOffset      = Offset;
        float ForegroundOffset = Offset;
        float MiddleOffset     = Offset;
        float StripeOffset     = Offset * StripeSpeed;
        Background.material.mainTextureOffset   = new Vector2(BackgroundOffset, 0);
        Cloud1.material.mainTextureOffset       = new Vector2(CloudOffset, 0);
        Cloud2.material.mainTextureOffset       = new Vector2(CloudOffset, 0);
        Cloud3.material.mainTextureOffset       = new Vector2(CloudOffset, 0);
        Foreground.material.mainTextureOffset   = new Vector2(ForegroundOffset, 0);
        Middle.material.mainTextureOffset       = new Vector2(MiddleOffset, 0);
        Stripe.material.mainTextureOffset       = new Vector2(StripeOffset, 0);
      }
  }

I’ve used this code before, and it works very well; I can control each of the 7 layers independently of each other, which is what I want. However, I’ve added a feature in this game to slow down or speed up the action. The controller which handles the foreground characters is working fine - but when I try to adjust the parallax, the entire set of images gets repositioned. Yes, they move more slowly (or more quickly, as the case may be), but I don’t want the position to reset. I want to speed up/slow down the progress without changing the location.

I tried this:

float BackgroundOffset = Offset * (BackgroundSpeed * Multiplier);

Where Multiplier is a float variable set to 0.25F or 1.00F, depending on the speed. But whenever I change the speed, the images “jump” to a new position. How can I speed this up WITHOUT resetting the position?

So if I’m understanding this script correctly, the intention is to set the one variable “Offset”, and have all the layers change position based on that offset * their own speed multiplier?

If that’s the case then you only need to slow down your changes to Offset, and the rest of the offsets will change slower as well.

Just a tip, you can simplify your logic by creating a class to hold your layer data, and looping through a list of that class like this:

using System;

[Serializable] public class Layer {
    public string name;
    public Renderer renderer;
    public float speed = 1f;
    public float currentOffsetX;
}

public List<Layer> layers;

public float Offset { get; set; }

private void Update() {
    foreach(Layer layer in layers) {
        layer.currentOffsetX = Offset * layer.speed;
        layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    }
}

That way it’s really easy to add new layers and change speeds in the inspector.

So you’re suggesting I try something like

float BackgroundOffset = (Offset * Multiplier) * BackgroundSpeed;

??

I don’t see how that would be any different. I’m not sure what the Vector2.right is for, since I’m not using it currently. However, I don’t see how this is moving anything at all… since Offset is 0, the result should always be zero. Hmm. Let me check my other code…

Vector2.right is the same as “new Vector2(1,0)”. When multiplied by a float, it makes a Vector2 with the float as the X, and 0 as the Y.

Maybe I misinterpreted what your original script is trying to do, but in my script example, the only variable you would change at runtime would be Offset, which would be the camera’s offset from the starting point. As the camera moves, all the layers move at different speeds according to how much the camera moves with just “Offset * layer.speed”.

Could you describe what you imagine “Offset”, “BackgroundSpeed”, and “Multiplier” to be representing?

BackgroundSpeed, CloudSpeed, MiddleSpeed (etc.) should be the speed for each layer. Offset, I thought was how much the image was being offset from its original position (i.e., how many pixels left). And multiplier SHOULD be the number I use to make it faster or slower. I want slow, normal and fast.

Maybe this will help: In my game controller, I have the following:

    void FixedUpdate()
      {
        if (VarRef.Started[VarRef.CurrPlayer] == true && VarRef.EndScene[VarRef.CurrPlayer] == false && VarRef.GameOver[VarRef.CurrPlayer] == false)
          {
            XPos += BackgroundSpeed;
            Parallax.Offset = XPos;
          }
      }

I still need help with this… it’s a little thing, but it’s annoying!

If you take another look at my reply above, that script would be able to move all the layers at different speeds, based on the current Offset.

If you want to then speed up / slow down that offset change overall, something like this maybe?

using System;
public class Example : MonoBehaviour {
    [Serializable]
    public class Layer {
        public string name;
        public Renderer renderer;
        public float speed = 1f;
        public float currentOffsetX;
    }

    public float parallaxSpeed;
    public List<Layer> layers;

    public float Offset { get; private set; }

    private void Update() {
        foreach(Layer layer in layers) {
            layer.currentOffsetX = Offset * layer.speed;
            layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
        }
    }

    public void ChangeOffsetBy(float delta) {
        Offset += delta * parallaxSpeed;
    }
}

So you would be using “ChangeOffsetBy” to shift the parallax incrementally, which would take into account parallaxSpeed. The “Offset” would then change slower/faster according to the speed, making each layer also reflect the speed change.

Both your pieces of code look useful & intriguing, but I’m not sure how to integrate it into what I have. I have:

    public Renderer Foreground;
    public Renderer Background;
    public Renderer Cloud1;
    public Renderer Cloud2;
    public Renderer Cloud3;
    public Renderer Middle;
    public Renderer Stripe;

These are passed in from the Inspector, referring to the specific objects to be scrolled. How would I put these into the layer list? Also, what about their individual speeds? Thanks!

This part of the script here:

[Serializable] public class Layer {
    public string name;
    public Renderer renderer;
    public float speed = 1f;
    public float currentOffsetX;
}

public List<Layer> layers;

Defines a new class called Layer, and then makes a public List of Layers. Since I used the [Serializable] attribute, that class’s public variables can be shown in the inspector. So you will be able to add to the list as you would any other list, and configure all the variables for each layer. Then your script will have a nice list of Layers to work with, loop through, etc.

Then in the Update, you see:

private void Update() {
    foreach(Layer layer in layers) {
        layer.currentOffsetX = Offset * layer.speed;
        layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
    }
}

Where I loop through the list of layers, having access to all the variables for each layer configured in the inspector.

I created the class:

using System;
[Serializable] public class Layer
  {
    public string name;
    public Renderer renderer;
    public float speed = 1f;
    public float currentOffsetX;
  }
public List<Layer> layers;

but it says "Unexpected symbol List', expecting class’, delegate', enum’, interface', partial’, or `struct’.

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

public class ParallaxScroll1 : MonoBehaviour
  {
    public Renderer Foreground;
    public Renderer Background;
    public Renderer Cloud1;
    public Renderer Cloud2;
    public Renderer Cloud3;
    public Renderer Middle;
    public Renderer Stripe;
    public float BackgroundSpeed = 0.02F;
    public float CloudSpeed      = 0.06F;
    public float ForegroundSpeed = 0.06F;
    public float MiddleSpeed     = 0.06F;
    public float StripeSpeed     = 0.06F;
    Variables VarRef;
    // Use this for initialization
    void Start()
      {
        VarRef = gameObject.AddComponent<Variables>();
      }
    // Update is called once per frame
    public float Offset { get; set; }
    private void Update()
      {
        foreach(Layer layer in layers)
          {
            layer.currentOffsetX = Offset * layer.speed;
            layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
          }
      }
  }

Also, in the ParallaxScroll1.cs code, it says that ‘layers’ does not exist in the current context.

Layer would be an inner class to ParallaxScroll, like this:

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

public class ParallaxScroll1 : MonoBehaviour {
    [Serializable]
    public class Layer {
        public string name;
        public Renderer renderer;
        public float speed = 1f;
        public float currentOffsetX;
    }

    public List<Layer> layers;

    public float Offset { get; set; }

    Variables VarRef;
    // Use this for initialization
    void Start() {
        VarRef = gameObject.AddComponent<Variables>();
    }
    // Update is called once per frame
    private void Update() {
        foreach(Layer layer in layers) {
            layer.currentOffsetX = Offset * layer.speed;
            layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
        }
    }
}

That makes much more sense. The only remaining question is, where do I call the ChangeOffsetBy function? What do I pass to it?

You can have this script manage the offset if you like, or you can have another class do that. You’re passing in the change in offset between last frame and this frame, or any other amount you want to change the offset by for whatever reason.

So if you’re tracking the camera horizontal movement, you would keep a variable of the last position, and each frame get the difference between last and current and pass that into ChangeOffsetBy. Using a function allows you to have a different class interface with the parallax if necessary, but you could also do it all directly inside the parallax class.

Unfortunately, I don’t understand your answer. Here’s what I have:

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

public class ParallaxScroll1 : MonoBehaviour
  {
    [Serializable] public class Layer
      {
        public string name;
        public Renderer renderer;
        public float speed = 1f;
        public float currentOffsetX;
      }
    public List<Layer> layers;
    public float Offset { get; set; }
    public float ParallaxSpeed;
    Variables VarRef;
    // Use this for initialization
    void Start()
      {
        VarRef = gameObject.AddComponent<Variables>();
      }
    // Update is called once per frame
    private void Update()
      {
        VarRef.Load();
        if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  0.25F) ParallaxSpeed =  0.05F; //Slow
        if (VarRef.CurrSpeed1[VarRef.CurrPlayer] ==  1.00F) ParallaxSpeed =  0.00F; //Normal
        if (VarRef.CurrSpeed1[VarRef.CurrPlayer] == 15.00F) ParallaxSpeed = 15.00F; //Fast
        foreach(Layer layer in layers)
          {
            layer.currentOffsetX = Offset * layer.speed;
            layer.renderer.material.mainTextureOffset = Vector2.right * layer.currentOffsetX;
          }
      }
    public void ChangeOffsetBy(float delta)
      {
        Offset += delta * ParallaxSpeed;
      }
  }

I can detect the user’s input to change the speed (I’m already doing that). Once the speed has been changed, the parallax needs to change with it.

So, on update, it checks the speed, and changes the ParallaxSpeed accordingly. I could add a line calling ChangeOffsetBy just before the “foreach,” but I don’t have a value to put in for delta. Can you show me what you mean? I’m lost on this.