forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Уроки (http://forum.boolean.name/forumdisplay.php?f=145)
-   -   Как скрипты общаются (http://forum.boolean.name/showthread.php?t=16712)

pax 27.04.2012 14:04

Как скрипты общаются
 
Мне часто задают вопрос о том, как обратиться из какого-либо скрипта к переменной другого скрипта, или как вызвать метод (функцию) другого скрипта. В этой маленькой статейке я бы хотел описать способы, которые можно для этого использовать.

Публичные переменные и доступ к компонентам

Допустим есть у нас такой скрипт
PHP код:

using UnityEngine;

// скрипт, к переменной которого мы хотим получить доступ
public class ScriptWithVariable
{
   
// переменная, к которой мы хотим получить доступ
   
public int myPublicVariable;


Далее мы хотим из другого скрипта на том же объекте менять эту переменную. Есть несколько способов это сделать:
  • Назначить ссылку на скрипт ScriptWithVariable в редакторе через публичную переменную
  • Получить ссылку на скрипт ScriptWithVariable в начале работы скрипта
  • Получать скрипт перед изменением

Первый вариант подразумевает, что вы создадите публичную

PHP код:

using UnityEngine;

public class 
VariableChanger
{
   
// переменная, которая отобразится в редакторе Unity 
   // и на которую надо перетащить скрипт ScriptWithVariable с того же или иного объекта сцены
   
public ScriptWithVariable scriptWithVariable;

   public 
void Update()
   {
     
// изменение нужной нам переменной
     
scriptWithVariable.myPublicVariable++;
   }



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

PHP код:

using UnityEngine;

public class 
VariableChanger
{
   
// переменная, которая отобразится в редакторе Unity 
   // и на которую надо перетащить скрипт ScriptWithVariable с того же или иного объекта сцены
   
public ScriptWithVariable scriptWithVariable;

   
// добавляем код поиска
   
public void Awake()
   {
      
scriptWithVariable GetComponent<ScriptWithVariable>();
   }

   public 
void Update()
   {
     
// изменение нужной нам переменной
     
scriptWithVariable.myPublicVariable++;
   }



Третий вариант самый не оптимальный для использования в каждом кадре (Update вызывается каждый кадр). Но зато эффективен для разового использования т.к. нет необходимости в создании переменной-ссылки на нужный нам скрипт.

PHP код:

using UnityEngine;

public class 
VariableChanger
{
   public 
void Start()
   {
      
// изменение нужной нам переменной
      
GetComponent<ScriptWithVariable>().myPublicVariable 100500;
   }



Вызов методов других скриптов

Все что описано про публичные переменные относится и к вызову методов.
Имеем скрипт:

PHP код:

using UnityEngine;

// скрипт, метод которого мы хотим вызвать
public class ScriptWithVariable
{
   public 
int myPublicVariable;

   
// метод который надо вызвать
   
public void ChangeVariable()
   {
      
myPublicVariable++;
   }



Ну и собственно пример вызова:

PHP код:

using UnityEngine;

public class 
VariableChanger
{
   public 
void Start()
   {
      
// изменение нужной нам переменной путем вызова метода скрипта
      
GetComponent<ScriptWithVariable>().ChangeVariable();
   }



Сообщения

Вызвать метод скрипта объекта можно так же послав сообщение этому объекту (не скрипту). Но данный способ медленнее описанного выше.

PHP код:

using UnityEngine;

public class 
VariableChanger
{
   public 
void Start()
   {
      
// изменение нужной нам переменной путем вызова сообщения
      
SendMessage("ChangeVariable");
   }


Данный способ вызовет метод ChangeVariable на всех скриптах текущего объекта, в которых он объявлен с тем же именем.


Ну вот и все что хотел рассказать. Данная статья так же есть на wiki

Черный крыс 31.07.2012 00:19

Ответ: Как скрипты общаются
 
Спасибо pax! В очередной раз отлично прояснил ситуацию.

Попутный вопрос в догонку насчет функции\метода SendMessage()... А как обьекту послать помимо сообщения еще и контекст сообщения ?

В БМаксе - все просто - SendMessage:Object(message:Object, context:Object)

Конечно, можно контекст "впихнуть" в саму мессагу, но хотелось бы как в БлицМаксе =)

pax 31.07.2012 00:47

Ответ: Как скрипты общаются
 
функция SendMessage принимает вторым параметром object, т.е. что угодно. Следовательно можно написать например такой класс
PHP код:

public class MessageData
{
     public 
GameObject context;


и посылать сообщение например так:

PHP код:

SendMessage("LogContext", new MessageData{context this.gameObject}); 

принимающая функция изменилась бы так:

PHP код:

public void LogContext(MessageData messageData)
   {
      
Debug.Log(messageData.context);
   } 


artsiom.kuzmin.86 23.01.2013 21:51

Ответ: Как скрипты общаются
 
Всем привет!
А подскажите как быть, если переменную нужно взять из скрипта другой сцены, т.е. есть сцена со скриптом там переменная bool, мы можем ее менять на true и false, и такоеже значение она должна иметь в другой сцене. Зарание спасибо.

seaman 23.01.2013 22:18

Ответ: Как скрипты общаются
 
В скрипте, переменная которого нужна в другой сцене нужно в Start использовать Object.DontDestroyOnLoad . ТОгда объект на котором этот скрипт не удалится при загрузке следующего уровня и скрипт будет доступен.

artsiom.kuzmin.86 23.01.2013 23:23

Ответ: Как скрипты общаются
 
Большое спасибо!
А сам объект отобразится в новой сцене? Он то мне не нужен. И если не тяжело, можно ссылку на мануал с этой функцией. Я так понял ее так вот писать:

void Start() {Object.DontDestroyOnLoad;}

а потом вызывать одним из описаных методов?

artsiom.kuzmin.86 23.01.2013 23:54

Ответ: Как скрипты общаются
 
ссылку не нужно, уже нашел....

artsiom.kuzmin.86 24.01.2013 16:37

Ответ: Как скрипты общаются
 
Извените, а немогли бы краткий пример написать, а то чета не могу понять, а в справке всего один пример?

Lestar 24.01.2013 16:48

Ответ: Как скрипты общаются
 
Переменные, к которым вы обращаетесь в разных сценах лучше хранить на каком нибуть донт дестрой обьекте. У вас этот обьект будет просто перемещаться между сценами и к переменным всегда будет доступ.

artsiom.kuzmin.86 24.01.2013 16:54

Ответ: Как скрипты общаются
 
Пробавал как-так, ScriptName это имя скрипта на объекте

void Start() {
ScriptName other;
other = gameObject.GetComponent("ScriptName") as ScriptName;
other.DontDestroyOnLoad()
}

pax 24.01.2013 17:15

Ответ: Как скрипты общаются
 
PHP код:

DontDestroyOnLoad(other


artsiom.kuzmin.86 25.01.2013 20:12

Ответ: Как скрипты общаются
 
Всем спасибо, разобрался, теперь тока одна проблема : когда в сцене меняю значение bool переменной, все работает как нужно, перехожу в след. сцену моя переменная с правильным значением тоже(радости нет предела), все работает как нужно, возвращаюсь в исходную сцену и (радость кончилась) значение переменной осталось исходным. Че с этими клонами объектов то делать, я так понял скрипт берет значение переменной с оригинала, а не с клона скрипта.Объекта.

Lestar 25.01.2013 20:41

Ответ: Как скрипты общаются
 
Сделать проверку на существование обьекта. Обьект не просто вставить в сцену, а инстансить его в старте и при этом проверять существование клонов.

artsiom.kuzmin.86 25.01.2013 21:32

Ответ: Как скрипты общаются
 
У меня в сцене1 два объекта, однин со скриптом действия, в нем тогглам меняется значение бул переменной. Второй со скриптом в котором я нахожу первый объект и беру зна.чение переменной, пока все хорошо, значения меняются синхронно в переменных обоих скриптов. Второй скрипт сделал донтдистракт. Переходим во вторую сцену : изночально в ней был только один объект со скриптом который находит появившийся донтдистракт объект и берет значение переменной(значение переменной из первой сцены, после изменения, а не дефолтное) и корректно выполняет свое предназначение(поко все хорошо), но перейдя из сцены2 в 1, мы имеем уже два донтдистройт объекта и значение переменной берецца из первого, а если снова перейти в сцену 2, то там тоже появился еще один донтдистройт объект, но значение переменной осталось такоеже, как при первом переходе.
Так вот как этого избежать? Чтобы донтдистракт объект был как-бы один, а не копировался, и перемесчался из сцены в сцену?

Lestar 25.01.2013 21:51

Ответ: Как скрипты общаются
 
Написал же выше.
Цитата:

Сообщение от Lestar (Сообщение 250688)
Обьект не просто вставить в сцену, а инстансить его в старте и при этом проверять существование клонов.

Код:

public GameObject Main;
Gameobject main;

void Start()
{
 if(main==null) main = (GameObject)Instantiate(Main);
}

Создайте префаб, повесьте на него ваш скрипт, засуньте в паблик поле Main. Вызывайте инстанс обьекта в вашей первой сцене.


Часовой пояс GMT +4, время: 22:07.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot