PDA

Просмотр полной версии : Ссылка на stage


Appleman
31.10.2017, 19:00
Друзья, подскажите ещё один маленький технический момент, пожалуйста. Часто приходится что-то центровать по размерам сцены и вообще с этими размерами взаимодействовать, причём подобные ситуации возникают в разных классах. Ловить в каждом событие ADDED_TO_STAGE - муторно. Как лучше организовать и хранить ссылку на экземпляр stage для быстрого к ней доступа? И откуда её "протягивать"?

Спасибо.

caseyryan
31.10.2017, 19:31
Лучше подписываться каждый раз и делать вычисления по событию.
Если муторно делать это каждый раз, то вместо Sprite можно создать свой класс наследник, и в нем сделать нужные подписки, а потом просто наследовать свои классы от него и перезаписывать метод onAdded, который можно поменить модификатором доступа protected
Если хранить где-то ссылку на stage, то это приведет к дополнительной связанности. Уже нельзя будет просто скопировать какой-то класс из одного проекта в другой. Нужно будет и тот, что хранит stage тянуть, это во-первых, а во вторых ссылка может в какой-то момент, по разным причинам теряться, что приведет к рантайм ошибкам, тогда как по событию, stage будет доступен 100%

Appleman
31.10.2017, 21:57
Спасибо. Значит, будем терпеливо добывать свою ссылку в каждом заинтересованном классе.

Wolsh
31.10.2017, 23:06
"Муторно" :)
А знаешь как я делаю? У меня главная Вью подписана на событие RESIZE от stage, и когда это событие случается, Вью вызывает метод resize() у всех своих модулей, передавая им размеры (не размеры стейджа, а пересчитывает ИХ, модулей, размеры и задает им эти новые).
1) Если модуль будет сам себя пересчитывать так, как хочется ему, а не хозяину, этот модуль нельзя будет использовать в других приложениях или даже в других задачах этого приложения. Для примера доведем до абсурда — написал бы я кнопку, которая спрашивает размеры стейджа и задает себе размеры в зависимости от них, а так же свои координаты на экране (иначе я не знаю зачем вообще иметь ссылку на стейдж). Ну и куда я смогу использовать такую кнопку, кроме одного-единственного случая?
2) Если модуль будет реагировать только на ADDED_TO_STAGE, то при изменении размеров приложения все расползется.
3) Модуль понятия не имеет о том, что творится вокруг него. Это знает хозяин. Может, хозяину пришлось раздвинуть текстовое поле чтобы вместить новый текст, или еще какие пертурбации произошли. У хозяина должна быть возможность изменить размеры и координаты любого модуля. Иерархия и контроль.
4) Модуль должен уметь менять свои размеры без деформации (scale) — в разумных пределах конечно — при необходимости буквально перерисовывая заново какие-то свои элементы. Та же кнопка должна уметь быть любой ширины и любой высоты (не связано друг с другом), но не меньше какого-то разумного минимума (особенно если она с лейблом). Более сложный модуль должен уметь менять размеры, поддерживая какой-то приличный вид, передвигая, перерисовывая, меняя размеры текстфилдов и, в самом ужасном случае, даже добавлять полосы прокрутки, если уместить все свои элементы в заданном размере он не в состоянии.
Это все в идеале, конечно. В реальности такие страсти не всегда нужны; однако при написании игры тебе, как ни крути, придется заморочиться красивым заполнением экрана в режиме фуллскрин. А экраны сейчас какого только разрешения не бывают.

Appleman
31.10.2017, 23:43
А откуда твоя главная вьюха "знает", в каких пределах и на какие значения должны измениться те или иные компоненты? Или это для каждого проекта в зависимости от разметки экрана прописывается?

Если честно, я про RESIZE сцены пока вообще не думал. А привязка к stage потребовалась, чтобы центровать меню по высоте. Ведь в нём кол-во кнопок может меняться от случая к случаю, а значит, и координата y должна подстраиваться. Плюс ширина кнопок подбираться под самый длинный из лэйблов.

ZergMaster
01.11.2017, 00:18
Я кстати тоже делал подобным образом, только более варварски. У меня были в главной вьюхе (main) были private static переменные mainWidth и mainHeight, у которых были только геттеры. И точно также по событию Event.RESIZE у каждого ребенка вызывалась функция .resize(). По разному я делал - иногда width и height были статическими переменными мэйна, иногда - передавались в каждого ребенка. Кажется, тогда я так и не определился, какой вариант оптимальнее)) Хотя сейчас кажется очевидным, что можно по ресайзу менять эти переменные в модели, которая будет рассылать события по всем и вся.

ApplemanА откуда твоя главная вьюха "знает", в каких пределах и на какие значения должны измениться те или иные компоненты?
главная вьюха об этом ничего не знает. Она даже может не знать, сколько этих самых дочерних вьюх, если рассматривать вариант с моделью. В каждом спрайте, который имплементирует iResizeble, своя соб ственная функция resize(), в которую либо приходят размеры стейджа, либо она их забирает из модели и уже самостоятельно принимает решение об изменении.

Добавлено через 3 минуты
хотя блин, что я говорю, ведь каждый спрайт имеет доступ к stage.stageWidth и stageHeight)) Правда, это если он добавлен на сцену. А у меня просто размер менялся из js окружения, поэтому параметры ширины приходили из ExternalInterface

Wolsh
01.11.2017, 00:40
Конечно, Вьюха знает. Это ее единственная ответственность, расположить все красиво на экране.

Но для этого не нужна ссылка на стейдж. Ну то есть, она нужна Вью, и Вью ее получает один раз при добавлении на сцену. Далее Вью создает экземпляры своих модулей. Допустим, у тебя есть вверху полоса интерфейса с каким-то заголовком и парой кнопок (например, вызов глобального Меню, он же канает и за общую Паузу в игре, и, допустим, вызов окна Инвентаря и вызов окна Задания), и внизу полоса интерфейса со всякими данными о состоянии персонажа. А в центре окно текущего стейта — Поединок, или Торговля, или Диалог. Вот три модуля, верхний, нижний и центральный. Вью знает размер стейджа. Вью знает, что верхняя полоса должна быть 24 пикселя высотой, а нижняя 36, и их высота постоянна, её нельзя менять, а вот центральный модуль "подвижен". Так она вычисляет высоту центрального модуля, stage.stageHeight - 24 - 36; Так же узнает координаты Y для центрального модуля и для нижнего: 24 и stage.stageHeight - 36. Ширина всех модулей одинакова — stage.stageWidth. Все эти расчеты помещаются в метод ресайз(), чтобы можно было пересчитать в любой момент, если размеры сцены поменяются. После пересчета у модулей вызываются их методы ресайз(), в которые передаются новые значения.

Горизонтальные модули пытаются подстроиться под изменение ширины (высоту они не меняют по определению). Допустим, в модуле одна кнопка должна быть прижата к левому краю, а вторая — к правому. А посередине какой-то текст. Левую кнопку мы не трогаем, а правой надо пересчитать координату Х, верно? Затем мы узнаем ширину оставшегося пространства между кнопками и подстраиваем ширину текстфилда. УзнаЁм, влазит ли текст; если нет то меняем размер шрифта, пока не влезет.

Это все только звучит страшно; на деле ты бы все это же проворачивал, имея ссылку на стейдж чтобы спросить его размеры, а здесь получаешь размеры в метод ресайз() от Хозяина компонента, вот и вся разница. Но мимимишность использования такого компонента на порядок выше, чем если он сам будет звонить в генштаб по каждому поводу кроме тех, когда надо.

Nooob
01.11.2017, 00:53
нужно оперировать анкерами(пределами) и точками опоры, а не ссылками на родителя/сцену и только при добавлении/изменении куда-то значения анкеров и точек опоры переводить в координаты и размер
посмотри API Flex https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponent.html или Unity UI https://docs.unity3d.com/ScriptReference/RectTransform.html или Node в cocos2d http://www.cocos2d-x.org/reference/native-cpp/V3.0alpha0/d3/d82/classcocos2d_1_1_node.html

Appleman
01.11.2017, 17:24
Конечно, Вьюха знает. Это ее единственная ответственность, расположить все красиво на экране. Но для этого не нужна ссылка на стейдж. Ну то есть, она нужна Вью, и Вью ее получает один раз при добавлении на сцену. Далее Вью создает экземпляры своих модулей.

Получается, все ключевые размеры основных компонентов хранятся в главной вью, верно? Иначе как она узнает, что такой-то компонент имеет фиксированную высоту в столько-то пикселей. И тогда выходит, что размеры компонентам также передаёт в конструктор вью, так?

Nooob, спасибо, читаю.

ZergMaster
01.11.2017, 19:21
Appleman думаю, все же, компонент сам хранит свои размеры и координаты относительно размера приложения. Хранить положения и размеры всех дочерних вьюх в главной - это абсурд))

Wolsh
01.11.2017, 20:53
Имхо, флекс и прочие системы с использованием лейаутов и кучей компонентов слишком избыточен для игры; да и универсальности здесь особой не требуется, как в какой-нибудь библиотеке GUI-компонентов для разработки разных приложений. У игр обычно.. весьма специфический дизайн, далекий от графических примитивов, часто на 100% отрисованый в битмапах.

Получается, все ключевые размеры основных компонентов хранятся в главной вью, верно? Иначе как она узнает, что такой-то компонент имеет фиксированную высоту в столько-то пикселей. И тогда выходит, что размеры компонентам также передаёт в конструктор вью, так?А где им еще храниться, есть варианты? В самих себе?)
"Как она узнает".. ей не надо узнавать, это ты пишешь её и её компоненты. Не доводи до абсурда. Если же вдруг понадобится неизвестная заранее ЗАМЕНА одного компонента другим с неизвестной высотой/шириной, или просто не хочется хардкодить (забивать точные значения вместо "реальных" свойств), то всегда можно спросить именно свойство после ресайза. Если компонент не может изменять высоту, он ее и не изменит при ресайзе. То есть, в моем примере ты задавал бы координату Y центральному модулю как _topPane.height, а не тупо "24". И если в какой-то момент тебе пришлось бы вставить туда другую панель, высотой 30, центральному модулю пришлось бы слегка сжаться.
размеры компонентам также передаёт в конструктор вьюСначала в конструктор, текущие на момент создания, а потом в метод ресайз(w, h). Понятно, что код в конструкторе не дублирует код в ресайз(), а просто вызывает его с этими начальными параметрами.

ZergMaster, Вы меня пугаете. То есть, НЕ абсурд для Вас — когда никто понятия не имеет, какого размера штуки вываливаются на экран, и в каких местах?

Nooob
01.11.2017, 22:14
Имхо, флекс и прочие системы с использованием лейаутов и кучей компонентов слишком избыточен для игры; да и универсальности здесь особой не требуется, как в какой-нибудь библиотеке GUI-компонентов для разработки разных приложений. У игр обычно.. весьма специфический дизайн, далекий от графических примитивов, часто на 100% отрисованый в битмапах.

Большинство игровых движков используют такой подход для верстки ui. Я не говорю что нужно использовать флекс или писать кучу компонентов, я советую использовать подход с анкерами для решения подобных задач.

undefined
02.11.2017, 00:15
а никто не подскажет чего-нибудь легковесного для оформления ui с помощью лейаутов(можно на js раз уж флэш похоронили)?Флекс и в самом деле сильно монструозен.

ZergMaster
02.11.2017, 01:00
Wolsh ну, тут, конечно, все зависит от задачи. Мне, как правило, хватает пропорций. Главной вьюхе не надо знать, где находятся дочерние, достаточно передать им свой размер. А они, исходя из этого размера, располагаются на сцене. Например произошел ресайз и по событию обновились глобальные width и height. Какая-нибудь дочерняя вьюшка, например аватарка пользователя, по событию приняла глобальные width и height и делает свой ресайз, в котором может быть наворочено куча всего. Например, она располагается на 10 пикселей от правого края и 10 пикселей сверху, принимает ширину 1/10 от сцены (но не меньше и не больше от крайних). А другая вьюха, какой-нибудь прогрессбар здоровья, висит на 10 пикселей от верхнего края и располагается в точке width/2 и так далее.
Нет, конечно, дисплей обжект контейнер все равно будет знать, где находятся его дети, я, конечно, имею ввиду то, что он их не располагает, а весь лэйаут происходит внутри компонента. Зачастую это удобно. Да, конечно, что касается кнопок меню, или каких-либо иконок в ряд или любых других списков - они просчитываются в зависимости друг от друга. Но главная сцена, как правило, все равно не располагает их. Она передает своим размеры в компонент "меню", который уже внутри себя располагает взаимозависимо кноки.
Или, вы хотите сказать, что главная сцена (вьюха) у вас содержит в себе большой-пребольшой метод resize, который занимает всеми этими расчетами и располагает всех детей в зависимости друг от друга? У меня этот метод в этом случае так разрастался, что я довольно быстро стал всю эту логику прятать в детей.

Добавлено через 5 минут
undefined для флеша - feathers (https://feathersui.com/ui-components/) на старлинге предназначена для построения интерфейсов.

Wolsh
02.11.2017, 03:23
Или, вы хотите сказать, что главная сцена (вьюха) у вас содержит в себе большой-пребольшой метод resize, который занимает всеми этими расчетами и располагает всех детей в зависимости друг от друга?Ну, у меня никогда "аватарка пользователя" или кнопка меню не окажется в главной Вью. Возможно, дело в этом. Вью имеет дело с тремя-пятью детьми, а те расставляют по местам своих детей, те — своих, и т.д. Положением и размером картинки-стейта кнопки занимается класс Кнопка, положением и размером Кнопки занимается класс Меню, положением и размером Меню занимается класс PopupLayer, а вот им управляет Вью. И даже игровое окно Вью не будет сама собирать по кусочкам, это будет какой-нибудь ГеймВью, который в свою очередь будет создавать три-четыре модуля и управлять ими (звучало хорошее слово "разметка"). А те уже тусовать внутри себя другие модули с иконками, аватарками и тп. То есть всегда, когда я пишу визуальный модуль, я закладываю в него возможность такого "умного" масштабирования без растягивания, искажения элементов. Поэтому и слово использую ресайз, а иногда и более точное rebuild. Потому что это не scale. Но инициировать этот ребилд может только хозяин компонента, потому что только он знает, что там творится вокруг. И даже если в результате какой-то внутренней жизни ребенка его вдруг раздуло (пришел новый текст например, или дизайнер заложил в него такую анимацию), ребенок должен сообщить об этом родителю, а не тупо занять под себя весь экран (что неизбежно в предлагаемой тобой парадигме "я сам!").

Я щас приведу пример одной поучительной ситуации, безотносительно всех этих умных вещей и религиозных догматов про иерархию и т.п. Почему нельзя ребёнкам самим подстраивать себя под стейдж (хотя для меня это очевидная вещь, но что ж делать...) Простой пример без всяких "потому что умные люди придумали умную вещь".

Представь. Написал ты игру по этой своей системе. Классная игра, и тебе удалось ее впарить какому-то гейм-порталу. И приходит от них ответ: Дружище, такое дело. Все эти ваши игрульки у нас на сайте загружаются в ротатор (проектор?). И поскольку игрулек много, там в проекторе слева есть такая панель со списком. А внизу — так уж повелось — у нас крутятся банеры. Вопрос: ты с чего вообще решил, что стейдж принадлежит тебе? Теперь пожалуйста возьми и перепиши свою игру так, чтобы она подстраивалась не под стейдж, а под Мейн, которому мы задаем размеры в своем проекторе-загрузчике.
Как думаешь, легко будет переписать ВСЮ игру так, чтобы каждый ее элемент подстраивался не под стейдж, на который у него автоматически есть ссылка, а под Мейн, который, строго говоря, и размеров то собственных на самом деле не имеет (в отличии от стейджа), а полностью зависит от добавленного в него контента. Представь, как ты будешь протаскивать в КАЖДУЮ фигулину ссылку на Мейн?

В чем мораль то. Стейдж не является частью вашего приложения. Он полностью независим и никак вашим кодом не управляется. Вы даже размер ему задать не можете. Даже те настройки, которые вы можете сделать из своего кода — stageAlign, scaleMode — относятся не к стейдж, а к тому как стейдж будет вертеть вашим Мейном. Стейдж всегда один для всего, что загружено в флэш-плеер, а загружено в него может быть далеко не только ваше приложение. Короче, размер вашего приложения может быть совсем не таким же, как у стейджа, и координаты вашего приложения на стейдже могут быть вовсе не (0, 0).

ZergMaster
02.11.2017, 09:11
Wolsh про пример - понятно. Главный ресайз от стеджа то никак не зависит - он может сработать как от события .RESIZE, так и от ExternalInterface, приняв в себя ширину и высоту.
Ну, про аватарку это ж я примеру ради. Речь о том, что в моем случае, ГеймВью, создав три-четыре модуля, не расставляет и не управляет ими, они просто сами знают, какую часть экрана занимают и в какой относительной точке находятся. Ведь пропорционально приложение то все равно должно быть постоянным. Если нам при каждом ресайзе надо полностью перестраивать их расположение, составляя разные узоры или что-то в этом духе - тогда конечно, без логики в родителе не обойтись. Просто, как правило, этого не требуется.
Я думая, что мой подход очень похож на то, о чем вы говорите, просто я стараюсь все, что возможно - спрятать в ресайзы детей. Пусть сами занимаются своим расположением, чай не маленькие.