Получение значение из другого класса

373
25 декабря 2016, 18:33

Есть класс (1), в котором содержатся несколько приватных полей (назовем их цена, количество, цвет). Для них уже сделаны геттеры. На сцене имеются несколько UI.Text. Мне нужно, чтобы при появлении этих UI.Text, в них выводилось соответствующее значение полей класса (1). Как это сделать?

Answer 1

У объектов есть метод Find, который находит объект с именем name и возвращает его. Можно воспользоваться им, как один из вариантов.

Пример

public GameObject hand;
void Example() {
    hand = GameObject.Find("Hand");
    hand = GameObject.Find("/Hand");
    hand = GameObject.Find("/Monster/Arm/Hand");
    hand = GameObject.Find("Monster/Arm/Hand");
}

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

Соответственно, при старте Start() находите объект через Find, и даете ему значение, взятое из метода. Что-то типа:

GameObject.Find("/Canvas/MyData/PriceText").GetComponent<Text>().text = GetPrice();
GameObject.Find("/Canvas/MyData/CountText").GetComponent<Text>().text = GetCount();

Небольшое дополнение (если можно так назвать)...

Вообще, на самом деле, скрипты на UI.Text и прочих UI, которые берут данные откуда-то с другого скрипты вам особо и не нужны. Часто делают Менеджеров (Managers), которые ответственны за некую общую сущность. Например UIManager. Делается один скрипт, который управляет отображением в UI. Он слушает события и в зависимости от них производит нужные действия.

Заметка (!!!):

О событиях, о слушателях и рассылках почитайте где-либо, особенно такую вещь как паттерны (шаблоны) проектирования и, в частности, паттерн "наблюдатель (Observer)". Потому что рассылка сообщений основывается именно на данном нём.

Итак, прежде всего нужен скрипт рассылки сообщений, назовём его Messenger.cs, с помощью методов которого и работает менеджер. Его код можно взять по данной ссылке или посмотреть под спойлером:

using System; 
using System.Collections.Generic; 
using System.Linq; 
  
public enum MessengerMode { 
	DONT_REQUIRE_LISTENER, 
	REQUIRE_LISTENER, 
} 
  
static internal class MessengerInternal { 
	readonly public static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>(); 
	static public readonly MessengerMode DEFAULT_MODE = MessengerMode.REQUIRE_LISTENER; 
  
 	static public void AddListener(string eventType, Delegate callback) { 
		MessengerInternal.OnListenerAdding(eventType, callback); 
		eventTable[eventType] = Delegate.Combine(eventTable[eventType], callback); 
	} 
  
	static public void RemoveListener(string eventType, Delegate handler) { 
		MessengerInternal.OnListenerRemoving(eventType, handler);	 
		eventTable[eventType] = Delegate.Remove(eventTable[eventType], handler); 
		MessengerInternal.OnListenerRemoved(eventType); 
	} 
  
	static public T[] GetInvocationList<T>(string eventType) { 
		Delegate d; 
		if(eventTable.TryGetValue(eventType, out d)) { 
			if(d != null) { 
				return d.GetInvocationList().Cast<T>().ToArray(); 
			} else { 
				throw MessengerInternal.CreateBroadcastSignatureException(eventType); 
			} 
		} 
		return null; 
	} 
  
	static public void OnListenerAdding(string eventType, Delegate listenerBeingAdded) { 
		if (!eventTable.ContainsKey(eventType)) { 
			eventTable.Add(eventType, null); 
		} 
  
		var d = eventTable[eventType]; 
		if (d != null && d.GetType() != listenerBeingAdded.GetType()) { 
			throw new ListenerException(string.Format("Attempting to add listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being added has type {2}", eventType, d.GetType().Name, listenerBeingAdded.GetType().Name)); 
		} 
	} 
  
	static public void OnListenerRemoving(string eventType, Delegate listenerBeingRemoved) { 
		if (eventTable.ContainsKey(eventType)) { 
			var d = eventTable[eventType]; 
  
			if (d == null) { 
				throw new ListenerException(string.Format("Attempting to remove listener with for event type {0} but current listener is null.", eventType)); 
			} else if (d.GetType() != listenerBeingRemoved.GetType()) { 
				throw new ListenerException(string.Format("Attempting to remove listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being removed has type {2}", eventType, d.GetType().Name, listenerBeingRemoved.GetType().Name)); 
			} 
		} else { 
			throw new ListenerException(string.Format("Attempting to remove listener for type {0} but Messenger doesn't know about this event type.", eventType)); 
		} 
	} 
  
	static public void OnListenerRemoved(string eventType) { 
		if (eventTable[eventType] == null) { 
			eventTable.Remove(eventType); 
		} 
	} 
  
	static public void OnBroadcasting(string eventType, MessengerMode mode) { 
		if (mode == MessengerMode.REQUIRE_LISTENER && !eventTable.ContainsKey(eventType)) { 
			throw new MessengerInternal.BroadcastException(string.Format("Broadcasting message {0} but no listener found.", eventType)); 
		} 
	} 
  
	static public BroadcastException CreateBroadcastSignatureException(string eventType) { 
		return new BroadcastException(string.Format("Broadcasting message {0} but listeners have a different signature than the broadcaster.", eventType)); 
	} 
  
	public class BroadcastException : Exception { 
		public BroadcastException(string msg) 
			: base(msg) { 
		} 
	} 
  
	public class ListenerException : Exception { 
		public ListenerException(string msg) 
			: base(msg) { 
		} 
	} 
} 
  
// No parameters 
static public class Messenger {  
	static public void AddListener(string eventType, Action handler) { 
		MessengerInternal.AddListener(eventType, handler); 
	} 
  
	static public void AddListener<TReturn>(string eventType, Func<TReturn> handler) { 
		MessengerInternal.AddListener(eventType, handler); 
	} 
  
	static public void RemoveListener(string eventType, Action handler) { 
		MessengerInternal.RemoveListener(eventType, handler); 
	} 
  
	static public void RemoveListener<TReturn>(string eventType, Func<TReturn> handler) { 
		MessengerInternal.RemoveListener(eventType, handler); 
	} 
  
	static public void Broadcast(string eventType) { 
		Broadcast(eventType, MessengerInternal.DEFAULT_MODE); 
	} 
  
	static public void Broadcast<TReturn>(string eventType, Action<TReturn> returnCall) { 
		Broadcast(eventType, returnCall, MessengerInternal.DEFAULT_MODE); 
	} 
  
 	static public void Broadcast(string eventType, MessengerMode mode) { 
		MessengerInternal.OnBroadcasting(eventType, mode); 
		var invocationList = MessengerInternal.GetInvocationList<Action>(eventType); 
  
		foreach(var callback in invocationList) 
			callback.Invoke(); 
	} 
  
	static public void Broadcast<TReturn>(string eventType, Action<TReturn> returnCall, MessengerMode mode) { 
		MessengerInternal.OnBroadcasting(eventType, mode); 
		var invocationList = MessengerInternal.GetInvocationList<Func<TReturn>>(eventType); 
  
		foreach(var result in invocationList.Select(del => del.Invoke()).Cast<TReturn>()) { 
			returnCall.Invoke(result); 
		} 
	} 
} 
  
// One parameter 
static public class Messenger<T> { 
	static public void AddListener(string eventType, Action<T> handler) { 
		MessengerInternal.AddListener(eventType, handler); 
	} 
  
	static public void AddListener<TReturn>(string eventType, Func<T, TReturn> handler) { 
		MessengerInternal.AddListener(eventType, handler); 
	} 
  
	static public void RemoveListener(string eventType, Action<T> handler) { 
		MessengerInternal.RemoveListener(eventType, handler); 
	} 
  
	static public void RemoveListener<TReturn>(string eventType, Func<T, TReturn> handler) { 
		MessengerInternal.RemoveListener(eventType, handler); 
	} 
  
	static public void Broadcast(string eventType, T arg1) { 
		Broadcast(eventType, arg1, MessengerInternal.DEFAULT_MODE); 
	} 
  
	static public void Broadcast<TReturn>(string eventType, T arg1, Action<TReturn> returnCall) { 
		Broadcast(eventType, arg1, returnCall, MessengerInternal.DEFAULT_MODE); 
	} 
  
	static public void Broadcast(string eventType, T arg1, MessengerMode mode) { 
		MessengerInternal.OnBroadcasting(eventType, mode); 
		var invocationList = MessengerInternal.GetInvocationList<Action<T>>(eventType); 
  
		foreach(var callback in invocationList) 
			callback.Invoke(arg1); 
	} 
  
	static public void Broadcast<TReturn>(string eventType, T arg1, Action<TReturn> returnCall, MessengerMode mode) { 
		MessengerInternal.OnBroadcasting(eventType, mode); 
		var invocationList = MessengerInternal.GetInvocationList<Func<T, TReturn>>(eventType); 
  
		foreach(var result in invocationList.Select(del => del.Invoke(arg1)).Cast<TReturn>()) { 
			returnCall.Invoke(result); 
		} 
	} 
} 
  
  
// Two parameters 
static public class Messenger<T, U> {  
	static public void AddListener(string eventType, Action<T, U> handler) { 
		MessengerInternal.AddListener(eventType, handler); 
	} 
  
	static public void AddListener<TReturn>(string eventType, Func<T, U, TReturn> handler) { 
		MessengerInternal.AddListener(eventType, handler); 
	} 
  
	static public void RemoveListener(string eventType, Action<T, U> handler) { 
		MessengerInternal.RemoveListener(eventType, handler); 
	} 
  
	static public void RemoveListener<TReturn>(string eventType, Func<T, U, TReturn> handler) { 
		MessengerInternal.RemoveListener(eventType, handler); 
	} 
  
	static public void Broadcast(string eventType, T arg1, U arg2) { 
		Broadcast(eventType, arg1, arg2, MessengerInternal.DEFAULT_MODE); 
	} 
  
	static public void Broadcast<TReturn>(string eventType, T arg1, U arg2, Action<TReturn> returnCall) { 
		Broadcast(eventType, arg1, arg2, returnCall, MessengerInternal.DEFAULT_MODE); 
	} 
  
	static public void Broadcast(string eventType, T arg1, U arg2, MessengerMode mode) { 
		MessengerInternal.OnBroadcasting(eventType, mode); 
		var invocationList = MessengerInternal.GetInvocationList<Action<T, U>>(eventType); 
  
		foreach(var callback in invocationList) 
			callback.Invoke(arg1, arg2); 
	} 
  
	static public void Broadcast<TReturn>(string eventType, T arg1, U arg2, Action<TReturn> returnCall, MessengerMode mode) { 
		MessengerInternal.OnBroadcasting(eventType, mode); 
		var invocationList = MessengerInternal.GetInvocationList<Func<T, U, TReturn>>(eventType); 
  
		foreach(var result in invocationList.Select(del => del.Invoke(arg1, arg2)).Cast<TReturn>()) { 
			returnCall.Invoke(result); 
		} 
	} 
} 
  
  
// Three parameters 
static public class Messenger<T, U, V> {  
	static public void AddListener(string eventType, Action<T, U, V> handler) { 
		MessengerInternal.AddListener(eventType, handler); 
	} 
  
	static public void AddListener<TReturn>(string eventType, Func<T, U, V, TReturn> handler) { 
		MessengerInternal.AddListener(eventType, handler); 
	} 
  
	static public void RemoveListener(string eventType, Action<T, U, V> handler) { 
		MessengerInternal.RemoveListener(eventType, handler); 
	} 
  
	static public void RemoveListener<TReturn>(string eventType, Func<T, U, V, TReturn> handler) { 
		MessengerInternal.RemoveListener(eventType, handler); 
	} 
  
	static public void Broadcast(string eventType, T arg1, U arg2, V arg3) { 
		Broadcast(eventType, arg1, arg2, arg3, MessengerInternal.DEFAULT_MODE); 
	} 
  
	static public void Broadcast<TReturn>(string eventType, T arg1, U arg2, V arg3, Action<TReturn> returnCall) { 
		Broadcast(eventType, arg1, arg2, arg3, returnCall, MessengerInternal.DEFAULT_MODE); 
	} 
  
	static public void Broadcast(string eventType, T arg1, U arg2, V arg3, MessengerMode mode) { 
		MessengerInternal.OnBroadcasting(eventType, mode); 
		var invocationList = MessengerInternal.GetInvocationList<Action<T, U, V>>(eventType); 
  
		foreach(var callback in invocationList) 
			callback.Invoke(arg1, arg2, arg3); 
	} 
  
	static public void Broadcast<TReturn>(string eventType, T arg1, U arg2, V arg3, Action<TReturn> returnCall, MessengerMode mode) { 
		MessengerInternal.OnBroadcasting(eventType, mode); 
		var invocationList = MessengerInternal.GetInvocationList<Func<T, U, V, TReturn>>(eventType); 
  
		foreach(var result in invocationList.Select(del => del.Invoke(arg1, arg2, arg3)).Cast<TReturn>()) { 
			returnCall.Invoke(result); 
		} 
	} 
}

Еще есть события в игре. Например вспомогательный скрипт GameEvent.cs будет их в себе содержать:

public static class GameEvent {
    public const string GAME_STARTED = "GAME_STARTED";
    public const string ITEM_BOUGHT = "ITEM_BOUGHT";
    public const string SPEED_CHANGED = "SPEED_CHANGED";
    // ... и т.д.
}

В менеджере (UIManager) подписываемся на событие, в данном случае на то, что игра стартовала GAME_STARTED и , например ITEM_BOUGHT (когда предмет покупаем, наверняка меняется их количество?).

public class UIManager : MonoBehaviour {
    [SerializeField] private Text colorLabel;
    [SerializeField] private Text priceLabel;
    [SerializeField] private Text countLabel;
    private MyDataClass myDataClass;
    void Awake() {
        // подписываемся на события и указываем методы, которые будут вызваны при возникновение этого события
        Messenger.AddListener(GameEvent.GAME_STARTED, OnGameStarted);
        Messenger.AddListener(GameEvent.ITEM_BOUGHT, OnItemBought);
    }
    void OnDestroy() {
        Messenger.RemoveListener(GameEvent.GAME_STARTED, OnGameStarted);
        Messenger.RemoveListener(GameEvent.ITEM_BOUGHT, OnItemBought);
    }
    // будет вызван при получении события GAME_STARTED
    private void OnGameStarted() {  
        myDataClass = GameObject.Find("/Canvas/MyData/MyClassObject").gameObject.GetComponent<MyClass>();
        colorLabel.text = myDataClass.GetColor().ToString();
        priceLabel.text = myDataClass.GetPrice().ToString();
        countLabel.text = myDataClass.GetCount().ToString();
    }
    // будет вызван при получении события ITEM_BOUGHT
    private void OnItemBought() {
        countLabel.text = myDataClass.GetCount().ToString();
    }
}

Скрипт вешается на пустой объект на сцене, который желательно тоже так же назвать: "UIManager". В поля скрипта (которые bv.n атрибут SerializeField) добавить нужные объекты (в данном случае текстовые объекты UI.Text) и всё.

Теперь в любой момент, на любом нужном скрипте рассылаем сообщения. Например на каком-нибудь главном скрипте Game.cs

public class Game : MonoBehaviour {
    void Start() {
        // Уведомляем, что игра началась
        Messenger.Broadcast(GameEvent.GAME_STARTED);
    }
}

Или в каком-то другом скрипте, который ответственен за покупку предметов

public class Inventory : MonoBehaviour {
    public void OnPointerDown() {
        _count++;
        // Уведомляем, что предмет куплен
        Messenger.Broadcast(GameEvent.ITEM_BOUGHT);
    }
}

Запускаем игру и радуемся...........

Так системка делается-то...