Random index from the list is not removed and ArgumentoutofRangeException error

197 views Asked by At

In my Unity Project, I have list of 4 signals. In the code, when CheckPress() is called, a random index, what I call the firststimIndex is selected from a list of signals and that index is sent to MAX/MSP via UDP to play some audio. When PlaySignal() is called, the audio associated with this index is played. This works fine. Then, when LoadNextSignal() is called, this previous index is removed and a new random index is loaded and played and is removed. LoadNextSignal() needs to be called 3 times as the remaining number of signals are three. This process will continue until all signals from the list are removed.

My problem lies when LoadNextSignal()is executed when called second time. How do I fix this part of my code? Also, The variable stimIndex is required as in my project when I write the data, it is written as signals[stimIndex].

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Text;
using System.Net;
using System.Net.Sockets;

public class CheckButtonBehaviour : MonoBehaviour
{
public Button Check;
public Button Play;
public Button NextSignal;

public List<string> signals = new List<string> {"Speech1", "Speech2", "Speech3", "Speech4"};

public int stimIndex;
public int index = 1;
public int counter = 3;
public int remainingSignals;

private static int localPort;
private string IP;  
public int port = 8050;
IPEndPoint remoteEndPoint;
UdpClient client;

void Start()
{
    IP = "127.0.0.1";
    port = 8050;
    remoteEndPoint = new IPEndPoint(IPAddress.Parse(IP), port);
    client = new UdpClient();
    Play.gameObject.SetActive(false);
    NextSignal.gameObject.SetActive(false);
}

public void CheckPress()    
{
    var random = new System.Random();
    int firststimIndex = random.Next(signals.Count);

    ///Sends to MAX MSP 
    string text = firststimIndex.ToString();
    byte[] data5 = Encoding.ASCII.GetBytes(text);
    client.Send(data5, data5.Length, remoteEndPoint);
    Debug.Log("<color=red>First signal is : </color>"+ signals[firststimIndex]);
    stimIndex = firststimIndex;
    
    Check.gameObject.SetActive(true);
    Check.interactable = false;
    Check.enabled = false;

    Play.gameObject.SetActive(true);
    NextSignal.gameObject.SetActive(true);
}

public void LoadNextSignal()
{
   if(signals.Count == 0)
      return;
   signals.RemoveAt(stimIndex); //Removes the previous signal
   remainingSignals = signals.Count;

   Debug.Log("<color=red>Remaining Signals are : </color>" + remainingSignals);
   int randomIndex = UnityEngine.Random.Range(0, remainingSignals);
   string text1 = randomIndex.ToString(); 
   byte[] data6 = Encoding.ASCII.GetBytes(text1);
   stimIndex = randomIndex;
   client.Send(data6, data6.Length, remoteEndPoint);
   
   
   Debug.Log("Loaded Signal" + stimIndex + "; remaining signals before removal equals" + remainingSignals);
   index++;

    if (counter >= index)
    {
        Debug.Log("<color=orange>Yay! Keep Listening!</color>");
    }
    else
    {
        Debug.Log("<color=green>All Trials finished</color>");
        Play.gameObject.SetActive(false);
        NextSignal.gameObject.SetActive(false);
    }
}

void PlaySignal()
{
    byte[] data2 = Encoding.ASCII.GetBytes("A"); //B
    client.Send(data2, data2.Length, remoteEndPoint);
    Debug.Log("<color=red>Signal is Played</color>");
}
}
1

There are 1 answers

4
Tatranskymedved On

There are several "problems" with the code, but they can be fixed:

  1. Using UnityEngine.Random.Range(0, remainingSignals) for Int value.

This function always return float as stated on Unity page for this function . You want to have result as int and I would follow that new System.Random().Next(signals.Count) only.


  1. Access those list items when it can be empty

In development such program/functions, which are called from different places, developer is usually trying to prevent any problems & exceptions when it is possible. As an example we can take your method public void LoadNextSignal() and add following lines at the beginning:

public void LoadNextSignal()
{
   if(signals.Count == 0) return;

   //... the rest of the code
}

This will prevent stepping out of the index & casting this exception. Main idea behind is that you can never be sure, how many times it was executed.