Проверить значение переменной из каждого игрового объекта, прикрепленного скриптом

У меня есть игровой объект под названием «студент», к которому прикреплен скрипт, затем я дублирую его вручную (ctrl+D), чтобы каждый дублированный объект студента имел один и тот же компонент скрипта. вот скрипт (не полный, потому что слишком длинный)

public class StudentScript : MonoBehaviour {

private Animator animator;
float sec;
public int m;
public GameManage gm;

void Start () {
    animator = GetComponent<Animator> ();
    sec = 0f;
    m = 0;
}

void Update () {
    sec+=Time.deltaTime;
    if (m == 5 && animator.GetInteger ("Behav") == 0) {
        animator.SetTrigger ("Finish");
    }
}

//this is called from another script
public void ResetStudentBehaviour(){
    if (animator.GetInteger ("Behav") != 0) {
        animator.SetInteger ("Behav", 0);
        sec = 0f;
        if (m < 5) {
            m++;
        }
    }else
        Debug.Log ("student done <3");
}
}

я хочу => если у каждого ученика m значение m == 5, то игра закончена. то, что я сделал до сих пор, называется StudentScript из сценария GameManage (общедоступный, поэтому мне нужно установить все экземпляры вручную), затем проверьте значение m для каждого ученика.

public StudentScript stu1, stu2;
void Update () {
    if (stu1.m == 5 && stu2.m == 5) {
        StartCoroutine (ChangeScene());
    }
}
IEnumerator ChangeScene(){
    yield return new WaitForSeconds (10);
    SceneManager.LoadScene(5);
}

есть ли простой способ проверить значение m всего объекта ученика без использования if (stu1.m == 5 && stu2.m == 5), потому что на каждом уровне количество учеников разное, поэтому я хочу создать динамический скрипт для всех уровней


person Eeva    schedule 21.05.2016    source источник


Ответы (2)


Я бы использовал List<> и добавил к нему все ваши StudentScript объекты. Затем вы можете использовать метод System.Linq All для проверки всех элементов в списке.

using System.Linq

//Add all your StudentScript objects to this list
List<StudentScript> studentScripts = new List<StudentScript>();

if(studentScripts.All(x => x.m == 5))
{
    StartCoroutine (ChangeScene());
}

Таким образом, вы можете использовать StudentScripts.Add() для добавления скриптов, и он может быть любого размера, и все элементы все равно будут проверены. Часть x => x.m == 5 называется лямбда-выражением (на всякий случай, если вы не знали). Это не так жутко, как кажется.

Если вы не хотите использовать Linq и лямбды, вы можете просто перебрать список и обновить переменную. Вы можете заменить оператор if на:

private bool isGameOver()
{
    bool gameOver = true;

    for(int i = 0; i < studentScripts.Count; i++)
    {
        if (studentScripts[i].m != 5) 
        {
            gameOver = false;
            break;
        }
    }

  return gameOver;
}

void Update()
{
    if (isGameOver()) {
    StartCoroutine (ChangeScene());
    }
}
person Danny Herbert    schedule 21.05.2016
comment
Я работал над второй частью вашего ответа, но вы опубликовали его. Мне это нравится больше, потому что некоторые из функций linq не будут работать в iOS, а некоторые из них выделяют много памяти. Осталось только поместить вторую часть вашего вопроса в функцию. Может быть, логическая функция с именем isGameOver. Это не обязательно, но это сделает код пригодным для повторного использования. Теперь функция обновления будет иметь меньше кода. - person Programmer; 22.05.2016
comment
Смарт, я не знал этого об iOS. Еще раз спасибо за знания, ха-ха. Я вставлю его в функцию для полноты картины! Я думаю, что All подходит для памяти? Сейчас сделаю профиль и проверю. - person Danny Herbert; 22.05.2016
comment
извините, а как объявить studentScripts? - person Eeva; 22.05.2016
comment
@Eeva Я сделал небольшую ошибку в первом разделе кода. Так и должно быть List<StudentScript> studentScripts = new List<StudentScript>();. Я обновил ответ. Также @Programmer был прав, All выделяя 40b памяти при каждом вызове. Если вы вызываете его в Update таким образом, используйте второй предложенный метод! - person Danny Herbert; 22.05.2016
comment
@Eeva, тебе тоже придется поставить using System.Collections.Generic; вверху скрипта. - person Danny Herbert; 22.05.2016
comment
@Eeva Этот ответ был отредактирован. Я исправил глупую ошибку, и программист тоже. Попробуйте сейчас, и это должно сработать. - person Danny Herbert; 22.05.2016
comment
@ gjttt1 Я не знаю насчет All, но у orderBy и у некоторых других проблемы из-за AOT. В любом случае, я немного исправил код, изменив функцию на bool, а затем вернув ее, если игра окончена или нет. Второй метод в вашем ответе настоятельно рекомендуется. Распределение памяти в GameEngine вообще не очень хорошо, особенно когда его можно избежать. Также оптимизирована функция. - person Programmer; 22.05.2016

Вы можете найти все объекты определенного типа, которые есть в сцене, а затем отфильтровать их с помощью Linq или подобного.

StudentScript[] studentsInScene = Object.FindObjectsOfType<StudentScript>();

if (studentsInScene.All(student => student.m == 5))
{
    StartCoroutine(ChangeScene());
}

FindObjectsOfType может быть не таким быстрым, как список, которым вы управляете самостоятельно (хотя это может быть), но если это не является вашим узким местом (что, скорее всего, так и есть), то эти несколько строк кода намного проще понять и таким образом предпочтительнее.

person Thomas Hilbert    schedule 22.05.2016