1

I have a function to get images from folder and display each on RawImage for 5 seconds, then start again.

I have this problem after first image is displayed when the looper() -function calls the medialogic() -function. It gives the error in title.

How could I solve this or why does this happen? I'm new with unity and C#.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
using System.IO;
using System.Linq;
using System.Text;

public class Test2 : MonoBehaviour {

    // Use this for initialization

    //Publics
    private string path = "file:///";
    public string folder = "C:/medias/";
    int interval = 7000;
    int arrLength;
    int i = 0;

    string source;
    string str;
    WWW www;

    string[] extensions = new[] { ".jpg", ".JPG", ".jpeg", ".JPEG", ".png", ".PNG", ".ogg", ".OGG" };

    FileInfo[] info;
    DirectoryInfo dir;

    void Start() {
        dir = new DirectoryInfo(@folder);
        info = dir.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
        arrLength = info.Length;

        looper ();
    }

    // Update is called once per frame
    void Update () {

    }

    void looper() {
        medialogic ();
        EasyTimer.SetInterval(() =>
        {
            if (i == arrLength-1) {
                info = dir.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
                arrLength = info.Length;
                i = 0;
            } else {
                i++;
            }
            medialogic();
        }, interval);
    }

    void medialogic() {
        source = info [i].ToString();
        str = path + source;
        www = new WWW(str);
        string[] extType = source.Split('.');
        int pos = Array.IndexOf(extensions, "."+extType[1]);
        if (pos > -1) {
            GetComponent<RawImage> ().texture = www.texture;
            Debug.Log (extType[1]);
        } else {
            //videos here
            Debug.Log (extType[1]);
        }
    }

    public static class EasyTimer
    {
        public static IDisposable SetInterval(Action method, int delayInMilliseconds)
        {
            System.Timers.Timer timer = new System.Timers.Timer(delayInMilliseconds);
            timer.Elapsed += (source, e) =>
            {
                method();
            };

            timer.Enabled = true;
            timer.Start();

            // Returns a stop handle which can be used for stopping
            // the timer, if required
            return timer as IDisposable;
        }

        public static IDisposable SetTimeout(Action method, int delayInMilliseconds)
        {
            System.Timers.Timer timer = new System.Timers.Timer(delayInMilliseconds);
            timer.Elapsed += (source, e) =>
            {
                method();
            };

            timer.AutoReset = false;
            timer.Enabled = true;
            timer.Start();

            // Returns a stop handle which can be used for stopping
            // the timer, if required
            return timer as IDisposable;
        }
    }
}

Edit: User Programmer below has the correct answer.

Jack M.
  • 1,831
  • 5
  • 24
  • 36

2 Answers2

3

Update

As @Programmer answered, my post isn't the proper way to handle WWW Interactions in Unity3D. InvokeRepeating() is the first your learn for simplicity. Please read his answer exactly for understand whats on my example wrong is. #CleanerCoding

Also according to users on this site InvokeRepeating() is using reflection which creates an bigger overhead.

Old Answer

Have a look at MonoBehaviour.InvokeRepeating()

It should work something like this in your code:

void Start() 
{
    dir = new DirectoryInfo(@folder);
    info = dir.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
    arrLength = info.Length;

    // Starting in 0.1 seconds.
    // and will be launched every 5 seconds
    InvokeRepeating("medialogic", 0.1f, 5f);
}

And get rid of this ugly looper() function.

3

Even though this is marked solved I do think that there just many other problems in your code that you may not notice now but will appear later.

Using InvokeRepeating call API(WWW) that needs to be yielded is totally wrong.

The main problem is that the SetInterval function from the Timer class is being called in another Thread but you can't use Unity's API from another Thread.

You can make the medialogic() function run in the Main Thread with this class:

void Awake()
{
    UnityThread.initUnityThread();
}

void looper()
{
    medialogic();
    EasyTimer.SetInterval(() =>
    {
        if (i == arrLength - 1)
        {
            info = dir.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
            arrLength = info.Length;
            i = 0;
        }
        else
        {
            i++;
        }

        UnityThread.executeInUpdate(() =>
        {
            medialogic();
        });

    }, interval);
}

This is not the only problem in your code:

You are improperly using the WWW API. It needs to be used in a coroutine function. You are not currently waiting for to it to finish downloading the image before using it with GetComponent<RawImage>().texture = www.texture;.

Since WWW requires coroutine, coroutine can also be used for timers, remove the Timer class and use the WaitForSeconds to wait for 5 seconds in the coroutine function.

This is the proper way of doing this:

public class Test2 : MonoBehaviour
{

    // Use this for initialization

    //Publics
    private string path = "file:///";
    public string folder = "C:/medias/";
    int interval = 7000;
    int arrLength;
    int i = 0;

    string source;
    string str;
    WWW www;

    string[] extensions = new[] { ".jpg", ".JPG", ".jpeg", ".JPEG", ".png", ".PNG", ".ogg", ".OGG" };

    FileInfo[] info;
    DirectoryInfo dir;

    void Start()
    {
        dir = new DirectoryInfo(@folder);
        info = dir.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
        arrLength = info.Length;

        StartCoroutine(looper());
    }


    IEnumerator looper()
    {
        yield return StartCoroutine(medialogic());

        WaitForSeconds waitTime = new WaitForSeconds(5);

        //Run forever
        while (true)
        {

            if (i == arrLength - 1)
            {
                info = dir.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
                arrLength = info.Length;
                i = 0;
            }
            else
            {
                i++;
            }
            yield return StartCoroutine(medialogic());

            //Wait for 5 seconds 
            yield return waitTime;
        }
    }

    IEnumerator medialogic()
    {
        source = info[i].ToString();
        str = path + source;
        www = new WWW(str);

        //Wait for download to finish
        yield return www;

        string[] extType = source.Split('.');
        int pos = Array.IndexOf(extensions, "." + extType[1]);
        if (pos > -1)
        {
            GetComponent<RawImage>().texture = www.texture;
            Debug.Log(extType[1]);
        }
        else
        {
            //videos here
            Debug.Log(extType[1]);
        }
    }
}
Community
  • 1
  • 1
Programmer
  • 121,791
  • 22
  • 236
  • 328