MonoBehaviour.Invoke
Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable.
Submission failed
For some reason your suggested change could not be submitted. Please <a>try again</a> in a few minutes. And thank you for taking the time to help us improve the quality of Unity Documentation.
Declaration
Description
Invokes the method methodName in time seconds.
If time is set to 0 and Invoke is called before the first frame update, the method is invoked at the next Update cycle before MonoBehaviour.Update. In this case, it’s better to call the function directly.
Note: Setting time to negative values is identical to setting it to 0.
In other cases, the order of execution of the method depends on the timing of the invocation.
If you need to pass parameters to your method, consider using Coroutine instead. Coroutines also provide better performance.
Unity. Вызов функции из другого скрипта
Помогите дописать код
Нужно чтобы при таче по кнопке выполнялась функция (func1) из другого скрипта (anotherScript).
![]()
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.3.11.43300
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Методы организации взаимодействия между скриптами в Unity3D
Пусть у нас в проекте есть два скрипта. Первый скрип отвечает за начисление очков в игре, а второй за пользовательский интерфейс, который, отображает количество набранных очков на экране игры.
Назовем оба скрипта менеджерами: ScoresManager и HUDManager.
Каким же образом менеджеру, отвечающему за меню экрана можно получить текущее количество очков от менеджера, отвечающего за начисление очков?
Предполагается, что в иерархии объектов(Hierarchy) сцены существуют два объекта, на один из которых назначен скрипт ScoresManager, а на другой скрипт HUDManager.
Один из подходов, содержит следующий принцип:
В скрипте UIManager определяем переменную типа ScoresManager:
Но переменную ScoresManager необходимо еще инициализировать экземпляром класса. Для этого выберем в иерархии объектов объект, на который назначен скрипт HUDManager и в настройках объекта увидим переменную ScoresManager со значением None.

Далее, из окна иерархии перетаскиваем объект, содержащий скрипт ScoresManager в область, где написано None и назначаем его объявленной переменной:

После чего, у нас появляется возможность из кода HUDManager обращаться к скрипту ScoresManager, таким образом:
Все просто, но игра, не ограничивается одними набранными очками, HUD может отображать текущие жизни игрока, меню доступных действия игрока, информацию о уровне и многое другое. Игра может насчитывать в себе десятки и сотни различных скриптов, которым нужно получать информацию друг от друга.
Чтобы получить в одном скрипте данные из другого скрипта нам каждый раз придется описывать переменную в одном скрипте и назначать (перетаскивать вручную) ее с помощью редактора, что само по себе нудная работа, которую легко можно забыть сделать и потом долго искать какая из переменных не инициализирована.
Если мы захотим что-то отрефакторить, переименовать скрипт, то все старые инициализации в иерархии объектов, связанные с переименованным скриптом, сбросятся и придется их назначать снова.
В то же время, такой механизм не работает для префабов (prefab) — динамического создания объектов из шаблона. Если какому-либо префабу нужно обращаться к менеджеру, расположенному в иерархии объектов, то вы не сможете назначить самому префабу элемент из иерархии, а придется сначала создать объект из префаба и после этого программно присвоить экземпляр менеджера переменной только что созданного объекта. Не нужная работа, не нужный код, дополнительная связанность.
Следующий подход решает все эти проблемы.
Подход 2. «Синглтоны»
Применим упрощенную классификацию возможных скриптов, которые используются при создании игры. Первый тип скриптов: «скрипты-менеджеры», второй: «скрипты-игровые-объекты».
Основное отличие одних от других в том, что «скрипты-менеджеры» всегда имеют единственный экземпляр в игре, в то время как «скрипты-игровые-объекты» могут иметь количество экземпляров больше единицы.
Примеры
Как правило, в единственном экземпляре существуют скрипты, отвечающие за общую логику пользовательского интерфейса, за проигрывание музыки, за отслеживание условий завершения уровня, за управление системой заданий, за отображение спецэффектов и так далее.
В то же время, скрипты игровых объектов существуют в большом количестве экземпляров: каждая птичка из «Angry Birds» управляется экземпляром скрипта птички со своим уникальным состоянием; для любого юнита в стратегии создается экземпляр скрипта юнита, содержащий его текущее количество жизней, позицию на поле и личную цель; поведение пяти разных иконок обеспечивается различными экземплярами одних и тех же скриптов, отвечающих за это поведение.
В примере из предыдущего шага скрипты HUDManager и ScoresManager всегда существуют в единственном экземпляре. Для их взаимодействия друг с другом применим паттерн «синглтон» (Singleton, он же одиночка).
В классе ScoresManager опишем статическое свойство типа ScoresManager, в котором будет храниться единственный экземпляр менеджера очков:
Осталось инициализировать свойство Instance экземпляром класса, который создает среда Unity3D. Так как ScoresManager наследник MonoBehaviour, то он участвует в жизненном цикле всех активных скриптов в сцене и во время инициализации скрипта у него вызывается метод Awake. В этот метод мы и поместить код инициализации свойства Instance:
После чего, использовать ScoresManager из других скриптов можно следующим образом:
Теперь нет необходимости в HUDManager описывать поле типа ScoresManager и назначать его в редакторе Unity3D, любой «скрипт-менеджер» может предоставлять доступ к себе через статическое свойство Instance, которое будет инициализировать в функции Awake.
Плюсы
— нет необходимости описывать поле скрипта и назначать его через редактор Unity3D.
— можно смело рефакторить код, если что и отвалится, то компилятор даст знать.
— к другим «скриптам-менеджерам» теперь можно обращаться из префабов, через свойство Instance.
Минусы
— подход обеспечивает доступ только к «скриптам-менеджерам», существующим в единственном экземпляре.
— сильная связанность.
На последнем «минусе» остановимся подробнее.
Пусть мы разрабатываем игру, в которой есть персонажи (unit) и эти персонажи могут погибать (die).
Где-то находится участок кода, который проверяет не погиб ли наш персонаж:
Каким образом игра может отреагировать на смерть персонажа? Множеством разнообразных реакций! Приведу несколько вариантов:
— надо удалить персонажа из сцены игры, чтобы он больше не отображался на ней.
— в игре начисляются очки за каждого погибшего персонажа, нужно их начислить и обновить значение на экране.
— на специальной панели отображаются все персонажи в игре, где мы можем выбрать конкретного персонажа. При смерти персонажа, нам нужно обновить панель, либо убрать персонажа с нее, либо отобразить что он мертв.
— нужно проиграть звуковой эффект смерти персонажа.
— нужно проиграть визуальный эффект смерти персонажа (взрыв, брызги крови).
— система достижений игры имеет достижение, которое считает общее число убитых персонажей за все время. Нужно добавить к счетчику только что умершего персонажа.
— система аналитики игры отправляет на внешний сервер факт смерти персонажа, нам этот факт важен для отслеживания прогресса игрока.
Учитывая все вышеперечисленное, функция Die может выглядеть следующим образом:
Получается, что персонаж после совей смерти должен разослать всем компонентам, которые в ней заинтересованы этот печальный факт, он должен знать о существовании этих компонентов и должен знать, что они им интересуются. Не слишком ли много знаний, для маленького юнита?
Так как игра, по логике, очень связанная структура, то и события происходящие в других компонентах интересуют третьи, юнит тут ничем не особенный.
Примеры таких событий (далеко не все):
— Условие прохождение уровня зависит от количества набранных очков, набрали 1000 очков – прошли уровень (LevelConditionManager связан с ScoresManager).
— Когда набираем 500 очков, достигаем важную стадию прохождения уровня, нужно проиграть веселую мелодию и визуальный эффект (ScoresManager связан с EffectsManager и SoundsManager).
— Когда персонаж восстанавливает здоровье, нужно проиграть эффект лечения над картинкой персонажа в панели персонажа (UnitsPanel связан с EffectsManager).
— и так далее.
В результате таких связей мы приходим к картине похожей на следующую, где все про всех все знают:

Пример со смертью персонажа немного преувеличен, сообщать о смерти (или другом событии) шести разным компонентам не так часто приходится. Но варианты, когда при каком-то событии в игре, функция, в которой произошло событие, сообщает об этом 2-3 другим компонентам встречается сплошь и рядом по всему коду.
Следующий подход пытается решает эту проблему.
Подход 3. Мировой эфир (Event Aggregator)
Введем специальный компонент «EventAggregator», основная функция которого хранить список событий, происходящих в игре.
Событие в игре — это функционал, предоставляющий любому другому компоненту возможность как подписаться на себя, так и опубликовать факт совершения этого события. Реализация функционала события может быть любой на вкус разработчика, можно использовать стандартные решения языка или написать свою реализацию.
Пример простой реализации события из прошлого примера (о смерти юнита):
Добавляем это событие в «EventAggregator»:
Теперь, функция Die из предыдущего примера с восемью строчками преобразуется в функцию с одной строчкой кода. Нам нет необходимости сообщать о том, что юнит умер всем заинтересованным компонентам и знать о этих заинтересованных. Мы просто публикуем факт свершения события:
А любой компонент, которому интересно это событие, может отреагировать на него следующим образом (на примере менеджера отвечающего за количество набранных очков):
В функции Awake менеджер подписывается на событие и передает делегат, отвечающий за обработку этого события. Сам же обработчик события, принимает в качестве параметра экземпляр умершего юнита и добавляет количество очков в зависимости от типа этого юнита.
Таким же образом, все другие компоненты, кому интересно событие смерти юнита, могут подписаться на него и обработать, когда событие произойдет.
В результате, диаграмма связей между компонентами, когда каждая компонента знала друг о друге, превращается в диаграмму, когда компоненты знают только о событиях, которые происходят в игре (только о интересующих их событиях), но им все равно, от куда эти события пришли. Новая диаграмма будет выглядеть следующим образом:

Я же люблю другую интерпретацию: представьте, что прямоугольник «EventAggregator» растянулся во все стороны и захватил внутрь себя все остальные прямоугольники, превратившись в границы мира. В моей голове, на этой диаграмме «EventAggregator» вообще отсутствует. «EventAggregator» это просто мир игры, некий «игровой эфир», куда различные части игры кричат «Эй, народ! Юнит такой-то умер!», и все прослушивают эфир и если какое-то из услышанных событий их заинтересует, они на него отреагируют. Таким образом — связей нет, каждый компонент независим.
Если я компонент и отвечаю за публикацию какого-то события, то я кричу в эфир мол этот умер, этот получил уровень, снаряд врезался в танк. И мне наплевать интересно кому-нибудь об этом. Возможно, никто не слушает это событие сейчас, а может на него подписана сотня других объектов. Меня, как автора события, это ни грамма не волнует, я про них ничего не знаю и знать не хочу.
Такой подход позволяет легко вводить новый функционал без изменения старого. Допустим, в готовую игру мы решили добавить систему достижений. Мы создаем новую компоненту системы достижений и подписываемся на все интересующие нас события. Никакой другой код не меняется. Не надо ходить по другим компонентам и из них вызывать систему достижений и говорить ей мол и мое событие посчитай пожалуйста. К тому же, все кто публикуют события в мире ничего не знают о системе достижений, даже о факте ее существования.
Замечание
Говоря, что никакой другой код не меняется, я конечно немножко лукавлю. Может оказаться так, что систему достижений интересуют события, которые ранее просто не публиковались в игре, потому как ни одну другую систему до этого не интересовали. И в этом случае, нам нужно будет решить какие новые события добавить в игру и кто будет их публиковать. Но в идеальной игре уже все возможные события есть и эфир наполнен ими по полной.
Плюсы
— не связанность компонентов, мне достаточно просто опубликовать событие, а кого оно интересует не имеет значение.
— не связанность компонентов, я просто подписываюсь на нужные мне события.
— можно добавлять отдельные модули без изменения в существующем функционале.
Минусы
— нужно постоянно описывать новые события и добавлять их в мир.
— нарушение функциональной атомарности.
Последний минус рассмотрим более детально
Представим, что у нас есть объект «ObjectA», в котором вызывается метод «MethodA». Метод «MethodA», состоит из трех шагов и вызывает внутри себя три других метода, которые выполняют эти шаги последовательно («MethodA1», «MethodA2» и «MethodA3»). Во втором методе «MethodA2» происходит публикация какого-то события. И тут происходит следующее: все кто подписан на это событие начнут его обрабатывать, выполняя какую-то свою логику. В этой логике тоже может произойти публикация других событий, обработка которых также может привести к публикации новых событий и так далее. Дерево публикаций и реакции в отдельных случаях может очень сильно разрастись. Такие длинные цепочки крайне тяжело отлаживать.
Но самая страшная проблема, которая тут может произойти, это когда одна из веток цепочки приводит обратно в «ObjectA» и начинает обрабатывать событие путем вызова какого-то другого метода «MethodB». Получается, что метод «MethodA» у нас еще не выполнил все шаги, так как был прерван на втором шаге, и содержит сейчас в себе не валидное состояние (в шаге 1 и 2 мы изменили состояние объекта, но последнее изменение из шага 3 еще не сделали) и при этом начинается выполняться «MethodB» в этом же объекте, имея это не валидное состояние. Такие ситуации порождают ошибки, очень сложно отлавливаются, приводят к тому, что надо контролировать порядок вызова методов и публикации событий, когда по логике этого делать нет необходимости и вводят дополнительную сложность, которую хотелось бы избежать.
Решение
Решить описанную проблему не сложно, достаточно добавить функционал отложенной реакции на событие. В качестве простой реализации такого функционала мы можем завести хранилище, в которое будем складывать произошедшие события. Когда событие произошло, мы не выполняем его немедленно, а просто сохраняем где-то у себя. И в момент наступления очереди выполнения функционала какой-то компоненты в игре (в методе Update, например) мы проверяем на наличие произошедших событий и выполняем обработку, если есть такие события.
Таким образом, при выполнении метода «MethodA» не происходит его прерывание, а опубликованное событие все заинтересованные записывают себе в специальное хранилище. И только после того как к заинтересованным подписчикам дойдет очередь, они достанут из хранилища событие и обработают его. В этот момент весь «MethodA» будет завершен и «ObjectA» будет иметь валидное состояние.
Communication between Scripts — Examples in Unity
In this article we see how to CALL FUNCTIONS and READ VARIABLES that are defined in a different script in Unity. This is especially important to create object-oriented solutions, because being able to access other scripts allows us to create scripts that solve specific problems and work with other scripts to achieve a bigger result, separating responsibility, increasing abstraction. In addition you will also find two videos about calling functions and reading variables from another script in Unity.
Dear reader
In the channel there lots of videos about Blender, Unity and programming
in which we solve different problems and we provide useful information on these topics.

ABOUT THESE VIDEOS
Here you have two videos about accessing variables and calling functions from another script. All the information is presented to you as generic examples, two scripts, «ScriptA» and «ScriptB«, the variable we want to read and the function we want to call are defined in ScriptA, so from ScriptB we are going to access to ScriptA.
HERE YOU HAVE MY UNITY PLAYLIST

What should we take into account?
Let’s look at a list of items to keep in mind to understand the basis behind the interaction between scripts.
About the Scripts
In this case we are going to see an example in Unity, therefore the two Scripts we are going to use will be an extension of the MonoBehaviour class. This, in practical terms, means that when the game starts, a «Start» function will be executed and also in each frame of the game an «Update» method will be automatically executed.
About the execution of Scripts
In order to execute the code that we will include in our scripts, those scripts must be assigned to at least one «GameObject» in the hierarchy of the scene we will run. In programming, there must exist an Instance of the class defined in the Script.
Instances of a classes
When we add the same Script to two different GameObjects we are creating two separate instances of the class, i.e. two objects that are going to be similar because they come from the same class, but their internal state will not necessarily be the same all the time.
Having the reference of an object
This is one of the key points to pay attention to and try to understand in depth.
Objects in programming are instances of a certain class and in order to access its functionality, that is to say read its public parameters or execute its public functions, we must have the reference of the object we need to use, in other words find the object among all the other objects that exist in the program.
The Dot Operator
The dot operator in several programming languages allows us to access the public fields and methods from an object. In other words, if we have the object reference, we can apply the dot operator to it in order to execute any of its public methods or read and write any of its public fields.
MOST SEARCHED VIDEOS FROM MY CHANNEL
ABOUT UNITY
ABOUT BLENDER
Practical example of Interaction between Scripts in C# — Unity
Previous Steps
In any Unity project we create two Scripts, ScriptA and ScriptB, in the first one we define the function that will be executed from the second Script.
In the hierarchy we are going to create two empty GameObjects to be able to create instances of both Scripts.
In GameObjectA we add the ScriptA as component and in GameObjectB the ScriptB. We can do this from the inspector with the «Add Component» button or by dragging the script to the inspector of the GameObject.
Code inside the Scripts
Let’s write the instructions we’ll use to perform the interaction between Scripts.
When you create a new Script in Unity, it will come with some functions predefined, as you can see in figure 5. The «Start» and «Update» method, which will be automatically executed if the Script is assigned to at least one GameObject from the hierarchy.
Functions and Variables from «ScriptA»
In the first Script we are going to write the following code:
A public string called «name» that will help us identify which instance it is.
Two methods, one called «Function1» and the other «Function2«, the first function we will define it as public and the second private, lines 10 and 16 respectively from figure 6.
We will be able to access the «Function1» method through the dot operator because it was defined with public visibility. , as it’s defined as public.
As we can see in figure 6, «Function1» prints in console the result of the execution of «Function2«. This method returns a text that will allow us to see who is the object that is executing the «Function1» method and which instance of the ScriptA class it is.
Functions and Variables from «ScriptB»
The «ScriptB» script will be the one that calls the function defined in the other Script A. In figure 7 we see the instructions defined in the «ScriptB» script.
We define a string to assign a name and know which instance it is.
To be able to execute functions defined in another Script we must have the reference of the instance of that class. So let’s define a ScriptA type variable and name it «scriptA» (first letter with lowercase), as we see in line 13 of figure 7.
Here we only have half of the work done, we declared the
«A» variable inside «B», but this variable is empty (a null variable) and will remain empty unless we do something about it.
To find the reference of an object in a Script there are several ways, in this case I will use a function calle «FindObjectOfType<T>» where «T» is the type of the variable we want to find. This function will search in the hierarchy an object of the indicated type and return the reference of that object if it founds it. See line 18 of figure 7.
Now that we have the reference of the «A» object, inside «B» we can execute the «Function1» function that is defined inside the A Script. Line 20 from figure 7).
Dot Operator
As mentioned before, the dot operator will allow us to access all the fields and public methods defined within the class.
In figures 8 and 9 we see that using the reference of the ScriptA-type object followed by a dot, we can see the list of fields and methods that are available to use.
In figure 8 we see the «name» variable that was the public string defined inside «ScriptA» and in figure 9 we see the «Function1» method, also defined as public. We can’t see the «Function2» method because it was declared as private.
First exectution test
Before enter in the Play mode, we select GameObjects «A» and «B» from the hierarchy and write names in the «name» fields to be able to analyze the execution of our code.
The «ScriptA» instance will be called «George (A)» and the
«ScriptB» instance will be called «Mike (B)«, as we see in figures 10 and 11.
When entering in the Play mode we see in the inspector of GameObjectB that the «ScriptA» field shows an object (unlike figure 11 where it said «none»). This means that the «ScriptB» was able to find the «ScriptA» reference.
Figure 13 shows the on-screen message, printed by the ScriptA Function1 method, which was called from the ScriptB.
The message says: «Mike(B) has executed my Function1. I’m George(A), by the way.
Second execution test
Let’s go a little deeper into the concept of programming object as an instance of a class.
Choose GameObjectA from the hierarchy and add a second instance of the ScriptA class using the «Add Component» or drag and drop button.
This second instance will be called «Luke (A)«, in figure 14 we see both instances of the class.
When running the game as it is, we see in the console that Mike (B) has executed the Function1 method of Luke (A), see figure 15.
What has happened here is that the «FindObjectOfType<>» function in line 18 of figure 7, has found a different reference of a ScriptA type object than before, the «name» variable from this references is «Luke (A)«. A different instance of the same class as the one that has the text «George (A)» in its «name» variable.
Now lets modify the code in «ScriptB» so that it is able to find all the «ScriptA» references in the scene and execute the «Function1» method of each one of them.
In the object declaration we have now defined an array (or vector) of «ScriptA» type objects (line 13 figure 16), this means that we will be able to save several references of ScriptsA objects.
In line 18 of figure 16 the change is rather subtle, instead of running the «FindObjectOfType<T>» function we use «FindObjectsOfType<T>«, this other function returns all the references of the indicated «T» type that is able to find in the hierarchy.
The last thing we do is go through all the elements of the array using a foreach loop and we execute the «Function1» method to all of them, as can be seen in lines 20 to 23 of figure 16.
When entering again in the Play Mode, we see that now in the GameObjectB inspector we have the «ScriptA» object references (figure 17) inside an array of size 2.
And now in the console appear two messages, the first corresponds to the execution of Luke’s «Function1» method and the second to the execution of George’s «Function2» method.
Third execution test
We are going to modify the ScriptB again to see another way to obtain the references of the objects and thus to be able to call their functions from another Script.
In this case, in the «ScriptB«, we are going to declare two serialized «ScriptA» objects (they can also be public, the idea is that they appear in the inspector). These objects will be called «scriptALuke» and «ScriptAGeorge«.
Then in the Start method we are going to execute the «Function1» methods directly using these objects. In this case it is not necessary to find the references through code since we will assign them directly in the inspector.
The modified «ScriptB» is shown below.
In the inspector we can see the new fields for «ScriptA» objects (figure 20).
We will modify a little the GameObjects of the hierarchy, we will have an Empty GameObject called A‑Luke and another called A‑George.
In each GameObject we assign the ScriptA component and complete the corresponding name, see figures 22 and 23.
Now let’s take the GameObjects from the hierarchy and assign them in the corresponding fields of the «ScriptB»
In figures 25 and 26 we see that the references have been assigned manually, this means that we can execute the «Function1» methods from each instance.
In console we see that the messages are printed due to the execution of «Function1» method on both instances.
Before finishing I would like to change the order of execution of the Function1 methods in the ScriptB, as seen in figure 28.
When we do this and enter in the Play Mode again we see that the messages on the console switch places, figure 29.
Conclusion
We have seen how to call functions that are defined in other Scripts. This is only possible if the functions are declared with public visibility, this allows the access from external contexts.
In addition we must have the reference of the object that contains that method to execute, this can be achieved in several ways, in this article we saw three ways to do it. It’s important to understand the concept of instances in programming, it can be two or more instances of the same class and therefore multiple objects with the same function defined but the result of the execution of that function on each instance could be different.
Understand in depth the concept of object in programming, which is the instance of a class and the fact that in order to access another object we must have the reference of that object, allow us to build more complex solutions, separating responsibility, increasing the abstraction of our solutions.