Image Cycle Script...

Hello there,

I started using Unity last week. I have done nothing but sleep four hours or so a day and work on a project. I have it all done and I’m happy with it, however I’m running into a critical issue that crashes my game. My game is essentially 190 or so images that you can click left and right on and change the shader and text tooltip to read 0/7, 1/7, 2/7 etc or however many you need of each item. It’s a checklist essentially.

The problem arises when you click the “next” button when you’re already 7/7 and you go beyond the array, outside of the index, however you need to put it. I get an “IndexOutOfRangeException: Index was outside the bounds of the array” error and it crashes. Since it saves automatically outside of the range, I’m screwed without resetting the button manually.

How do I “cap” the function of the next and previous buttons so that they cannot go outside of the index in either direction? Keep in mind out of the 190 buttons they all have different values. You need 20/20 of some things.

Here’s my code:

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

public class Cycle : MonoBehaviour
{
 
    public GameObject[] background;
    public int index;      

    void Update()
    {
        if(index >= 20)
           index = 20 ;

        if(index < 0)
           index = 0 ;
      


        if(index == 0)
        {
            background[0].gameObject.SetActive(true);
        }

                if(index == 1)
        {
            background[1].gameObject.SetActive(true);
        }

                if(index == 2)
        {
            background[2].gameObject.SetActive(true);
        }

                if(index == 3)
        {
            background[3].gameObject.SetActive(true);
        }

                if(index == 4)
        {
            background[4].gameObject.SetActive(true);
        }

                if(index == 5)
        {
            background[5].gameObject.SetActive(true);
        }

                if(index == 6)
        {
            background[6].gameObject.SetActive(true);
        }

                if(index == 7)
        {
            background[7].gameObject.SetActive(true);
        }

                if(index == 8)
        {
            background[8].gameObject.SetActive(true);
        }

                if(index == 9)
        {
            background[9].gameObject.SetActive(true);
        }

                if(index == 10)
        {
            background[10].gameObject.SetActive(true);
        }

                if(index == 11)
        {
            background[11].gameObject.SetActive(true);
        }

                if(index == 12)
        {
            background[12].gameObject.SetActive(true);
        }

                if(index == 13)
        {
            background[13].gameObject.SetActive(true);
        }

                if(index == 14)
        {
            background[14].gameObject.SetActive(true);
        }

                if(index == 15)
        {
            background[15].gameObject.SetActive(true);
        }

                if(index == 16)
        {
            background[16].gameObject.SetActive(true);
        }

                if(index == 17)
        {
            background[17].gameObject.SetActive(true);
        }

                if(index == 18)
        {
            background[18].gameObject.SetActive(true);
        }

                if(index == 19)
        {
            background[19].gameObject.SetActive(true);
        }
      
    }

    public void Next()
     {
        index += 1;
  
         for(int i = 0 ; i < background.Length; i++)
         {
            background[i].gameObject.SetActive(false);
            background[index].gameObject.SetActive(true);
         }
            Debug.Log(index);
     }
  
     public void Previous()
     {
          index -= 1;
  
        for(int i = 0 ; i < background.Length; i++)
         {
            background[i].gameObject.SetActive(false);
            background[index].gameObject.SetActive(true);
         }
            Debug.Log(index);
     }

 
}

And the manager for this code…

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

public class CycleManager : MonoBehaviour
{
    public List<Cycle> CycleList;
    void Start()
    {
        if (!PlayerPrefs.HasKey("CycleValues"))
            return;  // do nothing if there's no save value
        string[] loadedStrings = PlayerPrefs.GetString("CycleValues").Split(' ', StringSplitOptions.RemoveEmptyEntries);
        for(int i=0; i<CycleList.Count; i++)
            CycleList[i].index = int.Parse(loadedStrings[i]);
    }
    void OnApplicationQuit()
    {
        string saveString = "";
        foreach(Cycle c in CycleList)
            saveString += c.index + " ";
        PlayerPrefs.SetString("CycleValues", saveString);
        PlayerPrefs.Save();
    }
}

Go easy on me, I barely understand the basics but am passionate about this project.

Thank you so much for the help.

Well, there are a lot of things I would certainly change about your scripts, but to directly answer your question.

Next just needs to check if index + 1 >= background.Length. Because Arrays are 0 based, when index + 1 == the size of your array, then that means it would be out of range. Your choices at that point are either to set it back to 0 so it rolls over, or if you do the check, then just don’t increment it.

On the previous one, you just have to make sure it’s not going to be less than 0.

I would suggest you look into more c# tutorials to help out, you have plenty of time if you only just started learning last week. :slight_smile:

I’ve barely slept all week, and I’ve exhausted all of the tutorials I could on the subject. I was loathe to ask anyone at all for help and have mostly abstained. In many cases there were no guides for exactly what I wanted so I Frankensteined other people’s code together from YouTube and forums to make it work, and for the most part it functions perfectly, even if it is ugly.

However I am no longer off work and can’t dedicate 20 hour days anymore after this weekend. I don’t quite understand exactly what you’re saying, try though I might. So I would add a line around line 134 something like

    public void Next()
     {

if index + 1 >= background.Length
{
        index += 1;
  
         for(int i = 0 ; i < background.Length; i++)
         {
            background[i].gameObject.SetActive(false);
            background[index].gameObject.SetActive(true);
         }
            Debug.Log(index);
     }
}
else
{
Debug.Log("Out of Range");
}
{

}

I’m sure that’s nowhere near what you meant. Is there any way you could look at the code I posted in the original post and plug it in where you mean? I’d be so very grateful. It’s literally the last little thing that’s hanging me up on the whole project.

I think you understand the error, but just in case,

Here are some notes on IndexOutOfRangeException and ArgumentOutOfRangeException:

http://plbm.com/?p=236

Steps to success:

  • find which collection it is (critical first step!)
  • find out why it has fewer items than you expect
  • fix whatever logic is making the indexing value exceed the collection
  • remember you might have more than one instance of this script in your scene/prefab

And this is how to ACTUALLY find the error, and it should only take a minute or two:

You must find a way to get the information you need in order to reason about what the problem is.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is
  • you’re getting an error or warning and you haven’t noticed it in the console window

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: How To - Capturing Device Logs on iOS or this answer for Android: How To - Capturing Device Logs on Android

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

Well, the nice thing about programming is there are a ton of ways to do things. In your case, it’s not wrong to go this route, but you need to look at the logic. Kurt’s advice hopefully helps with the reason for the error, so you’ll need to rework the logic.

In this case, you don’t want to increase index if the value is going to be over the length, because that just continues to create the error. So, just switch it to < and then it will only go up when it’s lower than the size of the collection.