#c# #unity3d
#c# #unity3d
Вопрос:
возможно ли написать приведенную ниже функцию всего за один цикл foreach? я уже пробовал это, List<object>
но я не привожу это в действие.
private void SoundsOnButtons()
{
Button[] buttons = Resources.FindObjectsOfTypeAll<Button>();
Toggle[] toggles = Resources.FindObjectsOfTypeAll<Toggle>();
foreach (Button obj in buttons)
{
obj.gameObject.AddComponent<EventTrigger>();
EventTrigger.Entry eventEnter = new EventTrigger.Entry();
eventEnter.eventID = EventTriggerType.PointerEnter;
eventEnter.callback.AddListener((eventData) => {
Sound.PlaySfxOneShot(Sound.GiveSfxSound(7));
});
obj.GetComponent<EventTrigger>().triggers.Add(eventEnter);
}
foreach (Toggle obj in toggles)
{
obj.gameObject.AddComponent<EventTrigger>();
EventTrigger.Entry eventEnter = new EventTrigger.Entry();
eventEnter.eventID = EventTriggerType.PointerEnter;
eventEnter.callback.AddListener((eventData) => {
Sound.PlaySfxOneShot(Sound.GiveSfxSound(7));
});
obj.GetComponent<EventTrigger>().triggers.Add(eventEnter);
}
}
спасибо за помощь.
pezezzzle
—————РЕДАКТИРОВАТЬ—————
Спасибо вам @derHugo это было именно то, что я искал, но почему это невозможно?:
private void AddToList<T>() where T : Selectable
{
List<T> list = new List<T>();
Button[] buttons = Resources.FindObjectsOfTypeAll<Button>();
Toggle[] toggles = Resources.FindObjectsOfTypeAll<Toggle>();
list.AddRange(buttons); // Here i get a error cannot convert !
list.AddRange(toggles); // Here i get a error cannot convert !
foreach (var obj in list)
{
obj.gameObject.AddComponent<EventTrigger>();
EventTrigger.Entry eventEnter = new EventTrigger.Entry();
eventEnter.eventID = EventTriggerType.PointerEnter;
eventEnter.callback.AddListener((eventData) => {
Sound.PlaySfxOneShot(Sound.GiveSfxSound(7));
});
obj.GetComponent<EventTrigger>().triggers.Add(eventEnter);
}
}
Комментарии:
1. Вы можете использовать
List<GameObject>
иAddRange
все кнопки и все переключатели2. Это работа для дискриминируемых объединений ! * убегает к ближайшему телефонному аппарату*
3. «но я не привожу это в действие». — как именно
List<Object>
не сработало?4.
obj.gameObject.AddComponent<EventTrigger>();
<— Я проверил документы Unity иButton
не имеет никакого унаследованного свойства или членаgameObject
— так откуда вы его берете?5. Можно, но почему один цикл? Если вы просто хотите упростить код, лучшим выбором будет перенос объектов из цикла for в новый метод.
Ответ №1:
Вы могли бы, да.
Я знаю, что это не совсем то, о чем просит ваш заголовок, но, на мой взгляд, ваш код был бы уже намного лучше, просто извлеките внутренний блок в метод и выполните
private void SoundsOnButtons()
{
var buttons = Resources.FindObjectsOfTypeAll<Button>();
foreach (var obj in buttons)
{
AddTriggerEvent(obj.gameObject);
}
var toggles = Resources.FindObjectsOfTypeAll<Toggle>();
foreach (var obj in toggles)
{
AddTriggerEvent(obj.gameObject);
}
}
private void AddTriggerEvent(GameObject target)
{
var eventTrigger = target.AddComponent<EventTrigger>();
var eventEnter = new EventTrigger.Entry();
eventEnter.eventID = EventTriggerType.PointerEnter;
eventEnter.callback.AddListener((eventData) => {
Sound.PlaySfxOneShot(Sound.GiveSfxSound(7));
});
eventTrigger.triggers.Add(eventEnter);
}
Таким образом, вы остаетесь полностью гибкими и удобными в обслуживании, в то время как это так же эффективно, как делать все в одном цикле — может быть, даже лучше, поскольку вы не тратите впустую производительность реализации или выполнения на объединение двух коллекций в одну.
Вы могли бы даже пойти на один шаг дальше, если вы действительно хотите, и снова создать свой собственный универсальный метод-оболочку, например,
// "Selectable" is the most specific common base class of UI.Button and UI.Toggle
// You could also use "Component" in order to just allow any component as type parameter
private AddEventTriggersToAll<T>() where T : Selectable
{
var instances = Resources.FindObjectsOfTypeAll<T>();
foreach (var obj in instances)
{
AddTriggerEvent(obj.gameObject);
}
}
а затем просто сделайте
private void SoundsOnButtons()
{
AddEventTriggersToAll<Button>();
AddEventTriggersToAll<Toggle>();
}
Если вы действительно хотите использовать один цикл, вы можете использовать, например, Linq Concat
foreach(var obj in Enumerable.Empty<Selectable>().Concat(buttons).Concat(toggles)
{
AddTriggerEvent(obj.gameObject);
}
что в основном равно более или менее выполнению
var list = new List<Selectable>(buttons.Length toggles.Length);
list.AddRange(buttons);
list.AddRange(toggles);
foreach(var obj in list)
{
AddTriggerEvent(obj.gameObject);
}
В качестве очень общего замечания: вы уверены, что хотите использовать Resources.FindObjectsOfTypeAll
, а не, может быть, довольно просто Object.FindObjectsOfType
?
Обновление — Ответ на вашу правку
Хотя вы можете добавлять экземпляры Button
or Toggle
в a List<Selectable>
, вы не можете сделать это в общем List<T> where T : Selectable
, потому что здесь вы ограничиваете только тип вниз.
Другими словами, поскольку Button
это a Selectable
, теоретически было бы вполне допустимо вызывать, AddToList<Button>
НО то, что вы тогда попытались бы сделать, в основном
List<Button> list = new List<Button>();
Toggle[] toggles = Resources.FindObjectsOfTypeAll<Toggle>();
list.AddRange(toggles);
=> не может работать, конечно!
Однако я не вижу необходимости в том, чтобы ваш метод был универсальным вообще… почему бы просто не иметь
private void AddToList()
{
var list = new List<Selectable>();
var buttons = Resources.FindObjectsOfTypeAll<Button>();
var toggles = Resources.FindObjectsOfTypeAll<Toggle>();
list.AddRange(buttons);
list.AddRange(toggles);
foreach (var obj in list)
{
obj.gameObject.AddComponent<EventTrigger>();
EventTrigger.Entry eventEnter = new EventTrigger.Entry();
eventEnter.eventID = EventTriggerType.PointerEnter;
eventEnter.callback.AddListener((eventData) => {
Sound.PlaySfxOneShot(Sound.GiveSfxSound(7));
});
obj.GetComponent<EventTrigger>().triggers.Add(eventEnter);
}
}
НО обратите внимание, что AddRange
работа с List<T>
ними в целом довольно дорогая, если вы заранее не назначаете ожидаемую емкость, поскольку, пока список растет и внутренне превышает текущую максимальную емкость, ему все время приходится перераспределять и перемещать базовый массив!
Вы действительно ничего не получаете, «объединяя» оба массива вместе, просто чтобы иметь один цикл. ЕСЛИ вы хотите пойти по этому пути, несмотря на все, что я сказал, вам лучше сделать
var buttons = Resources.FindObjectsOfTypeAll<Button>();
var toggles = Resources.FindObjectsOfTypeAll<Toggle>();
var list = new List<Selectable>(buttons.Length toggles.Length);
list.AddRange(buttons);
list.AddRange(toggles);
таким образом, вы, по крайней мере, сразу выделяете список только один раз с правильной емкостью
Комментарии:
1. спасибо за ваш ответ, это то, что я ищу, можете ли вы также ответить на мое редактирование в моем вопросе? 🙂
2. @RonnyBigler смотрите Обновление внизу ответа
3. большое вам спасибо за ваше объяснение.