Q:

Script Optimation in checking database for each frame using event ? Unity3D

Example : 
Note : Slot.cs is a produce slot that produce something with timer.
I have a script name Slot.cs and it have UI Text that will show a timer and Gem Spent. It will look like this :
UI Text Example
UI.Text = "02:00:00 \n (Gem : 5)"
UI.Text = "01:30:00 \n (Gem : 4)"
UI.Text = "01:00:00 \n (Gem : 3)"
UI.Text = "00:30:00 \n (Gem : 2)"
UI.Text = "00:15:00 \n (Gem : 1)"
UI.Text = "00:00:00 \n (Gem : 0)"

The UI.Text Timer is showing each second and the Gem is calculate each second.
The Gem Spent is base from the Timer. And there is a Gem Spent Database like this to check how much is spent :
The parameter look like :

gem (Code, Time_1 ,Time_2, Gem_Spent)

The Time_1 and Time_2 is a minutes
And The Database Look Like :
gems.Add (new gem ("NONE", 0, 0, 0));
gems.Add (new gem ("A", 1, 900, 1));
gems.Add (new gem ("B", 901, 2760, 2));
gems.Add (new gem ("C", 2761, 6420, 3));
gems.Add (new gem ("D", 6421, 13680, 4));
gems.Add (new gem ("E", 13681, 24540, 5));

What i have do to show like UI Text Example above is the script like :
Note : I am not show the time anymore in here. I just need how to show the Gem Spent.
void Update() {

            int c = gDatabase.gems.FindIndex (j => {
                return Player.chickencoop [x].TotalMinute >= j.time1 && Player.chickencoop [x].TotalMinute <= j.time2;
            });
            if (c == -1) {
                UI.Text = 1;
            } else {
                UI.Text = gDatabase.gems [c].gemspent;
            }

}

But using FindIndex and put it in Update() to run every frame take a lot of memory. If I have more than 20 slot.cs attach to every gameobject like that it is slowing the game and make the game loading scene to long.
And i hear using event System.Action and implement it for the Gem Database save a lot of memory and make the game loading fast.
I need to optimal the script using event System.Action, But i don't know how it look like in code ? So could someone give me a clue and solution for this problem for not running those code for every slot.cs that attach to gameobject ? And for not calculate it each frame or each second maybe ?
Maybe use GemSpentManager.cs event ?
Thanks

A:

FindIndex is a bad choice here because you want the object at that index, not the index itself. Just use a for loop.
void Update() {
    //set the text to "1" in case we don't find a matching value
    UI.Text = 1;
    for(int i=0; i < gDatabase.gems.Count(); i++) {
        if(Player.chickencoop[x].TotalMinute >= gDatabase.gems[i].time1 && Player.chickencoop[x].TotalMinute <= gDatabase.gems[i].time2) {
            UI.Text = gDatabase.gems[i].gemspent;
            break; //we're done, break out of the loop
        }
    }
}

Second, you can cache the minimum (and maximum) time for the gem cost found and you only need to do a lookup again if the time changes enough to fall outside those boundaries:
private int minTime;
private int maxTime;

void Update() {
    //if the time is within the last known bounds, skip.
    if(Player.chickencoop[x].TotalMinute < minTime || Player.chickencoop[x].TotalMinute > maxTime) {
        UI.Text = 1;
        for(int i=0; i < gDatabase.gems.Count(); i++) {
            if(Player.chickencoop[x].TotalMinute >= gDatabase.gems[i].time1 && Player.chickencoop[x].TotalMinute <= gDatabase.gems[i].time2) {
                UI.Text = gDatabase.gems[i].gemspent;
                minTime = gDatabase.gems[i].time1;
                maxTime = gDatabase.gems[i].time2;
                break;
            }
        }
    }
}

Note that there may be other optimizations you can make here, such knowing that if the costs are in increasing order, you check that the current time is less than the minimum, and if so, immediately dump out of the loop (because ALL of the entries are going to be larger). Although for an array of size 6, it won't make that much of an impact.

